From a6c09bb2c638cf8be5d98c9e6fcea8caa2b4cbe8 Mon Sep 17 00:00:00 2001 From: Myles Watson Date: Fri, 31 Jul 2020 16:11:23 -0700 Subject: [PATCH 001/382] Protect bluetooth.device.action.ALIAS_CHANGED Bug: 157472962 Tag: #security Test: build Change-Id: I7737c4f1ad4bf5fec3127526465c78808de03693 --- core/res/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 9945057f0e94..21ac67cc8126 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -144,7 +144,7 @@ - + -- GitLab From 2c80a717895a9cdd00f520424977525b67831a71 Mon Sep 17 00:00:00 2001 From: Ivan Chiang Date: Mon, 10 Aug 2020 16:43:33 +0800 Subject: [PATCH 002/382] Revoke the uri permission when the file is deleted When the file is deleted, renamed or moved, revoke all uri permissions with the file Bug: 157474195 Test: manual test with DocumentsUI Test: atest DocumentsTest#testAfterMoveDocumentInStorage_revokeUriPermission Change-Id: I4ffb183630aadb2d87b0965e8cecf88af15f4534 Merged-In: I4ffb183630aadb2d87b0965e8cecf88af15f4534 (cherry picked from commit 9efd606f43abe36f9fcf7f0d1ab0d059c51be514) --- .../android/internal/content/FileSystemProvider.java | 11 +++++++++++ .../externalstorage/ExternalStorageProvider.java | 7 +++++++ 2 files changed, 18 insertions(+) diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java index a50a52219c74..3b5fecfc600a 100644 --- a/core/java/com/android/internal/content/FileSystemProvider.java +++ b/core/java/com/android/internal/content/FileSystemProvider.java @@ -113,6 +113,14 @@ public abstract class FileSystemProvider extends DocumentsProvider { // Default is no-op } + /** + * Callback indicating that the given document has been deleted or moved. This gives + * the provider a hook to revoke the uri permissions. + */ + protected void onDocIdDeleted(String docId) { + // Default is no-op + } + @Override public boolean onCreate() { throw new UnsupportedOperationException( @@ -283,6 +291,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { final String afterDocId = getDocIdForFile(after); onDocIdChanged(docId); + onDocIdDeleted(docId); onDocIdChanged(afterDocId); final File afterVisibleFile = getFileForDocId(afterDocId, true); @@ -312,6 +321,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { final String docId = getDocIdForFile(after); onDocIdChanged(sourceDocumentId); + onDocIdDeleted(sourceDocumentId); onDocIdChanged(docId); moveInMediaStore(visibleFileBefore, getFileForDocId(docId, true)); @@ -343,6 +353,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { } onDocIdChanged(docId); + onDocIdDeleted(docId); removeFromMediaStore(visibleFile); } diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index f42bf1982b36..11d1b0a9ef2a 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -482,6 +482,13 @@ public class ExternalStorageProvider extends FileSystemProvider { } } + @Override + protected void onDocIdDeleted(String docId) { + Uri uri = DocumentsContract.buildDocumentUri(AUTHORITY, docId); + getContext().revokeUriPermission(uri, ~0); + } + + @Override public Cursor queryRoots(String[] projection) throws FileNotFoundException { final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection)); -- GitLab From 51da01e172b7a2274e1164ce5ba88045156bc843 Mon Sep 17 00:00:00 2001 From: Ivan Chiang Date: Mon, 10 Aug 2020 16:43:33 +0800 Subject: [PATCH 003/382] Revoke the uri permission when the file is deleted When the file is deleted, renamed or moved, revoke all uri permissions with the file Bug: 157474195 Test: manual test with DocumentsUI Test: atest DocumentsTest#testAfterMoveDocumentInStorage_revokeUriPermission Change-Id: I4ffb183630aadb2d87b0965e8cecf88af15f4534 Merged-In: I4ffb183630aadb2d87b0965e8cecf88af15f4534 (cherry picked from commit 9efd606f43abe36f9fcf7f0d1ab0d059c51be514) --- .../android/internal/content/FileSystemProvider.java | 11 +++++++++++ .../externalstorage/ExternalStorageProvider.java | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java index cdb79abbb7ce..c8df16862111 100644 --- a/core/java/com/android/internal/content/FileSystemProvider.java +++ b/core/java/com/android/internal/content/FileSystemProvider.java @@ -108,6 +108,14 @@ public abstract class FileSystemProvider extends DocumentsProvider { // Default is no-op } + /** + * Callback indicating that the given document has been deleted or moved. This gives + * the provider a hook to revoke the uri permissions. + */ + protected void onDocIdDeleted(String docId) { + // Default is no-op + } + @Override public boolean onCreate() { throw new UnsupportedOperationException( @@ -278,6 +286,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { final String afterDocId = getDocIdForFile(after); onDocIdChanged(docId); + onDocIdDeleted(docId); onDocIdChanged(afterDocId); final File afterVisibleFile = getFileForDocId(afterDocId, true); @@ -307,6 +316,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { final String docId = getDocIdForFile(after); onDocIdChanged(sourceDocumentId); + onDocIdDeleted(sourceDocumentId); onDocIdChanged(docId); moveInMediaStore(visibleFileBefore, getFileForDocId(docId, true)); @@ -336,6 +346,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { } onDocIdChanged(docId); + onDocIdDeleted(docId); removeFromMediaStore(visibleFile, isDirectory); } diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 1b27b52f1fa1..4343611eb4c8 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -434,6 +434,12 @@ public class ExternalStorageProvider extends FileSystemProvider { } } + @Override + protected void onDocIdDeleted(String docId) { + Uri uri = DocumentsContract.buildDocumentUri(AUTHORITY, docId); + getContext().revokeUriPermission(uri, ~0); + } + @Override public Cursor queryRoots(String[] projection) throws FileNotFoundException { final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection)); -- GitLab From 773bec181da077601b66727b1b1472db907a00af Mon Sep 17 00:00:00 2001 From: Ivan Chiang Date: Mon, 10 Aug 2020 16:43:33 +0800 Subject: [PATCH 004/382] Revoke the uri permission when the file is deleted When the file is deleted, renamed or moved, revoke all uri permissions with the file Bug: 157474195 Test: manual test with DocumentsUI Test: atest DocumentsTest#testAfterMoveDocumentInStorage_revokeUriPermission Change-Id: I4ffb183630aadb2d87b0965e8cecf88af15f4534 Merged-In: I4ffb183630aadb2d87b0965e8cecf88af15f4534 (cherry picked from commit 9efd606f43abe36f9fcf7f0d1ab0d059c51be514) --- .../android/internal/content/FileSystemProvider.java | 11 +++++++++++ .../externalstorage/ExternalStorageProvider.java | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java index cdb79abbb7ce..c8df16862111 100644 --- a/core/java/com/android/internal/content/FileSystemProvider.java +++ b/core/java/com/android/internal/content/FileSystemProvider.java @@ -108,6 +108,14 @@ public abstract class FileSystemProvider extends DocumentsProvider { // Default is no-op } + /** + * Callback indicating that the given document has been deleted or moved. This gives + * the provider a hook to revoke the uri permissions. + */ + protected void onDocIdDeleted(String docId) { + // Default is no-op + } + @Override public boolean onCreate() { throw new UnsupportedOperationException( @@ -278,6 +286,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { final String afterDocId = getDocIdForFile(after); onDocIdChanged(docId); + onDocIdDeleted(docId); onDocIdChanged(afterDocId); final File afterVisibleFile = getFileForDocId(afterDocId, true); @@ -307,6 +316,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { final String docId = getDocIdForFile(after); onDocIdChanged(sourceDocumentId); + onDocIdDeleted(sourceDocumentId); onDocIdChanged(docId); moveInMediaStore(visibleFileBefore, getFileForDocId(docId, true)); @@ -336,6 +346,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { } onDocIdChanged(docId); + onDocIdDeleted(docId); removeFromMediaStore(visibleFile, isDirectory); } diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 1b27b52f1fa1..4343611eb4c8 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -434,6 +434,12 @@ public class ExternalStorageProvider extends FileSystemProvider { } } + @Override + protected void onDocIdDeleted(String docId) { + Uri uri = DocumentsContract.buildDocumentUri(AUTHORITY, docId); + getContext().revokeUriPermission(uri, ~0); + } + @Override public Cursor queryRoots(String[] projection) throws FileNotFoundException { final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection)); -- GitLab From c5c373c25890b9473a93d4ad000a89d134cf2d17 Mon Sep 17 00:00:00 2001 From: Ivan Chiang Date: Mon, 10 Aug 2020 16:43:33 +0800 Subject: [PATCH 005/382] Revoke the uri permission when the file is deleted When the file is deleted, renamed or moved, revoke all uri permissions with the file Bug: 157474195 Test: manual test with DocumentsUI Test: atest DocumentsTest#testAfterMoveDocumentInStorage_revokeUriPermission Change-Id: I4ffb183630aadb2d87b0965e8cecf88af15f4534 Merged-In: I4ffb183630aadb2d87b0965e8cecf88af15f4534 (cherry picked from commit 9efd606f43abe36f9fcf7f0d1ab0d059c51be514) --- .../android/internal/content/FileSystemProvider.java | 11 +++++++++++ .../externalstorage/ExternalStorageProvider.java | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java index b591163e8728..13619434044a 100644 --- a/core/java/com/android/internal/content/FileSystemProvider.java +++ b/core/java/com/android/internal/content/FileSystemProvider.java @@ -93,6 +93,14 @@ public abstract class FileSystemProvider extends DocumentsProvider { // Default is no-op } + /** + * Callback indicating that the given document has been deleted or moved. This gives + * the provider a hook to revoke the uri permissions. + */ + protected void onDocIdDeleted(String docId) { + // Default is no-op + } + @Override public boolean onCreate() { throw new UnsupportedOperationException( @@ -243,6 +251,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { final String afterDocId = getDocIdForFile(after); onDocIdChanged(docId); + onDocIdDeleted(docId); onDocIdChanged(afterDocId); final File beforeVisibleFile = getFileForDocId(docId, true); @@ -274,6 +283,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { final String docId = getDocIdForFile(after); onDocIdChanged(sourceDocumentId); + onDocIdDeleted(sourceDocumentId); onDocIdChanged(docId); moveInMediaStore(visibleFileBefore, getFileForDocId(docId, true)); @@ -325,6 +335,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { } onDocIdChanged(docId); + onDocIdDeleted(docId); removeFromMediaStore(visibleFile, isDirectory); } diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 0a720a5b234e..fcf1692775e7 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -430,6 +430,12 @@ public class ExternalStorageProvider extends FileSystemProvider { } } + @Override + protected void onDocIdDeleted(String docId) { + Uri uri = DocumentsContract.buildDocumentUri(AUTHORITY, docId); + getContext().revokeUriPermission(uri, ~0); + } + @Override public Cursor queryRoots(String[] projection) throws FileNotFoundException { final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection)); -- GitLab From 42c44f3601c788582dad1ff53d82c20d42ef9fbc Mon Sep 17 00:00:00 2001 From: Ivan Chiang Date: Mon, 10 Aug 2020 16:43:33 +0800 Subject: [PATCH 006/382] Revoke the uri permission when the file is deleted When the file is deleted, renamed or moved, revoke all uri permissions with the file Bug: 157474195 Test: manual test with DocumentsUI Test: atest DocumentsTest#testAfterMoveDocumentInStorage_revokeUriPermission Change-Id: I4ffb183630aadb2d87b0965e8cecf88af15f4534 Merged-In: I4ffb183630aadb2d87b0965e8cecf88af15f4534 (cherry picked from commit 9efd606f43abe36f9fcf7f0d1ab0d059c51be514) --- .../android/internal/content/FileSystemProvider.java | 11 +++++++++++ .../externalstorage/ExternalStorageProvider.java | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java index 4b80a5ff03de..ff8dd6e17a45 100644 --- a/core/java/com/android/internal/content/FileSystemProvider.java +++ b/core/java/com/android/internal/content/FileSystemProvider.java @@ -87,6 +87,14 @@ public abstract class FileSystemProvider extends DocumentsProvider { protected abstract Uri buildNotificationUri(String docId); + /** + * Callback indicating that the given document has been deleted or moved. This gives + * the provider a hook to revoke the uri permissions. + */ + protected void onDocIdDeleted(String docId) { + // Default is no-op + } + @Override public boolean onCreate() { throw new UnsupportedOperationException( @@ -221,6 +229,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { } final String afterDocId = getDocIdForFile(after); + onDocIdDeleted(docId); moveInMediaStore(visibleFileBefore, getFileForDocId(afterDocId, true)); if (!TextUtils.equals(docId, afterDocId)) { @@ -246,6 +255,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { } final String docId = getDocIdForFile(after); + onDocIdDeleted(sourceDocumentId); moveInMediaStore(visibleFileBefore, getFileForDocId(docId, true)); return docId; @@ -295,6 +305,7 @@ public abstract class FileSystemProvider extends DocumentsProvider { throw new IllegalStateException("Failed to delete " + file); } + onDocIdDeleted(docId); removeFromMediaStore(visibleFile, isDirectory); } diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index f844cc163bbe..af722ed62b4d 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -384,6 +384,12 @@ public class ExternalStorageProvider extends FileSystemProvider { return DocumentsContract.buildChildDocumentsUri(AUTHORITY, docId); } + @Override + protected void onDocIdDeleted(String docId) { + Uri uri = DocumentsContract.buildDocumentUri(AUTHORITY, docId); + getContext().revokeUriPermission(uri, ~0); + } + @Override public Cursor queryRoots(String[] projection) throws FileNotFoundException { final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection)); -- GitLab From e4bb1d7b6cd538acf423c7d8864dd26819fe8757 Mon Sep 17 00:00:00 2001 From: Abhijeet Kaur Date: Thu, 13 Aug 2020 12:21:15 +0100 Subject: [PATCH 007/382] Validate user-supplied URIs in DocumentsProvider calls Some URIs are used without validating their authorities which can lead to exploitation by malicious apps. Bug: 157294893 Test: Manual using test app in b/157294893 Change-Id: I799509ed5ff7e69140e84d796fe7f96d9dbfd32f Merged-In: I799509ed5ff7e69140e84d796fe7f96d9dbfd32f (cherry picked from commit 75f984bd32a3ee8115d5cea09ab1bd237537ab54) --- .../android/provider/DocumentsProvider.java | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 327bca268a7b..91b591c7b77e 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -232,6 +232,10 @@ public abstract class DocumentsProvider extends ContentProvider { } } + private Uri validateIncomingNullableUri(@Nullable Uri uri) { + return uri == null ? null : validateIncomingUri(uri); + } + /** * Create a new document and return its newly generated * {@link Document#COLUMN_DOCUMENT_ID}. You must allocate a new @@ -1076,11 +1080,18 @@ public abstract class DocumentsProvider extends ContentProvider { final Context context = getContext(); final Bundle out = new Bundle(); + final Uri extraUri = validateIncomingNullableUri( + extras.getParcelable(DocumentsContract.EXTRA_URI)); + final Uri extraTargetUri = validateIncomingNullableUri( + extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI)); + final Uri extraParentUri = validateIncomingNullableUri( + extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI)); + if (METHOD_EJECT_ROOT.equals(method)) { // Given that certain system apps can hold MOUNT_UNMOUNT permission, but only apps // signed with platform signature can hold MANAGE_DOCUMENTS, we are going to check for // MANAGE_DOCUMENTS or associated URI permission here instead - final Uri rootUri = extras.getParcelable(DocumentsContract.EXTRA_URI); + final Uri rootUri = extraUri; enforceWritePermissionInner(rootUri, getCallingPackage(), getCallingAttributionTag(), null); @@ -1090,7 +1101,7 @@ public abstract class DocumentsProvider extends ContentProvider { return out; } - final Uri documentUri = extras.getParcelable(DocumentsContract.EXTRA_URI); + final Uri documentUri = extraUri; final String authority = documentUri.getAuthority(); final String documentId = DocumentsContract.getDocumentId(documentUri); @@ -1106,7 +1117,7 @@ public abstract class DocumentsProvider extends ContentProvider { enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingAttributionTag(), null); - final Uri childUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI); + final Uri childUri = extraTargetUri; final String childAuthority = childUri.getAuthority(); final String childId = DocumentsContract.getDocumentId(childUri); @@ -1173,7 +1184,7 @@ public abstract class DocumentsProvider extends ContentProvider { revokeDocumentPermission(documentId); } else if (METHOD_COPY_DOCUMENT.equals(method)) { - final Uri targetUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI); + final Uri targetUri = extraTargetUri; final String targetId = DocumentsContract.getDocumentId(targetUri); enforceReadPermissionInner(documentUri, getCallingPackage(), @@ -1197,9 +1208,9 @@ public abstract class DocumentsProvider extends ContentProvider { } } else if (METHOD_MOVE_DOCUMENT.equals(method)) { - final Uri parentSourceUri = extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI); + final Uri parentSourceUri = extraParentUri; final String parentSourceId = DocumentsContract.getDocumentId(parentSourceUri); - final Uri targetUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI); + final Uri targetUri = extraTargetUri; final String targetId = DocumentsContract.getDocumentId(targetUri); enforceWritePermissionInner(documentUri, getCallingPackage(), @@ -1225,7 +1236,7 @@ public abstract class DocumentsProvider extends ContentProvider { } } else if (METHOD_REMOVE_DOCUMENT.equals(method)) { - final Uri parentSourceUri = extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI); + final Uri parentSourceUri = extraParentUri; final String parentSourceId = DocumentsContract.getDocumentId(parentSourceUri); enforceReadPermissionInner(parentSourceUri, getCallingPackage(), -- GitLab From e9b1dd415fed5415bc21abbd8e2f653fda5cf30c Mon Sep 17 00:00:00 2001 From: Jing Ji Date: Fri, 28 Aug 2020 14:55:48 -0700 Subject: [PATCH 008/382] Enforce permission checks in getting app exit reasons Bug: 165595677 Test: atest CtsSecurityTestCases:ActivityManagerTest Change-Id: Ia758d32bce6b2ac4c7145a96eccf68a962f0748b --- .../java/com/android/server/am/ActivityManagerService.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 82abb988cb2c..e75d54f8ac9f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -10475,12 +10475,10 @@ public class ActivityManagerService extends IActivityManager.Stub } finally { Binder.restoreCallingIdentity(identity); } - if (uid == Process.INVALID_UID) { - return Process.INVALID_UID; - } + // If the uid is Process.INVALID_UID, the below 'if' check will be always true if (UserHandle.getAppId(uid) != UserHandle.getAppId(callingUid)) { // Requires the DUMP permission if the target package doesn't belong - // to the caller. + // to the caller or it doesn't exist. enforceCallingPermission(android.Manifest.permission.DUMP, function); } return uid; -- GitLab From e592700068db0335c83934f191fc9efcbd8037ec Mon Sep 17 00:00:00 2001 From: Howard Ro Date: Tue, 18 Aug 2020 17:13:40 -0700 Subject: [PATCH 009/382] Fix out of bound error of IncidentService Before this change, it was possible for the code to suffer an out of bound error. Bug: 150706572 Test: make Change-Id: I3e8d37f2ee3c942bc9b176edee043557b005c757 (cherry picked from commit 8ff5315e989c1348e313bcb8170b77adc80b2fce) --- cmds/incidentd/src/IncidentService.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp index dc1612575f38..13bf197aa9dc 100644 --- a/cmds/incidentd/src/IncidentService.cpp +++ b/cmds/incidentd/src/IncidentService.cpp @@ -554,6 +554,10 @@ status_t IncidentService::command(FILE* in, FILE* out, FILE* err, Vector Date: Wed, 16 Sep 2020 14:10:21 +0100 Subject: [PATCH 010/382] Do not re-initialize synthetic password A bug was introduced in R where LSS ends up regenerating SP when an escrow token is being auto-activated on unsecured user, due to a logic error in shouldMigrateToSyntheticPasswordLocked(). Fix the bug and add some safeguards as well as unit test to prevent future regressions. Bug: 168692734 Test: atest com.android.server.locksettings Change-Id: If35f2fd26b49faf6e3d0d75c10b1b3bb95f247c2 (cherry picked from commit efc1d53df3a2e7116d7ed83bca9bf8e384d32740) --- .../locksettings/LockSettingsService.java | 7 ++++++- .../locksettings/SyntheticPasswordTests.java | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 90370ddd21dd..9187e83af251 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -113,6 +113,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Preconditions; import com.android.internal.widget.ICheckCredentialProgressCallback; import com.android.internal.widget.ILockSettings; import com.android.internal.widget.LockPatternUtils; @@ -2618,6 +2619,10 @@ public class LockSettingsService extends ILockSettings.Stub { protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash, LockscreenCredential credential, int userId) { Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId); + Preconditions.checkState( + getSyntheticPasswordHandleLocked(userId) == SyntheticPasswordManager.DEFAULT_HANDLE, + "Cannot reinitialize SP"); + final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid( getGateKeeperService(), credentialHash, credential, userId); onAuthTokenKnownForUser(userId, auth); @@ -2678,7 +2683,7 @@ public class LockSettingsService extends ILockSettings.Stub { @VisibleForTesting protected boolean shouldMigrateToSyntheticPasswordLocked(int userId) { - return true; + return getSyntheticPasswordHandleLocked(userId) == SyntheticPasswordManager.DEFAULT_HANDLE; } private VerifyCredentialResponse spBasedDoVerifyCredential(LockscreenCredential userCredential, diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java index ba851992cbad..2c2fdcaab340 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java @@ -519,10 +519,24 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { LockscreenCredential password = newPassword("password"); initializeCredentialUnderSP(password, PRIMARY_USER_ID); assertTrue(mService.setLockCredential(password, password, PRIMARY_USER_ID)); + assertNoOrphanedFilesLeft(PRIMARY_USER_ID); + } + + @Test + public void testAddingEscrowToken_NoOrphanedFilesLeft() throws Exception { + final byte[] token = "some-high-entropy-secure-token".getBytes(); + for (int i = 0; i < 16; i++) { + long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null); + assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); + mLocalService.removeEscrowToken(handle, PRIMARY_USER_ID); + } + assertNoOrphanedFilesLeft(PRIMARY_USER_ID); + } + private void assertNoOrphanedFilesLeft(int userId) { String handleString = String.format("%016x", - mService.getSyntheticPasswordHandleLocked(PRIMARY_USER_ID)); - File directory = mStorage.getSyntheticPasswordDirectoryForUser(PRIMARY_USER_ID); + mService.getSyntheticPasswordHandleLocked(userId)); + File directory = mStorage.getSyntheticPasswordDirectoryForUser(userId); for (File file : directory.listFiles()) { String[] parts = file.getName().split("\\."); if (!parts[0].equals(handleString) && !parts[0].equals("0000000000000000")) { -- GitLab From e3eba1322bd2c965df625ac440f9e4b88de8c4f2 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Thu, 16 Jul 2020 16:49:06 -0700 Subject: [PATCH 011/382] Fix the issue provider can be wrong when requesting slice permission SlicePermissionActivity reads provider_pkg from intent, which can be modified at will. As a result user might see incorrect package name in the dialog granting slice permission. Bug: 159145361 Test: manual Merged-In: I8b66c02786df4096dad74b7e76255d5ddd1d609d Change-Id: I8b66c02786df4096dad74b7e76255d5ddd1d609d (cherry picked from commit 0ad32a2d70ae410a59d730802b47af7c27b0b4a3) --- .../java/android/app/slice/SliceProvider.java | 5 --- .../systemui/SlicePermissionActivity.java | 36 ++++++++++++++++++- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java index 5e530eedd818..a07ab1d845ca 100644 --- a/core/java/android/app/slice/SliceProvider.java +++ b/core/java/android/app/slice/SliceProvider.java @@ -152,10 +152,6 @@ public abstract class SliceProvider extends ContentProvider { * @hide */ public static final String EXTRA_PKG = "pkg"; - /** - * @hide - */ - public static final String EXTRA_PROVIDER_PKG = "provider_pkg"; /** * @hide */ @@ -519,7 +515,6 @@ public abstract class SliceProvider extends ContentProvider { "com.android.systemui.SlicePermissionActivity")); intent.putExtra(EXTRA_BIND_URI, sliceUri); intent.putExtra(EXTRA_PKG, callingPackage); - intent.putExtra(EXTRA_PROVIDER_PKG, context.getPackageName()); // Unique pending intent. intent.setData(sliceUri.buildUpon().appendQueryParameter("package", callingPackage) .build()); diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java index 449ed8c3bcdb..2365f128532e 100644 --- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java @@ -16,6 +16,7 @@ package com.android.systemui; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; +import android.annotation.Nullable; import android.app.Activity; import android.app.AlertDialog; import android.app.slice.SliceManager; @@ -29,6 +30,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Bundle; import android.text.BidiFormatter; +import android.util.EventLog; import android.util.Log; import android.widget.CheckBox; import android.widget.TextView; @@ -50,10 +52,17 @@ public class SlicePermissionActivity extends Activity implements OnClickListener mUri = getIntent().getParcelableExtra(SliceProvider.EXTRA_BIND_URI); mCallingPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PKG); - mProviderPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PROVIDER_PKG); + if (mUri == null) { + Log.e(TAG, SliceProvider.EXTRA_BIND_URI + " wasn't provided"); + finish(); + return; + } try { PackageManager pm = getPackageManager(); + mProviderPkg = pm.resolveContentProvider(mUri.getAuthority(), + PackageManager.GET_META_DATA).applicationInfo.packageName; + verifyCallingPkg(); CharSequence app1 = BidiFormatter.getInstance().unicodeWrap(pm.getApplicationInfo( mCallingPkg, 0).loadSafeLabel(pm, PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX, PackageItemInfo.SAFE_LABEL_FLAG_TRIM @@ -97,4 +106,29 @@ public class SlicePermissionActivity extends Activity implements OnClickListener public void onDismiss(DialogInterface dialog) { finish(); } + + private void verifyCallingPkg() { + final String providerPkg = getIntent().getStringExtra("provider_pkg"); + if (providerPkg == null || mProviderPkg.equals(providerPkg)) return; + final String callingPkg = getCallingPkg(); + EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg), String.format( + "pkg %s (disguised as %s) attempted to request permission to show %s slices in %s", + callingPkg, providerPkg, mProviderPkg, mCallingPkg)); + } + + @Nullable + private String getCallingPkg() { + final Uri referrer = getReferrer(); + if (referrer == null) return null; + return referrer.getHost(); + } + + private int getUid(@Nullable final String pkg) { + if (pkg == null) return -1; + try { + return getPackageManager().getApplicationInfo(pkg, 0).uid; + } catch (NameNotFoundException e) { + } + return -1; + } } -- GitLab From 149bb7e0380399dd331a1b45943037633b8c5fd4 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Thu, 16 Jul 2020 16:49:06 -0700 Subject: [PATCH 012/382] Fix the issue provider can be wrong when requesting slice permission SlicePermissionActivity reads provider_pkg from intent, which can be modified at will. As a result user might see incorrect package name in the dialog granting slice permission. Bug: 159145361 Test: manual Merged-In: I8b66c02786df4096dad74b7e76255d5ddd1d609d Change-Id: I8b66c02786df4096dad74b7e76255d5ddd1d609d (cherry picked from commit 0ad32a2d70ae410a59d730802b47af7c27b0b4a3) --- .../java/android/app/slice/SliceProvider.java | 5 --- .../systemui/SlicePermissionActivity.java | 36 ++++++++++++++++++- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java index 5e530eedd818..a07ab1d845ca 100644 --- a/core/java/android/app/slice/SliceProvider.java +++ b/core/java/android/app/slice/SliceProvider.java @@ -152,10 +152,6 @@ public abstract class SliceProvider extends ContentProvider { * @hide */ public static final String EXTRA_PKG = "pkg"; - /** - * @hide - */ - public static final String EXTRA_PROVIDER_PKG = "provider_pkg"; /** * @hide */ @@ -519,7 +515,6 @@ public abstract class SliceProvider extends ContentProvider { "com.android.systemui.SlicePermissionActivity")); intent.putExtra(EXTRA_BIND_URI, sliceUri); intent.putExtra(EXTRA_PKG, callingPackage); - intent.putExtra(EXTRA_PROVIDER_PKG, context.getPackageName()); // Unique pending intent. intent.setData(sliceUri.buildUpon().appendQueryParameter("package", callingPackage) .build()); diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java index 449ed8c3bcdb..2365f128532e 100644 --- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java @@ -16,6 +16,7 @@ package com.android.systemui; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; +import android.annotation.Nullable; import android.app.Activity; import android.app.AlertDialog; import android.app.slice.SliceManager; @@ -29,6 +30,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Bundle; import android.text.BidiFormatter; +import android.util.EventLog; import android.util.Log; import android.widget.CheckBox; import android.widget.TextView; @@ -50,10 +52,17 @@ public class SlicePermissionActivity extends Activity implements OnClickListener mUri = getIntent().getParcelableExtra(SliceProvider.EXTRA_BIND_URI); mCallingPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PKG); - mProviderPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PROVIDER_PKG); + if (mUri == null) { + Log.e(TAG, SliceProvider.EXTRA_BIND_URI + " wasn't provided"); + finish(); + return; + } try { PackageManager pm = getPackageManager(); + mProviderPkg = pm.resolveContentProvider(mUri.getAuthority(), + PackageManager.GET_META_DATA).applicationInfo.packageName; + verifyCallingPkg(); CharSequence app1 = BidiFormatter.getInstance().unicodeWrap(pm.getApplicationInfo( mCallingPkg, 0).loadSafeLabel(pm, PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX, PackageItemInfo.SAFE_LABEL_FLAG_TRIM @@ -97,4 +106,29 @@ public class SlicePermissionActivity extends Activity implements OnClickListener public void onDismiss(DialogInterface dialog) { finish(); } + + private void verifyCallingPkg() { + final String providerPkg = getIntent().getStringExtra("provider_pkg"); + if (providerPkg == null || mProviderPkg.equals(providerPkg)) return; + final String callingPkg = getCallingPkg(); + EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg), String.format( + "pkg %s (disguised as %s) attempted to request permission to show %s slices in %s", + callingPkg, providerPkg, mProviderPkg, mCallingPkg)); + } + + @Nullable + private String getCallingPkg() { + final Uri referrer = getReferrer(); + if (referrer == null) return null; + return referrer.getHost(); + } + + private int getUid(@Nullable final String pkg) { + if (pkg == null) return -1; + try { + return getPackageManager().getApplicationInfo(pkg, 0).uid; + } catch (NameNotFoundException e) { + } + return -1; + } } -- GitLab From 4344e632953b103910b48d43f4eb226b38ed5048 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Thu, 16 Jul 2020 16:49:06 -0700 Subject: [PATCH 013/382] Fix the issue provider can be wrong when requesting slice permission SlicePermissionActivity reads provider_pkg from intent, which can be modified at will. As a result user might see incorrect package name in the dialog granting slice permission. Bug: 159145361 Test: manual Merged-In: I8b66c02786df4096dad74b7e76255d5ddd1d609d Change-Id: I8b66c02786df4096dad74b7e76255d5ddd1d609d --- .../java/android/app/slice/SliceProvider.java | 1 + .../systemui/SlicePermissionActivity.java | 31 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java index bd1eea51f8af..46be54814dc9 100644 --- a/core/java/android/app/slice/SliceProvider.java +++ b/core/java/android/app/slice/SliceProvider.java @@ -153,6 +153,7 @@ public abstract class SliceProvider extends ContentProvider { */ public static final String EXTRA_PKG = "pkg"; /** + * @Deprecated provider pkg is now being extracted in SlicePermissionActivity * @hide */ public static final String EXTRA_PROVIDER_PKG = "provider_pkg"; diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java index 449ed8c3bcdb..1b241b743242 100644 --- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java @@ -16,6 +16,7 @@ package com.android.systemui; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; +import android.annotation.Nullable; import android.app.Activity; import android.app.AlertDialog; import android.app.slice.SliceManager; @@ -29,6 +30,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Bundle; import android.text.BidiFormatter; +import android.util.EventLog; import android.util.Log; import android.widget.CheckBox; import android.widget.TextView; @@ -50,10 +52,12 @@ public class SlicePermissionActivity extends Activity implements OnClickListener mUri = getIntent().getParcelableExtra(SliceProvider.EXTRA_BIND_URI); mCallingPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PKG); - mProviderPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PROVIDER_PKG); try { PackageManager pm = getPackageManager(); + mProviderPkg = pm.resolveContentProvider(mUri.getAuthority(), + PackageManager.GET_META_DATA).applicationInfo.packageName; + verifyCallingPkg(); CharSequence app1 = BidiFormatter.getInstance().unicodeWrap(pm.getApplicationInfo( mCallingPkg, 0).loadSafeLabel(pm, PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX, PackageItemInfo.SAFE_LABEL_FLAG_TRIM @@ -97,4 +101,29 @@ public class SlicePermissionActivity extends Activity implements OnClickListener public void onDismiss(DialogInterface dialog) { finish(); } + + private void verifyCallingPkg() { + final String providerPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PROVIDER_PKG); + if (providerPkg == null || mProviderPkg.equals(providerPkg)) return; + final String callingPkg = getCallingPkg(); + EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg), String.format( + "pkg %s (disguised as %s) attempted to request permission to show %s slices in %s", + callingPkg, providerPkg, mProviderPkg, mCallingPkg)); + } + + @Nullable + private String getCallingPkg() { + final Uri referrer = getReferrer(); + if (referrer == null) return null; + return referrer.getHost(); + } + + private int getUid(@Nullable final String pkg) { + if (pkg == null) return -1; + try { + return getPackageManager().getApplicationInfo(pkg, 0).uid; + } catch (NameNotFoundException e) { + } + return -1; + } } -- GitLab From 4cab9c38764a6123c0072f0ef7b007cc29cd1b74 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Thu, 24 Sep 2020 15:33:58 -0700 Subject: [PATCH 014/382] Fix the issue provider can be wrong when requesting slice permission SlicePermissionActivity reads provider_pkg from intent, which can be modified at will. As a result user might see incorrect package name in the dialog granting slice permission. Bug: 159145361 Test: manual Merged-In: I8b66c02786df4096dad74b7e76255d5ddd1d609d Change-Id: I8b66c02786df4096dad74b7e76255d5ddd1d609d (cherry picked from commit 0ad32a2d70ae410a59d730802b47af7c27b0b4a3) --- .../java/android/app/slice/SliceProvider.java | 5 --- .../systemui/SlicePermissionActivity.java | 31 ++++++++++++++++++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java index 7da4b30b03e1..7b706b8a3895 100644 --- a/core/java/android/app/slice/SliceProvider.java +++ b/core/java/android/app/slice/SliceProvider.java @@ -152,10 +152,6 @@ public abstract class SliceProvider extends ContentProvider { * @hide */ public static final String EXTRA_PKG = "pkg"; - /** - * @hide - */ - public static final String EXTRA_PROVIDER_PKG = "provider_pkg"; /** * @hide */ @@ -519,7 +515,6 @@ public abstract class SliceProvider extends ContentProvider { "com.android.systemui.SlicePermissionActivity")); intent.putExtra(EXTRA_BIND_URI, sliceUri); intent.putExtra(EXTRA_PKG, callingPackage); - intent.putExtra(EXTRA_PROVIDER_PKG, context.getPackageName()); // Unique pending intent. intent.setData(sliceUri.buildUpon().appendQueryParameter("package", callingPackage) .build()); diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java index 19f8416860a2..8e92818db083 100644 --- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java @@ -16,6 +16,7 @@ package com.android.systemui; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; +import android.annotation.Nullable; import android.app.Activity; import android.app.AlertDialog; import android.app.slice.SliceManager; @@ -28,6 +29,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Bundle; import android.text.BidiFormatter; +import android.util.EventLog; import android.util.Log; import android.widget.CheckBox; import android.widget.TextView; @@ -49,10 +51,12 @@ public class SlicePermissionActivity extends Activity implements OnClickListener mUri = getIntent().getParcelableExtra(SliceProvider.EXTRA_BIND_URI); mCallingPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PKG); - mProviderPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PROVIDER_PKG); try { PackageManager pm = getPackageManager(); + mProviderPkg = pm.resolveContentProvider(mUri.getAuthority(), + PackageManager.GET_META_DATA).applicationInfo.packageName; + verifyCallingPkg(); CharSequence app1 = BidiFormatter.getInstance().unicodeWrap( pm.getApplicationInfo(mCallingPkg, 0).loadSafeLabel(pm).toString()); CharSequence app2 = BidiFormatter.getInstance().unicodeWrap( @@ -92,4 +96,29 @@ public class SlicePermissionActivity extends Activity implements OnClickListener public void onDismiss(DialogInterface dialog) { finish(); } + + private void verifyCallingPkg() { + final String providerPkg = getIntent().getStringExtra("provider_pkg"); + if (providerPkg == null || mProviderPkg.equals(providerPkg)) return; + final String callingPkg = getCallingPkg(); + EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg), String.format( + "pkg %s (disguised as %s) attempted to request permission to show %s slices in %s", + callingPkg, providerPkg, mProviderPkg, mCallingPkg)); + } + + @Nullable + private String getCallingPkg() { + final Uri referrer = getReferrer(); + if (referrer == null) return null; + return referrer.getHost(); + } + + private int getUid(@Nullable final String pkg) { + if (pkg == null) return -1; + try { + return getPackageManager().getApplicationInfo(pkg, 0).uid; + } catch (NameNotFoundException e) { + } + return -1; + } } -- GitLab From 870c9f7caed91bb3dc73a363426aee9a56388d51 Mon Sep 17 00:00:00 2001 From: Vadim Caen Date: Fri, 25 Sep 2020 11:26:30 +0200 Subject: [PATCH 015/382] Call DecorView.drawableChanged() in PhoneWindow.setBackgroungDrawable Not calling it result in empty buffer and stuttering during some animation. BUG: 158672949 Test: Manual test with ASOS app (see b/151910308) and Boost app (b/158672949) Change-Id: Ic5018829d7c7dde388bc928c1f5b3f773cc2f5e4 --- core/java/com/android/internal/policy/PhoneWindow.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 046981cf2e8f..d90a0225608d 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -1510,11 +1510,13 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (drawable != mBackgroundDrawable) { mBackgroundDrawable = drawable; if (mDecor != null) { + mDecor.startChanging(); mDecor.setWindowBackground(drawable); if (mBackgroundFallbackDrawable != null) { mDecor.setBackgroundFallback(drawable != null ? null : mBackgroundFallbackDrawable); } + mDecor.finishChanging(); } } } -- GitLab From b392903052b3c35b5b9706d6d1f19762d943f58e Mon Sep 17 00:00:00 2001 From: wilsonshih Date: Wed, 13 May 2020 16:09:35 +0800 Subject: [PATCH 016/382] Make WallpaperMS bind wallpaper component PendingIntent immutable. Require that the PendingIntent be immutable so that a malicious app is not able to hijack and mutate any of the details. Fixes: 154915372 Test: build & flash, change wallpaper manually. Change-Id: I59b48811b26736bf0575769107dd940ca33ccf8d (cherry picked from commit d4bd69cef05d379555418a8fe748ec94ff6bd6d0) --- .../com/android/server/wallpaper/WallpaperManagerService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 52cb89d6ed78..28587ea29a23 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -1796,7 +1796,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { mContext, 0, Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER), mContext.getText(com.android.internal.R.string.chooser_wallpaper)), - 0, null, new UserHandle(serviceUserId))); + PendingIntent.FLAG_IMMUTABLE, null, new UserHandle(serviceUserId))); if (!mContext.bindServiceAsUser(intent, newConn, Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, -- GitLab From 178da54fc94df895bdc87543b25201ee415e7182 Mon Sep 17 00:00:00 2001 From: wilsonshih Date: Wed, 13 May 2020 16:09:35 +0800 Subject: [PATCH 017/382] Make WallpaperMS bind wallpaper component PendingIntent immutable. Require that the PendingIntent be immutable so that a malicious app is not able to hijack and mutate any of the details. Fixes: 154915372 Test: build & flash, change wallpaper manually. Change-Id: I59b48811b26736bf0575769107dd940ca33ccf8d (cherry picked from commit d4bd69cef05d379555418a8fe748ec94ff6bd6d0) --- .../com/android/server/wallpaper/WallpaperManagerService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index a04a3248b8e9..ab331fafd54e 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -2133,7 +2133,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { mContext, 0, Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER), mContext.getText(com.android.internal.R.string.chooser_wallpaper)), - 0, null, new UserHandle(serviceUserId))); + PendingIntent.FLAG_IMMUTABLE, null, new UserHandle(serviceUserId))); if (!mContext.bindServiceAsUser(intent, newConn, Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, -- GitLab From a839692d5ca4ea47e9565865eae5cdf904cc0629 Mon Sep 17 00:00:00 2001 From: wilsonshih Date: Wed, 13 May 2020 16:09:35 +0800 Subject: [PATCH 018/382] Make WallpaperMS bind wallpaper component PendingIntent immutable. Require that the PendingIntent be immutable so that a malicious app is not able to hijack and mutate any of the details. Fixes: 154915372 Test: build & flash, change wallpaper manually. Change-Id: I59b48811b26736bf0575769107dd940ca33ccf8d (cherry picked from commit d4bd69cef05d379555418a8fe748ec94ff6bd6d0) --- .../com/android/server/wallpaper/WallpaperManagerService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index f66918789dd4..1d634d3d760c 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -2373,7 +2373,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub mContext, 0, Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER), mContext.getText(com.android.internal.R.string.chooser_wallpaper)), - 0, null, new UserHandle(serviceUserId))); + PendingIntent.FLAG_IMMUTABLE, null, new UserHandle(serviceUserId))); if (!mContext.bindServiceAsUser(intent, newConn, Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, -- GitLab From d337ac7a46cfd4eae52f34e58f952a6b3c710f25 Mon Sep 17 00:00:00 2001 From: wilsonshih Date: Wed, 13 May 2020 16:09:35 +0800 Subject: [PATCH 019/382] Make WallpaperMS bind wallpaper component PendingIntent immutable. Require that the PendingIntent be immutable so that a malicious app is not able to hijack and mutate any of the details. Fixes: 154915372 Test: build & flash, change wallpaper manually. Change-Id: I59b48811b26736bf0575769107dd940ca33ccf8d (cherry picked from commit d4bd69cef05d379555418a8fe748ec94ff6bd6d0) --- .../com/android/server/wallpaper/WallpaperManagerService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 991c09a97bf5..caaafc3be76f 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -2688,7 +2688,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub mContext, 0, Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER), mContext.getText(com.android.internal.R.string.chooser_wallpaper)), - 0, null, new UserHandle(serviceUserId))); + PendingIntent.FLAG_IMMUTABLE, null, new UserHandle(serviceUserId))); if (!mContext.bindServiceAsUser(intent, newConn, Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE -- GitLab From 3c21166a2746d8dfa152dc9f5c90f8d6078e378d Mon Sep 17 00:00:00 2001 From: wilsonshih Date: Wed, 13 May 2020 16:09:35 +0800 Subject: [PATCH 020/382] Make WallpaperMS bind wallpaper component PendingIntent immutable. Require that the PendingIntent be immutable so that a malicious app is not able to hijack and mutate any of the details. Fixes: 154915372 Test: build & flash, change wallpaper manually. Change-Id: I59b48811b26736bf0575769107dd940ca33ccf8d (cherry picked from commit d4bd69cef05d379555418a8fe748ec94ff6bd6d0) --- .../com/android/server/wallpaper/WallpaperManagerService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 0e2f0ce991c7..37ae3340d319 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -2709,7 +2709,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub mContext, 0, Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER), mContext.getText(com.android.internal.R.string.chooser_wallpaper)), - 0, null, new UserHandle(serviceUserId))); + PendingIntent.FLAG_IMMUTABLE, null, new UserHandle(serviceUserId))); if (!mContext.bindServiceAsUser(intent, newConn, Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE -- GitLab From e57c25a4518c80ad927db16a64412eefe7aa1c5b Mon Sep 17 00:00:00 2001 From: Tyler Gunn Date: Thu, 26 Apr 2018 14:43:31 -0700 Subject: [PATCH 021/382] Backport sendBroadcastAsUserMultiplePermissions to oc-dev Bug: 159373687 Test: Verify Settings still works correctly. Change-Id: I857ea00cc58a0abbb77960643f361dd6dd9c8b56 Merged-In: I857ea00cc58a0abbb77960643f361dd6dd9c8b56 --- core/java/android/app/ContextImpl.java | 16 +++++++++++ core/java/android/content/Context.java | 27 +++++++++++++++++++ core/java/android/content/ContextWrapper.java | 7 +++++ .../server/devicepolicy/DpmMockContext.java | 6 +++++ .../src/android/test/mock/MockContext.java | 7 +++++ .../test/BroadcastInterceptingContext.java | 6 +++++ 6 files changed, 69 insertions(+) diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 3ea0c83f2db6..2a4c78853911 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -992,6 +992,22 @@ class ContextImpl extends Context { } } + @Override + public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + String[] receiverPermissions) { + warnIfCallingFromSystemProcess(); + String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); + try { + intent.prepareToLeaveProcess(this); + ActivityManager.getService().broadcastIntent( + mMainThread.getApplicationThread(), intent, resolvedType, null, + Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, + null, false, false, user.getIdentifier()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + @Override public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) { warnIfCallingFromSystemProcess(); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 2977fb43f442..67d1a245b702 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1947,6 +1947,33 @@ public abstract class Context { public abstract void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions); + /** + * Broadcast the given intent to all interested BroadcastReceivers, allowing + * an array of required permissions to be enforced. This call is asynchronous; it returns + * immediately, and you will continue executing while the receivers are run. No results are + * propagated from receivers and receivers can not abort the broadcast. If you want to allow + * receivers to propagate results or abort the broadcast, you must send an ordered broadcast + * using {@link #sendOrderedBroadcast(Intent, String)}. + * + *

See {@link BroadcastReceiver} for more information on Intent broadcasts. + * + * @param intent The Intent to broadcast; all receivers matching this + * Intent will receive the broadcast. + * @param user The user to send the broadcast to. + * @param receiverPermissions Array of names of permissions that a receiver must hold + * in order to receive your broadcast. + * If null or empty, no permissions are required. + * + * @see android.content.BroadcastReceiver + * @see #registerReceiver + * @see #sendBroadcast(Intent) + * @see #sendOrderedBroadcast(Intent, String) + * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) + * @hide + */ + public abstract void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + String[] receiverPermissions); + /** * Broadcast the given intent to all interested BroadcastReceivers, allowing * an optional required permission to be enforced. This diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index df59f0eba0a5..096fcf8db019 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -442,6 +442,13 @@ public class ContextWrapper extends Context { mBase.sendBroadcastMultiplePermissions(intent, receiverPermissions); } + /** @hide */ + @Override + public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + String[] receiverPermissions) { + mBase.sendBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions); + } + /** @hide */ @SystemApi @Override diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index 87106ec7b918..2d9ff4c6036e 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -646,6 +646,12 @@ public class DpmMockContext extends MockContext { spiedContext.sendBroadcastMultiplePermissions(intent, receiverPermissions); } + @Override + public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + String[] receiverPermissions) { + spiedContext.sendBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions); + } + @Override public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) { spiedContext.sendBroadcast(intent, receiverPermission, options); diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java index 24e7bff09794..89f488b10d6e 100644 --- a/test-runner/src/android/test/mock/MockContext.java +++ b/test-runner/src/android/test/mock/MockContext.java @@ -352,6 +352,13 @@ public class MockContext extends Context { throw new UnsupportedOperationException(); } + /** @hide */ + @Override + public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + String[] receiverPermissions) { + throw new UnsupportedOperationException(); + } + /** @hide */ @SystemApi @Override diff --git a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java index 21662407db42..25bd7c06be49 100644 --- a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java +++ b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java @@ -174,6 +174,12 @@ public class BroadcastInterceptingContext extends ContextWrapper { sendBroadcast(intent); } + @Override + public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + String[] receiverPermissions) { + sendBroadcast(intent); + } + @Override public void sendBroadcastAsUser(Intent intent, UserHandle user) { sendBroadcast(intent); -- GitLab From 8d71bdf3e63d8cfc66e45f47a031d77e3509cb5b Mon Sep 17 00:00:00 2001 From: Charles Chen Date: Thu, 17 Sep 2020 23:04:57 +0800 Subject: [PATCH 022/382] [RESTRICT AUTOMERGE] Fix VrDisplayTest failure Before CL[1], the system regarded system created displays as trusted displays, which provided the ability to gain the focus without user's touch. After CL[1], the system checked if a virtual display is trusted by the flag FLAG_TRUSTED. Therefore, the activity lunched on the Vr2dDisplay can not gain the focus because Vr2dDisplay didn't hold the flag FLAG_TRUSTED. This CL adds the flag to Vr2dDisplay to make it a trusted display. CL[1]: ef7b1333f0e87cd07af115719b94dd37e2de54dc Bug: 168268396 Test: Vr2DisplayTests Change-Id: Iac88859d3fa7cbb75214efcc6ce4a88e0eb718f2 (cherry picked from commit 534bbaeead15bc3c540efd947b3a5ade62cf27be) --- services/core/java/com/android/server/vr/Vr2dDisplay.java | 1 + 1 file changed, 1 insertion(+) diff --git a/services/core/java/com/android/server/vr/Vr2dDisplay.java b/services/core/java/com/android/server/vr/Vr2dDisplay.java index 3f2b5c231dca..a713e5b13667 100644 --- a/services/core/java/com/android/server/vr/Vr2dDisplay.java +++ b/services/core/java/com/android/server/vr/Vr2dDisplay.java @@ -295,6 +295,7 @@ class Vr2dDisplay { flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL; flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE; + flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder( DISPLAY_NAME, mVirtualDisplayWidth, mVirtualDisplayHeight, mVirtualDisplayDpi); -- GitLab From ea7ef4ad2a15bae23039034fa00a36d6ff84e6cd Mon Sep 17 00:00:00 2001 From: Tyler Gunn Date: Thu, 26 Apr 2018 14:43:31 -0700 Subject: [PATCH 023/382] Backport sendBroadcastAsUserMultiplePermissions to oc-dev Bug: 159373687 Test: Verify Settings still works correctly. Change-Id: I857ea00cc58a0abbb77960643f361dd6dd9c8b56 Merged-In: I857ea00cc58a0abbb77960643f361dd6dd9c8b56 --- core/java/android/app/ContextImpl.java | 16 +++++++++++ core/java/android/content/Context.java | 27 +++++++++++++++++++ core/java/android/content/ContextWrapper.java | 7 +++++ .../server/devicepolicy/DpmMockContext.java | 6 +++++ test-runner/api/android-test-mock-current.txt | 1 + .../src/android/test/mock/MockContext.java | 7 +++++ .../test/BroadcastInterceptingContext.java | 6 +++++ 7 files changed, 70 insertions(+) diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 5f3432264ca0..06d63ea14a2c 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1008,6 +1008,22 @@ class ContextImpl extends Context { } } + @Override + public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + String[] receiverPermissions) { + warnIfCallingFromSystemProcess(); + String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); + try { + intent.prepareToLeaveProcess(this); + ActivityManager.getService().broadcastIntent( + mMainThread.getApplicationThread(), intent, resolvedType, null, + Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE, + null, false, false, user.getIdentifier()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + @Override public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) { warnIfCallingFromSystemProcess(); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index f821d31e3e2b..961901e2fb8f 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1950,6 +1950,33 @@ public abstract class Context { public abstract void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions); + /** + * Broadcast the given intent to all interested BroadcastReceivers, allowing + * an array of required permissions to be enforced. This call is asynchronous; it returns + * immediately, and you will continue executing while the receivers are run. No results are + * propagated from receivers and receivers can not abort the broadcast. If you want to allow + * receivers to propagate results or abort the broadcast, you must send an ordered broadcast + * using {@link #sendOrderedBroadcast(Intent, String)}. + * + *

See {@link BroadcastReceiver} for more information on Intent broadcasts. + * + * @param intent The Intent to broadcast; all receivers matching this + * Intent will receive the broadcast. + * @param user The user to send the broadcast to. + * @param receiverPermissions Array of names of permissions that a receiver must hold + * in order to receive your broadcast. + * If null or empty, no permissions are required. + * + * @see android.content.BroadcastReceiver + * @see #registerReceiver + * @see #sendBroadcast(Intent) + * @see #sendOrderedBroadcast(Intent, String) + * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) + * @hide + */ + public abstract void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + String[] receiverPermissions); + /** * Broadcast the given intent to all interested BroadcastReceivers, allowing * an optional required permission to be enforced. This diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index 85acdc6b8101..3a5fccbbff94 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -448,6 +448,13 @@ public class ContextWrapper extends Context { mBase.sendBroadcastMultiplePermissions(intent, receiverPermissions); } + /** @hide */ + @Override + public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + String[] receiverPermissions) { + mBase.sendBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions); + } + /** @hide */ @SystemApi @Override diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index 97021181c384..cb5f0a701615 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -234,6 +234,12 @@ public class DpmMockContext extends MockContext { spiedContext.sendBroadcastMultiplePermissions(intent, receiverPermissions); } + @Override + public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + String[] receiverPermissions) { + spiedContext.sendBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions); + } + @Override public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) { spiedContext.sendBroadcast(intent, receiverPermission, options); diff --git a/test-runner/api/android-test-mock-current.txt b/test-runner/api/android-test-mock-current.txt index 93bbf6c5c024..dfb2ee8d7599 100644 --- a/test-runner/api/android-test-mock-current.txt +++ b/test-runner/api/android-test-mock-current.txt @@ -133,6 +133,7 @@ package android.test.mock { method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String); method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.os.Bundle); method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, int); + method public void sendBroadcastAsUserMultiplePermissions(android.content.Intent, android.os.UserHandle, java.lang.String[]); method public void sendBroadcastMultiplePermissions(android.content.Intent, java.lang.String[]); method public void sendOrderedBroadcast(android.content.Intent, java.lang.String); method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle); diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java index 5e5ba462cfca..8cde61284b53 100644 --- a/test-runner/src/android/test/mock/MockContext.java +++ b/test-runner/src/android/test/mock/MockContext.java @@ -358,6 +358,13 @@ public class MockContext extends Context { throw new UnsupportedOperationException(); } + /** @hide */ + @Override + public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + String[] receiverPermissions) { + throw new UnsupportedOperationException(); + } + /** @hide */ @SystemApi @Override diff --git a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java index 21662407db42..25bd7c06be49 100644 --- a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java +++ b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java @@ -174,6 +174,12 @@ public class BroadcastInterceptingContext extends ContextWrapper { sendBroadcast(intent); } + @Override + public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + String[] receiverPermissions) { + sendBroadcast(intent); + } + @Override public void sendBroadcastAsUser(Intent intent, UserHandle user) { sendBroadcast(intent); -- GitLab From 81bab8b849a854ac1308862ed264ce9f16301f37 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 26 May 2020 19:02:59 -0700 Subject: [PATCH 024/382] [DO NOT MERGE][BACKPORT]Improve location checks in TelephonyRegistry Improve location checking for apps targeting SDK28 or earlier. Bug: 158484422 Test: (cts) atest TelephonyLocationTests; atest PhoneStateListenerTest Merged-In: I8caa3ea409836ce8469d8d8210b481a0284594f2 Change-Id: I8caa3ea409836ce8469d8d8210b481a0284594f2 (cherry picked from commit 4e0c7d16fd76bd7743a7f46ba63c75e8c65d63be) (cherry picked from commit 5c4fa70f5e543a5438f1c1efb35474a481c21430) --- .../com/android/server/TelephonyRegistry.java | 70 +++++++++++-------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 1a6faecaecfd..466a398abbc3 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -251,10 +251,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private PreciseDataConnectionState[] mPreciseDataConnectionState; - // Nothing here yet, but putting it here in case we want to add more in the future. - static final int ENFORCE_COARSE_LOCATION_PERMISSION_MASK = 0; - - static final int ENFORCE_FINE_LOCATION_PERMISSION_MASK = + // Starting in Q, almost all cellular location requires FINE location enforcement. + // Prior to Q, cellular was available with COARSE location enforcement. Bits in this + // list will be checked for COARSE on apps targeting P or earlier and FINE on Q or later. + static final int ENFORCE_LOCATION_PERMISSION_MASK = PhoneStateListener.LISTEN_CELL_LOCATION | PhoneStateListener.LISTEN_CELL_INFO; @@ -292,7 +292,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { + newDefaultSubId + " newDefaultPhoneId=" + newDefaultPhoneId); } - //Due to possible risk condition,(notify call back using the new + //Due to possible race condition,(notify call back using the new //defaultSubId comes before new defaultSubId update) we need to recall all //possible missed notify callback synchronized (mRecords) { @@ -710,11 +710,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) { try { - if (DBG_LOC) log("listen: mCellLocation = " - + mCellLocation[phoneId]); - if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { - r.callback.onCellLocationChanged( - new Bundle(mCellLocation[phoneId])); + if (DBG_LOC) log("listen: mCellLocation= " + mCellLocation[phoneId]); + if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + // null will be translated to empty CellLocation object in client. + r.callback.onCellLocationChanged(mCellLocation[phoneId]); } } catch (RemoteException ex) { remove(r.binder); @@ -761,7 +761,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { try { if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = " + mCellInfo.get(phoneId)); - if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); } } catch (RemoteException ex) { @@ -1239,7 +1240,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) && idMatch(r.subId, subId, phoneId) && - checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) { try { if (DBG_LOC) { log("notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r); @@ -1552,7 +1554,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) && idMatch(r.subId, subId, phoneId) && - checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) { try { if (DBG_LOC) { log("notifyCellLocation: cellLocation=" + cellLocation @@ -2221,19 +2224,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { .setCallingPid(Binder.getCallingPid()) .setCallingUid(Binder.getCallingUid()); - boolean shouldCheckLocationPermissions = false; - if ((events & ENFORCE_COARSE_LOCATION_PERMISSION_MASK) != 0) { - locationQueryBuilder.setMinSdkVersionForCoarse(0); - shouldCheckLocationPermissions = true; - } - - if ((events & ENFORCE_FINE_LOCATION_PERMISSION_MASK) != 0) { + if ((events & ENFORCE_LOCATION_PERMISSION_MASK) != 0) { // Everything that requires fine location started in Q. So far... locationQueryBuilder.setMinSdkVersionForFine(Build.VERSION_CODES.Q); - shouldCheckLocationPermissions = true; - } + // If we're enforcing fine starting in Q, we also want to enforce coarse even for + // older SDK versions. + locationQueryBuilder.setMinSdkVersionForCoarse(0); - if (shouldCheckLocationPermissions) { LocationAccessPolicy.LocationPermissionResult result = LocationAccessPolicy.checkLocationPermission( mContext, locationQueryBuilder.build()); @@ -2396,8 +2393,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { try { if (VDBG) log("checkPossibleMissNotify: onServiceStateChanged state=" + mServiceState[phoneId]); - r.callback.onServiceStateChanged( - new ServiceState(mServiceState[phoneId])); + ServiceState ss = new ServiceState(mServiceState[phoneId]); + if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + r.callback.onServiceStateChanged(ss); + } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) { + r.callback.onServiceStateChanged( + ss.sanitizeLocationInfo(false)); + } else { + r.callback.onServiceStateChanged( + ss.sanitizeLocationInfo(true)); + } } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -2436,7 +2441,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = " + mCellInfo.get(phoneId)); } - if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); } } catch (RemoteException ex) { @@ -2484,10 +2490,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) { try { - if (DBG_LOC) log("checkPossibleMissNotify: onCellLocationChanged mCellLocation = " - + mCellLocation[phoneId]); - if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { - r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId])); + if (DBG_LOC) { + log("checkPossibleMissNotify: onCellLocationChanged mCellLocation= " + + mCellLocation[phoneId]); + } + if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + // null will be translated to empty CellLocation object in client. + r.callback.onCellLocationChanged(mCellLocation[phoneId]); } } catch (RemoteException ex) { mRemoveList.add(r.binder); -- GitLab From cc584e777db03316f98298a18a1844e51592ebef Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 26 May 2020 19:02:59 -0700 Subject: [PATCH 025/382] [BACKPORT] Improve location checks in TelephonyRegistry Improve location checking for apps targeting SDK28 or earlier. Bug: 158484422 Test: (cts) atest TelephonyLocationTests; atest PhoneStateListenerTest Merged-In: I8caa3ea409836ce8469d8d8210b481a0284594f2 Change-Id: I8caa3ea409836ce8469d8d8210b481a0284594f2 (cherry picked from commit 4e0c7d16fd76bd7743a7f46ba63c75e8c65d63be) --- .../com/android/server/TelephonyRegistry.java | 55 +++++++++++-------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 23bf955ba9a6..c4f1c805398b 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -310,11 +310,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private List> mPreciseDataConnectionStates = new ArrayList>(); - static final int ENFORCE_COARSE_LOCATION_PERMISSION_MASK = - PhoneStateListener.LISTEN_REGISTRATION_FAILURE - | PhoneStateListener.LISTEN_BARRING_INFO; - - static final int ENFORCE_FINE_LOCATION_PERMISSION_MASK = + // Starting in Q, almost all cellular location requires FINE location enforcement. + // Prior to Q, cellular was available with COARSE location enforcement. Bits in this + // list will be checked for COARSE on apps targeting P or earlier and FINE on Q or later. + static final int ENFORCE_LOCATION_PERMISSION_MASK = PhoneStateListener.LISTEN_CELL_LOCATION | PhoneStateListener.LISTEN_CELL_INFO | PhoneStateListener.LISTEN_REGISTRATION_FAILURE @@ -371,7 +370,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { + " newDefaultPhoneId=" + newDefaultPhoneId); } - //Due to possible risk condition,(notify call back using the new + //Due to possible race condition,(notify call back using the new //defaultSubId comes before new defaultSubId update) we need to recall all //possible missed notify callback synchronized (mRecords) { @@ -904,7 +903,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) { try { if (DBG_LOC) log("listen: mCellIdentity = " + mCellIdentity[phoneId]); - if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { // null will be translated to empty CellLocation object in client. r.callback.onCellLocationChanged(mCellIdentity[phoneId]); } @@ -959,7 +959,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { try { if (DBG_LOC) log("listen: mCellInfo[" + phoneId + "] = " + mCellInfo.get(phoneId)); - if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); } } catch (RemoteException ex) { @@ -1513,7 +1514,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) && idMatch(r.subId, subId, phoneId) && - checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) { try { if (DBG_LOC) { log("notifyCellInfoForSubscriber: mCellInfo=" + cellInfo @@ -1845,7 +1847,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { for (Record r : mRecords) { if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) && idMatch(r.subId, subId, phoneId) && - checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q))) { try { if (DBG_LOC) { log("notifyCellLocation: cellLocation=" + cellLocation @@ -2624,19 +2627,13 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { .setCallingPid(Binder.getCallingPid()) .setCallingUid(Binder.getCallingUid()); - boolean shouldCheckLocationPermissions = false; - if ((events & ENFORCE_COARSE_LOCATION_PERMISSION_MASK) != 0) { - locationQueryBuilder.setMinSdkVersionForCoarse(0); - shouldCheckLocationPermissions = true; - } - - if ((events & ENFORCE_FINE_LOCATION_PERMISSION_MASK) != 0) { + if ((events & ENFORCE_LOCATION_PERMISSION_MASK) != 0) { // Everything that requires fine location started in Q. So far... locationQueryBuilder.setMinSdkVersionForFine(Build.VERSION_CODES.Q); - shouldCheckLocationPermissions = true; - } + // If we're enforcing fine starting in Q, we also want to enforce coarse even for + // older SDK versions. + locationQueryBuilder.setMinSdkVersionForCoarse(0); - if (shouldCheckLocationPermissions) { LocationAccessPolicy.LocationPermissionResult result = LocationAccessPolicy.checkLocationPermission( mContext, locationQueryBuilder.build()); @@ -2803,8 +2800,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { try { if (VDBG) log("checkPossibleMissNotify: onServiceStateChanged state=" + mServiceState[phoneId]); - r.callback.onServiceStateChanged( - new ServiceState(mServiceState[phoneId])); + ServiceState ss = new ServiceState(mServiceState[phoneId]); + if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + r.callback.onServiceStateChanged(ss); + } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) { + r.callback.onServiceStateChanged( + ss.createLocationInfoSanitizedCopy(false)); + } else { + r.callback.onServiceStateChanged( + ss.createLocationInfoSanitizedCopy(true)); + } } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -2849,7 +2854,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = " + mCellInfo.get(phoneId)); } - if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); } } catch (RemoteException ex) { @@ -2915,7 +2921,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("checkPossibleMissNotify: onCellLocationChanged mCellIdentity = " + mCellIdentity[phoneId]); } - if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { + if (checkCoarseLocationAccess(r, Build.VERSION_CODES.BASE) + && checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { // null will be translated to empty CellLocation object in client. r.callback.onCellLocationChanged(mCellIdentity[phoneId]); } -- GitLab From 4ed2e6b76dc955a400ed252ce162ee6335276858 Mon Sep 17 00:00:00 2001 From: Edwin Wong Date: Mon, 28 Sep 2020 21:07:23 -0700 Subject: [PATCH 026/382] Use shared libdrmframeworkcommon. The libdrmframeworkcommon was statically linked to multiple libraries used by libfwdlockengine. When the shared libraries closes, the same block of static memory will be freed twice. Test: CTS forwardlock tests atest CtsDrmTestCases Bug: 155647761 Change-Id: I45113549772d48e925082d15659b1409cbed6499 --- drm/jni/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/drm/jni/Android.bp b/drm/jni/Android.bp index 1e33f0ea5094..68757d86fb89 100644 --- a/drm/jni/Android.bp +++ b/drm/jni/Android.bp @@ -21,6 +21,7 @@ cc_library_shared { shared_libs: [ "libdrmframework", + "libdrmframeworkcommon", "liblog", "libutils", "libandroid_runtime", -- GitLab From 9226fc3723a477751705011cd7eecf063b1c3707 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Mon, 5 Oct 2020 20:00:07 +0800 Subject: [PATCH 027/382] Fix storing the wrong value of mLockdown in setting When user is stopped, the Vpn#onUserStopped() will be called and the value of mLockdown will be set to false then store into setting. This is a wrong behavior because user doesn't change it, so for this kind of case, there is no need to store the value of mLockdown in setting. In fact, there is no need to call Vpn#saveAlwaysOnPackage() when user is stopped because there is nothing changed. Bug: 168500792 Test: atest FrameworksNetTests Change-Id: Ie85a347216614b7873bfdf199165d89527ada3a8 --- services/core/java/com/android/server/connectivity/Vpn.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index d51e1f738659..8adb7f30d857 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -1138,7 +1138,7 @@ public class Vpn { */ public synchronized void onUserStopped() { // Switch off networking lockdown (if it was enabled) - setLockdown(false); + setVpnForcedLocked(false); mAlwaysOn = false; unregisterPackageChangeReceiverLocked(); -- GitLab From e3a71c62959acdb0347262f5730eb09ebb7f74e9 Mon Sep 17 00:00:00 2001 From: JW Wang Date: Wed, 8 Jul 2020 17:06:36 +0800 Subject: [PATCH 028/382] Rewrite how we abandon sessions The original code is flawed in that `pm install-abandon` only abandons the 1st session returned by `pm get-stagedsessions ...`. 1. move AbandonSessionsRule to be shared by multiple host tests 2. use AbandonSessionsRule to do the job Bug: 160754072 Test: StagedInstallInternalTest Change-Id: Ib7b32fbd7b1133ac6a8e6782234a4fe2c5a782bd Merged-In: Ib7b32fbd7b1133ac6a8e6782234a4fe2c5a782bd (cherry picked from commit 3ac333f2d20e240093235d957ba67ce174fe2db8) --- tests/RollbackTest/Android.bp | 9 ++- .../rollback/host/AbandonSessionsRule.java | 62 ------------------- tests/StagedInstallTest/Android.bp | 1 + .../host/StagedInstallInternalTest.java | 19 +++--- .../rollback/host/AbandonSessionsRule.java | 8 +-- 5 files changed, 18 insertions(+), 81 deletions(-) delete mode 100644 tests/RollbackTest/lib/src/com/android/tests/rollback/host/AbandonSessionsRule.java diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp index 3ccbad84f2e0..4f5a30502c91 100644 --- a/tests/RollbackTest/Android.bp +++ b/tests/RollbackTest/Android.bp @@ -29,7 +29,12 @@ java_test_host { name: "StagedRollbackTest", srcs: ["StagedRollbackTest/src/**/*.java"], libs: ["tradefed"], - static_libs: ["testng", "compatibility-tradefed", "RollbackTestLib"], + static_libs: [ + "compatibility-tradefed", + "frameworks-base-hostutils", + "RollbackTestLib", + "testng", + ], test_suites: ["general-tests"], test_config: "StagedRollbackTest.xml", data: [":com.android.apex.apkrollback.test_v1"], @@ -39,7 +44,7 @@ java_test_host { name: "NetworkStagedRollbackTest", srcs: ["NetworkStagedRollbackTest/src/**/*.java"], libs: ["tradefed"], - static_libs: ["RollbackTestLib"], + static_libs: ["RollbackTestLib", "frameworks-base-hostutils"], test_suites: ["general-tests"], test_config: "NetworkStagedRollbackTest.xml", } diff --git a/tests/RollbackTest/lib/src/com/android/tests/rollback/host/AbandonSessionsRule.java b/tests/RollbackTest/lib/src/com/android/tests/rollback/host/AbandonSessionsRule.java deleted file mode 100644 index b08621314ee0..000000000000 --- a/tests/RollbackTest/lib/src/com/android/tests/rollback/host/AbandonSessionsRule.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.tests.rollback.host; - -import com.android.tradefed.device.ITestDevice; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; - -import org.junit.rules.ExternalResource; - -public class AbandonSessionsRule extends ExternalResource { - private final BaseHostJUnit4Test mHost; - - public AbandonSessionsRule(BaseHostJUnit4Test host) { - mHost = host; - } - - @Override - protected void before() throws Throwable { - abandonSessions(mHost.getDevice()); - } - - @Override - protected void after() { - try { - abandonSessions(mHost.getDevice()); - } catch (Exception ignore) { - } - } - - /** - * Abandons all sessions to prevent interference in our tests. - */ - private static void abandonSessions(ITestDevice device) throws Exception { - // No point in abandoning applied or failed sessions. We care about ready sessions only. - String cmdListReadySessions = - "pm list staged-sessions --only-sessionid --only-parent --only-ready"; - String output = device.executeShellCommand(cmdListReadySessions); - if (output.trim().isEmpty()) { - // No sessions to abandon - return; - } - // Ensure we have sufficient privilege to abandon sessions from other apps - device.enableAdbRoot(); - device.executeShellCommand("for i in $(" + cmdListReadySessions - + "); do pm install-abandon $i; done"); - device.disableAdbRoot(); - } -} diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp index 1e286bb15c49..30f3f185203c 100644 --- a/tests/StagedInstallTest/Android.bp +++ b/tests/StagedInstallTest/Android.bp @@ -28,6 +28,7 @@ java_test_host { "testng", "compatibility-tradefed", "module_test_util", + "frameworks-base-hostutils", ], data: [ ":com.android.apex.cts.shim.v2_prebuilt", diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java index 86d5fd80c108..56d1280e5d01 100644 --- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import com.android.ddmlib.Log; +import com.android.tests.rollback.host.AbandonSessionsRule; import com.android.tests.util.ModuleTestUtils; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; @@ -29,6 +30,7 @@ import com.android.tradefed.util.ProcessInfo; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -39,7 +41,9 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { private static final String TAG = StagedInstallInternalTest.class.getSimpleName(); private static final long SYSTEM_SERVER_TIMEOUT_MS = 60 * 1000; - private boolean mWasRoot = false; + + @Rule + public AbandonSessionsRule mHostTestRule = new AbandonSessionsRule(this); private static final String SHIM_V2 = "com.android.apex.cts.shim.v2.apex"; private static final String APK_A = "TestAppAv1.apk"; @@ -71,21 +75,11 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { @Before public void setUp() throws Exception { - mWasRoot = getDevice().isAdbRoot(); - if (!mWasRoot) { - getDevice().enableAdbRoot(); - } cleanUp(); - // Abandon all staged sessions - getDevice().executeShellCommand("pm install-abandon $(pm get-stagedsessions --only-ready " - + "--only-parent --only-sessionid)"); } @After public void tearDown() throws Exception { - if (!mWasRoot) { - getDevice().disableAdbRoot(); - } cleanUp(); } @@ -151,7 +145,10 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { private void restartSystemServer() throws Exception { // Restart the system server long oldStartTime = getDevice().getProcessByName("system_server").getStartTime(); + + getDevice().enableAdbRoot(); // Need root to restart system server assertThat(getDevice().executeShellCommand("am restart")).contains("Restart the system"); + getDevice().disableAdbRoot(); // Wait for new system server process to start long start = System.currentTimeMillis(); diff --git a/tests/utils/hostutils/src/com/android/tests/rollback/host/AbandonSessionsRule.java b/tests/utils/hostutils/src/com/android/tests/rollback/host/AbandonSessionsRule.java index 5bfc75203ae3..b08621314ee0 100644 --- a/tests/utils/hostutils/src/com/android/tests/rollback/host/AbandonSessionsRule.java +++ b/tests/utils/hostutils/src/com/android/tests/rollback/host/AbandonSessionsRule.java @@ -16,14 +16,12 @@ package com.android.tests.rollback.host; -import com.android.ddmlib.Log; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; import org.junit.rules.ExternalResource; -public final class AbandonSessionsRule extends ExternalResource { - private static final String TAG = "AbandonSessionsRule"; +public class AbandonSessionsRule extends ExternalResource { private final BaseHostJUnit4Test mHost; public AbandonSessionsRule(BaseHostJUnit4Test host) { @@ -39,9 +37,7 @@ public final class AbandonSessionsRule extends ExternalResource { protected void after() { try { abandonSessions(mHost.getDevice()); - } catch (Exception e) { - mHost.getDevice().logOnDevice(TAG, Log.LogLevel.ERROR, - "%s", "Failed to abandon sessions"); + } catch (Exception ignore) { } } -- GitLab From eca247f2d33b18d14e0568512a7ee003cbbcd4a9 Mon Sep 17 00:00:00 2001 From: Abhijeet Kaur Date: Wed, 12 Aug 2020 17:34:22 +0100 Subject: [PATCH 029/382] Validate user-supplied tree URIs in DocumentsProvider calls Currently we only validate DocumentsContract.EXTRA_URI, this change validates other URIs suchs as DocumentsContract.EXTRA_TARGET_URI and DocumentsContract.EXTRA_PARENT_URI as well Bug: 157320716 Test: Manually using the test app in b/157320716#comment1 Change-Id: I90fd1e62aa7dc333bf32eb80ccc5b181a1d54e41 Merged-In: I90fd1e62aa7dc333bf32eb80ccc5b181a1d54e41 (cherry picked from commit b9f4fb792812f9a38ac54e69be6f121f7367c017) --- .../android/provider/DocumentsProvider.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 91b591c7b77e..4e1f81919c7d 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -218,8 +218,15 @@ public abstract class DocumentsProvider extends ContentProvider { } /** {@hide} */ - private void enforceTree(Uri documentUri) { - if (isTreeUri(documentUri)) { + private void enforceTreeForExtraUris(Bundle extras) { + enforceTree(extras.getParcelable(DocumentsContract.EXTRA_URI)); + enforceTree(extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI)); + enforceTree(extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI)); + } + + /** {@hide} */ + private void enforceTree(@Nullable Uri documentUri) { + if (documentUri != null && isTreeUri(documentUri)) { final String parent = getTreeDocumentId(documentUri); final String child = getDocumentId(documentUri); if (Objects.equals(parent, child)) { @@ -1080,6 +1087,9 @@ public abstract class DocumentsProvider extends ContentProvider { final Context context = getContext(); final Bundle out = new Bundle(); + // If the URI is a tree URI performs some validation. + enforceTreeForExtraUris(extras); + final Uri extraUri = validateIncomingNullableUri( extras.getParcelable(DocumentsContract.EXTRA_URI)); final Uri extraTargetUri = validateIncomingNullableUri( @@ -1110,9 +1120,6 @@ public abstract class DocumentsProvider extends ContentProvider { "Requested authority " + authority + " doesn't match provider " + mAuthority); } - // If the URI is a tree URI performs some validation. - enforceTree(documentUri); - if (METHOD_IS_CHILD_DOCUMENT.equals(method)) { enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingAttributionTag(), null); -- GitLab From 0fc2997333aa72a1cba229a5f87eee6c6b3339af Mon Sep 17 00:00:00 2001 From: Prameet Shah Date: Mon, 5 Oct 2020 10:58:51 -0700 Subject: [PATCH 030/382] Notify AppOps when notifications are [un]blocked for an app. Bug: crbug.com/934581 Bug: 129992781 Test: atest NotificationManagerServiceTest NotificationManagerTest Test: Verified that blocked apps stay blocked on Android on ChromeOS. Change-Id: Ibb57d295a1c4345d0acc514cbfe9994f8184cc9d (cherry picked from commit 49d1a012b657668195d75e4fa5972c03a50fae0e) --- .../android/server/notification/NotificationManagerService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 5d0981da1906..81c72ef21aaa 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -3056,6 +3056,8 @@ public class NotificationManagerService extends SystemService { UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null); } + mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg, + enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); try { getContext().sendBroadcastAsUser( new Intent(ACTION_APP_BLOCK_STATE_CHANGED) -- GitLab From ce0a50bcdefa5991f6fdde535595e2ba1be58f37 Mon Sep 17 00:00:00 2001 From: Curtis Belmonte Date: Fri, 2 Oct 2020 13:54:38 -0700 Subject: [PATCH 031/382] DO NOT MERGE Check fingerprint client against top activity in auth callback Due to a race condition with activity task stack broadcasts, it's currently possible for fingerprint authentication to succeed for a non-top activity. This means, for example, that a malicious overlay could be drawn in order to mislead the user about what they are authenticating for. This commit addresses the issue by adding a check to the biometric authentication client interface that ensures the authenticating activity is on top at the time of authentication. Otherwise, the pending authentication will fail, as if an incorrect biometric had been presented. Test: Follow steps from b/159249069: 1. Install com.pro100svitlo.fingerprintauthdemo from the Play store. 2. Install the PoC attack app from b/159249069. 3. Start the PoC attack app and press the "Launch PoC attack" button. 4. Use fingerprint to authenticate while the overlay is showing. Before: Authentication succeeds, and a new activity is launched. After: Authentication fails, and no new activity is launched. Bug: 159249069 Change-Id: I9b242a9fee0acbfb430875061e2d809c00fe4b97 Merged-In: I1241a12eafa0bdbac59a8ddd4cf6a0637d467b19 Merged-In: Ie5a0f8c3e9b92d348a78678a6ed192d440c45ffc Merged-In: I289d67e5c7055ed60f7a96725c523d07cd047b23 --- .../biometrics/AuthenticationClient.java | 52 +++++++++++++++++++ .../com/android/server/biometrics/Utils.java | 17 ++++++ 2 files changed, 69 insertions(+) diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java index 4a9ccdee0522..e22e9bd1b671 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java @@ -16,16 +16,22 @@ package com.android.server.biometrics; +import android.app.ActivityManager; +import android.app.ActivityTaskManager; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricsProtoEnums; import android.os.IBinder; import android.os.RemoteException; import android.security.KeyStore; +import android.util.EventLog; import android.util.Slog; import java.util.ArrayList; +import java.util.List; /** * A class to keep track of the authentication state for a given client. @@ -149,7 +155,53 @@ public abstract class AuthenticationClient extends ClientMonitor { + ", requireConfirmation: " + mRequireConfirmation + ", user: " + getTargetUserId()); + // Ensure authentication only succeeds if the client activity is on top or is keyguard. + boolean isBackgroundAuth = false; + if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString())) { + try { + final List tasks = + ActivityTaskManager.getService().getTasks(1); + if (tasks == null || tasks.isEmpty()) { + Slog.e(TAG, "No running tasks reported"); + isBackgroundAuth = true; + } else { + final ComponentName topActivity = tasks.get(0).topActivity; + if (topActivity == null) { + Slog.e(TAG, "Unable to get top activity"); + isBackgroundAuth = true; + } else { + final String topPackage = topActivity.getPackageName(); + if (!topPackage.contentEquals(getOwnerString())) { + Slog.e(TAG, "Background authentication detected, top: " + topPackage + + ", client: " + this); + isBackgroundAuth = true; + } + } + } + } catch (RemoteException e) { + Slog.e(TAG, "Unable to get running tasks", e); + isBackgroundAuth = true; + } + } + + // Fail authentication if we can't confirm the client activity is on top. + if (isBackgroundAuth) { + Slog.e(TAG, "Failing possible background authentication"); + authenticated = false; + + // SafetyNet logging for exploitation attempts of b/159249069. + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Attempted background authentication"); + } + if (authenticated) { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Successful background authentication!"); + } mAlreadyDone = true; if (listener != null) { diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java index 4fa29ac541f9..3c1e8a6ea57b 100644 --- a/services/core/java/com/android/server/biometrics/Utils.java +++ b/services/core/java/com/android/server/biometrics/Utils.java @@ -16,11 +16,17 @@ package com.android.server.biometrics; +import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; + +import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Build; import android.os.UserHandle; import android.provider.Settings; +import com.android.internal.R; + public class Utils { public static boolean isDebugEnabled(Context context, int targetUserId) { if (targetUserId == UserHandle.USER_NULL) { @@ -38,4 +44,15 @@ public class Utils { } return true; } + + static boolean isKeyguard(Context context, String clientPackage) { + final boolean hasPermission = context.checkCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL) + == PackageManager.PERMISSION_GRANTED; + + final ComponentName keyguardComponent = ComponentName.unflattenFromString( + context.getResources().getString(R.string.config_keyguardComponent)); + final String keyguardPackage = keyguardComponent != null + ? keyguardComponent.getPackageName() : null; + return hasPermission && keyguardPackage != null && keyguardPackage.equals(clientPackage); + } } -- GitLab From be924dac10523e1a540147702bbefbb2bdcdd4c8 Mon Sep 17 00:00:00 2001 From: Curtis Belmonte Date: Fri, 2 Oct 2020 16:18:37 -0700 Subject: [PATCH 032/382] DO NOT MERGE Check fingerprint client against top activity in auth callback Due to a race condition with activity task stack broadcasts, it's currently possible for fingerprint authentication to succeed for a non-top activity. This means, for example, that a malicious overlay could be drawn in order to mislead the user about what they are authenticating for. This commit addresses the issue by adding a check to the biometric authentication client interface that ensures the authenticating activity is on top at the time of authentication. Otherwise, the pending authentication will fail, as if an incorrect biometric had been presented. Test: Follow steps from b/159249069: 1. Install com.pro100svitlo.fingerprintauthdemo from the Play store. 2. Install the PoC attack app from b/159249069. 3. Start the PoC attack app and press the "Launch PoC attack" button. 4. Use fingerprint to authenticate while the overlay is showing. Before: Authentication succeeds, and a new activity is launched. After: Authentication fails, and no new activity is launched. Bug: 159249069 Change-Id: Iee6af379515385777984da55048c1efd9339ed88 Merged-In: I9b242a9fee0acbfb430875061e2d809c00fe4b97 Merged-In: I1241a12eafa0bdbac59a8ddd4cf6a0637d467b19 Merged-In: Ie5a0f8c3e9b92d348a78678a6ed192d440c45ffc Merged-In: I289d67e5c7055ed60f7a96725c523d07cd047b23 --- .../biometrics/AuthenticationClient.java | 53 +++++++++++++++++++ .../com/android/server/biometrics/Utils.java | 17 ++++++ 2 files changed, 70 insertions(+) diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java index b899d028869b..552df8e365a2 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java @@ -16,16 +16,22 @@ package com.android.server.biometrics; +import android.app.ActivityManager; +import android.app.ActivityTaskManager; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricsProtoEnums; import android.os.IBinder; import android.os.RemoteException; import android.security.KeyStore; +import android.util.EventLog; import android.util.Slog; import java.util.ArrayList; +import java.util.List; /** * A class to keep track of the authentication state for a given client. @@ -144,7 +150,54 @@ public abstract class AuthenticationClient extends ClientMonitor { + ", requireConfirmation: " + mRequireConfirmation + ", user: " + getTargetUserId()); + // Ensure authentication only succeeds if the client activity is on top or is keyguard. + boolean isBackgroundAuth = false; + if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString())) { + try { + final List tasks = + ActivityTaskManager.getService().getTasks(1); + if (tasks == null || tasks.isEmpty()) { + Slog.e(TAG, "No running tasks reported"); + isBackgroundAuth = true; + } else { + final ComponentName topActivity = tasks.get(0).topActivity; + if (topActivity == null) { + Slog.e(TAG, "Unable to get top activity"); + isBackgroundAuth = true; + } else { + final String topPackage = topActivity.getPackageName(); + if (!topPackage.contentEquals(getOwnerString())) { + Slog.e(TAG, "Background authentication detected, top: " + topPackage + + ", client: " + this); + isBackgroundAuth = true; + } + } + } + } catch (RemoteException e) { + Slog.e(TAG, "Unable to get running tasks", e); + isBackgroundAuth = true; + } + } + + // Fail authentication if we can't confirm the client activity is on top. + if (isBackgroundAuth) { + Slog.e(TAG, "Failing possible background authentication"); + authenticated = false; + + // SafetyNet logging for exploitation attempts of b/159249069. + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Attempted background authentication"); + } + if (authenticated) { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Successful background authentication!"); + } + mAlreadyDone = true; if (listener != null) { diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java index 5544bede92f2..80d93153776a 100644 --- a/services/core/java/com/android/server/biometrics/Utils.java +++ b/services/core/java/com/android/server/biometrics/Utils.java @@ -16,10 +16,16 @@ package com.android.server.biometrics; +import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; + +import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Build; import android.provider.Settings; +import com.android.internal.R; + public class Utils { public static boolean isDebugEnabled(Context context, int targetUserId) { if (!(Build.IS_ENG || Build.IS_USERDEBUG)) { @@ -33,4 +39,15 @@ public class Utils { } return true; } + + static boolean isKeyguard(Context context, String clientPackage) { + final boolean hasPermission = context.checkCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL) + == PackageManager.PERMISSION_GRANTED; + + final ComponentName keyguardComponent = ComponentName.unflattenFromString( + context.getResources().getString(R.string.config_keyguardComponent)); + final String keyguardPackage = keyguardComponent != null + ? keyguardComponent.getPackageName() : null; + return hasPermission && keyguardPackage != null && keyguardPackage.equals(clientPackage); + } } -- GitLab From d4774f910101d20b36afff4b39ce824b89d491cc Mon Sep 17 00:00:00 2001 From: Curtis Belmonte Date: Mon, 5 Oct 2020 15:37:53 -0700 Subject: [PATCH 033/382] DO NOT MERGE Check fingerprint client against top activity in auth callback Due to a race condition with activity task stack broadcasts, it's currently possible for fingerprint authentication to succeed for a non-top activity. This means, for example, that a malicious overlay could be drawn in order to mislead the user about what they are authenticating for. This commit addresses the issue by adding a check to the fingerprint authentication client interface that ensures the authenticating activity is on top at the time of authentication. Otherwise, the pending authentication will fail, as if an incorrect biometric been presented. Test: Follow steps from b/159249069: 1. Install com.pro100svitlo.fingerprintauthdemo from the Play store. 2. Install the PoC attack app from b/159249069. 3. Start the PoC attack app and press the "Launch PoC attack" button. 4. Use fingerprint to authenticate while the overlay is showing. Before: Authentication succeeds, and a new activity is launched. After: Authentication fails, and no new activity is launched. Bug: 159249069 Change-Id: If5cdf8ffaf3aa7d8a1ac81272e3bfb2cc7cdddf1 Merged-In: Iee6af379515385777984da55048c1efd9339ed88 Merged-In: I9b242a9fee0acbfb430875061e2d809c00fe4b97 Merged-In: I1241a12eafa0bdbac59a8ddd4cf6a0637d467b19 Merged-In: Ie5a0f8c3e9b92d348a78678a6ed192d440c45ffc Merged-In: I289d67e5c7055ed60f7a96725c523d07cd047b23 --- .../fingerprint/AuthenticationClient.java | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java index afd1a94bf506..61bc843aad79 100644 --- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java +++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java @@ -16,7 +16,15 @@ package com.android.server.fingerprint; +import static android.Manifest.permission.USE_BIOMETRIC; +import static android.Manifest.permission.USE_FINGERPRINT; + +import android.app.ActivityManager; +import android.app.IActivityManager; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.IBiometricPromptReceiver; @@ -26,12 +34,16 @@ import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; +import android.util.EventLog; import android.util.Slog; +import com.android.internal.R; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.statusbar.IStatusBarService; +import java.util.List; + /** * A class to keep track of the authentication state for a given client. */ @@ -156,10 +168,68 @@ public abstract class AuthenticationClient extends ClientMonitor { boolean result = false; boolean authenticated = fingerId != 0; + // Ensure authentication only succeeds if the client activity is on top or is keyguard. + boolean isBackgroundAuth = false; + if (authenticated && !isKeyguard(getContext(), getOwnerString())) { + final ActivityManager activityManager = + (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE); + final IActivityManager activityManagerService = activityManager != null + ? activityManager.getService() + : null; + if (activityManagerService == null) { + Slog.e(TAG, "Unable to get activity manager service"); + isBackgroundAuth = true; + } else { + try { + final List tasks = + activityManagerService.getTasks(1); + if (tasks == null || tasks.isEmpty()) { + Slog.e(TAG, "No running tasks reported"); + isBackgroundAuth = true; + } else { + final ComponentName topActivity = tasks.get(0).topActivity; + if (topActivity == null) { + Slog.e(TAG, "Unable to get top activity"); + isBackgroundAuth = true; + } else { + final String topPackage = topActivity.getPackageName(); + if (!topPackage.contentEquals(getOwnerString())) { + Slog.e(TAG, "Background authentication detected, top: " + topPackage + + ", client: " + this); + isBackgroundAuth = true; + } + } + } + } catch (RemoteException e) { + Slog.e(TAG, "Unable to get running tasks", e); + isBackgroundAuth = true; + } + } + } + + // Fail authentication if we can't confirm the client activity is on top. + if (isBackgroundAuth) { + Slog.e(TAG, "Failing possible background authentication"); + authenticated = false; + + // SafetyNet logging for exploitation attempts of b/159249069. + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Attempted background authentication"); + } + // If the fingerprint dialog is showing, notify authentication succeeded if (mBundle != null) { try { if (authenticated) { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", + appInfo != null ? appInfo.uid : -1, + "Successful background authentication! Dialog notified"); + } + mStatusBarService.onFingerprintAuthenticated(); } else { mStatusBarService.onFingerprintHelp(getContext().getResources().getString( @@ -178,6 +248,14 @@ public abstract class AuthenticationClient extends ClientMonitor { if (!authenticated) { receiver.onAuthenticationFailed(getHalDeviceId()); } else { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", + appInfo != null ? appInfo.uid : -1, + "Successful background authentication! Receiver notified"); + } + if (DEBUG) { Slog.v(TAG, "onAuthenticated(owner=" + getOwnerString() + ", id=" + fingerId + ", gp=" + groupId + ")"); @@ -226,6 +304,13 @@ public abstract class AuthenticationClient extends ClientMonitor { } result |= lockoutMode != LOCKOUT_NONE; // in a lockout mode } else { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Successful background authentication! Lockout reset"); + } + if (receiver != null) { vibrateSuccess(); } @@ -236,6 +321,20 @@ public abstract class AuthenticationClient extends ClientMonitor { return result; } + private static boolean isKeyguard(Context context, String clientPackage) { + final boolean hasFingerPermission = context.checkCallingOrSelfPermission(USE_FINGERPRINT) + == PackageManager.PERMISSION_GRANTED; + final boolean hasBiometricPermission = context.checkCallingOrSelfPermission(USE_BIOMETRIC) + == PackageManager.PERMISSION_GRANTED; + final boolean hasPermission = hasFingerPermission || hasBiometricPermission; + + final ComponentName keyguardComponent = ComponentName.unflattenFromString( + context.getResources().getString(R.string.config_keyguardComponent)); + final String keyguardPackage = keyguardComponent != null + ? keyguardComponent.getPackageName() : null; + return hasPermission && keyguardPackage != null && keyguardPackage.equals(clientPackage); + } + /** * Start authentication */ -- GitLab From 7786f4908fc213447c53dee5f06f830eebc9f110 Mon Sep 17 00:00:00 2001 From: Curtis Belmonte Date: Mon, 5 Oct 2020 17:54:15 -0700 Subject: [PATCH 034/382] DO NOT MERGE Check fingerprint client against top activity in auth callback Due to a race condition with activity task stack broadcasts, it's currently possible for fingerprint authentication to succeed for a non-top activity. This means, for example, that a malicious overlay could be drawn in order to mislead the user about what they are authenticating for. This commit addresses the issue by adding a check to the fingerprint authentication client interface that ensures the authenticating activity is on top at the time of authentication. Otherwise, the pending authentication will fail, as if an incorrect biometric been presented. Test: Follow steps from b/159249069: 1. Install com.pro100svitlo.fingerprintauthdemo from the Play store. 2. Install the PoC attack app from b/159249069. 3. Start the PoC attack app and press the "Launch PoC attack" button. 4. Use fingerprint to authenticate while the overlay is showing. Before: Authentication succeeds, and a new activity is launched. After: Authentication fails, and no new activity is launched. Bug: 159249069 Change-Id: I0707c3f55eaf2a69c6625a3ceb3b5626b3676b26 Merged-In: If5cdf8ffaf3aa7d8a1ac81272e3bfb2cc7cdddf1 Merged-In: Iee6af379515385777984da55048c1efd9339ed88 Merged-In: I9b242a9fee0acbfb430875061e2d809c00fe4b97 Merged-In: I1241a12eafa0bdbac59a8ddd4cf6a0637d467b19 Merged-In: Ie5a0f8c3e9b92d348a78678a6ed192d440c45ffc Merged-In: I289d67e5c7055ed60f7a96725c523d07cd047b23 --- .../fingerprint/AuthenticationClient.java | 94 ++++++++++++++++++- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java index 370e569f2598..0c73c4410cb2 100644 --- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java +++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java @@ -16,18 +16,29 @@ package com.android.server.fingerprint; -import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import static android.Manifest.permission.USE_FINGERPRINT; +import android.app.ActivityManager; +import android.app.IActivityManager; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.os.IBinder; import android.os.RemoteException; +import android.util.EventLog; import android.util.Slog; +import com.android.internal.R; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; + +import java.util.List; + /** * A class to keep track of the authentication state for a given client. */ @@ -53,6 +64,56 @@ public abstract class AuthenticationClient extends ClientMonitor { boolean result = false; boolean authenticated = fingerId != 0; + // Ensure authentication only succeeds if the client activity is on top or is keyguard. + boolean isBackgroundAuth = false; + if (authenticated && !isKeyguard(getContext(), getOwnerString())) { + final ActivityManager activityManager = + (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE); + final IActivityManager activityManagerService = activityManager != null + ? activityManager.getService() + : null; + if (activityManagerService == null) { + Slog.e(TAG, "Unable to get activity manager service"); + isBackgroundAuth = true; + } else { + try { + final List tasks = + activityManagerService.getTasks(1, 0 /* flags */); + if (tasks == null || tasks.isEmpty()) { + Slog.e(TAG, "No running tasks reported"); + isBackgroundAuth = true; + } else { + final ComponentName topActivity = tasks.get(0).topActivity; + if (topActivity == null) { + Slog.e(TAG, "Unable to get top activity"); + isBackgroundAuth = true; + } else { + final String topPackage = topActivity.getPackageName(); + if (!topPackage.contentEquals(getOwnerString())) { + Slog.e(TAG, "Background authentication detected, top: " + topPackage + + ", client: " + this); + isBackgroundAuth = true; + } + } + } + } catch (RemoteException e) { + Slog.e(TAG, "Unable to get running tasks", e); + isBackgroundAuth = true; + } + } + } + + // Fail authentication if we can't confirm the client activity is on top. + if (isBackgroundAuth) { + Slog.e(TAG, "Failing possible background authentication"); + authenticated = false; + + // SafetyNet logging for exploitation attempts of b/159249069. + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Attempted background authentication"); + } + IFingerprintServiceReceiver receiver = getReceiver(); if (receiver != null) { try { @@ -61,6 +122,14 @@ public abstract class AuthenticationClient extends ClientMonitor { if (!authenticated) { receiver.onAuthenticationFailed(getHalDeviceId()); } else { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", + appInfo != null ? appInfo.uid : -1, + "Successful background authentication! Receiver notified"); + } + if (DEBUG) { Slog.v(TAG, "onAuthenticated(owner=" + getOwnerString() + ", id=" + fingerId + ", gp=" + groupId + ")"); @@ -98,6 +167,14 @@ public abstract class AuthenticationClient extends ClientMonitor { } result |= lockoutMode != LOCKOUT_NONE; // in a lockout mode } else { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", + appInfo != null ? appInfo.uid : -1, + "Successful background authentication! Lockout reset"); + } + if (receiver != null) { vibrateSuccess(); } @@ -107,6 +184,17 @@ public abstract class AuthenticationClient extends ClientMonitor { return result; } + private static boolean isKeyguard(Context context, String clientPackage) { + final boolean hasPermission = context.checkCallingOrSelfPermission(USE_FINGERPRINT) + == PackageManager.PERMISSION_GRANTED; + + final ComponentName keyguardComponent = ComponentName.unflattenFromString( + context.getResources().getString(R.string.config_keyguardComponent)); + final String keyguardPackage = keyguardComponent != null + ? keyguardComponent.getPackageName() : null; + return hasPermission && keyguardPackage != null && keyguardPackage.equals(clientPackage); + } + /** * Start authentication */ -- GitLab From bb5706541d178ebe13894a3d3561c4aacf710a8e Mon Sep 17 00:00:00 2001 From: Curtis Belmonte Date: Mon, 5 Oct 2020 19:02:52 -0700 Subject: [PATCH 035/382] DO NOT MERGE Check fingerprint client against top activity in auth callback Due to a race condition with activity task stack broadcasts, it's currently possible for fingerprint authentication to succeed for a non-top activity. This means, for example, that a malicious overlay could be drawn in order to mislead the user about what they are authenticating for. This commit addresses the issue by adding a check to the fingerprint authentication client interface that ensures the authenticating activity is on top at the time of authentication. Otherwise, the pending authentication will fail, as if an incorrect biometric been presented. Test: Follow steps from b/159249069: 1. Install com.pro100svitlo.fingerprintauthdemo from the Play store. 2. Install the PoC attack app from b/159249069. 3. Start the PoC attack app and press the "Launch PoC attack" button. 4. Use fingerprint to authenticate while the overlay is showing. Before: Authentication succeeds, and a new activity is launched. After: Authentication fails, and no new activity is launched. Bug: 159249069 Change-Id: Ic482cbfdd810e9c8b60a5093fd8d615ee320a6a6 Merged-In: I0707c3f55eaf2a69c6625a3ceb3b5626b3676b26 Merged-In: If5cdf8ffaf3aa7d8a1ac81272e3bfb2cc7cdddf1 Merged-In: Iee6af379515385777984da55048c1efd9339ed88 Merged-In: I9b242a9fee0acbfb430875061e2d809c00fe4b97 Merged-In: I1241a12eafa0bdbac59a8ddd4cf6a0637d467b19 Merged-In: Ie5a0f8c3e9b92d348a78678a6ed192d440c45ffc Merged-In: I289d67e5c7055ed60f7a96725c523d07cd047b23 --- .../fingerprint/AuthenticationClient.java | 94 ++++++++++++++++++- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java index 5339bac8b030..3f1dbe4bc483 100644 --- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java +++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java @@ -16,18 +16,29 @@ package com.android.server.fingerprint; -import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; -import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import static android.Manifest.permission.USE_FINGERPRINT; +import android.app.ActivityManager; +import android.app.IActivityManager; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.IFingerprintServiceReceiver; import android.os.IBinder; import android.os.RemoteException; +import android.util.EventLog; import android.util.Slog; +import com.android.internal.R; +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; + +import java.util.List; + /** * A class to keep track of the authentication state for a given client. */ @@ -53,6 +64,56 @@ public abstract class AuthenticationClient extends ClientMonitor { boolean result = false; boolean authenticated = fingerId != 0; + // Ensure authentication only succeeds if the client activity is on top or is keyguard. + boolean isBackgroundAuth = false; + if (authenticated && !isKeyguard(getContext(), getOwnerString())) { + final ActivityManager activityManager = + (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE); + final IActivityManager activityManagerService = activityManager != null + ? activityManager.getService() + : null; + if (activityManagerService == null) { + Slog.e(TAG, "Unable to get activity manager service"); + isBackgroundAuth = true; + } else { + try { + final List tasks = + activityManagerService.getTasks(1, 0 /* flags */); + if (tasks == null || tasks.isEmpty()) { + Slog.e(TAG, "No running tasks reported"); + isBackgroundAuth = true; + } else { + final ComponentName topActivity = tasks.get(0).topActivity; + if (topActivity == null) { + Slog.e(TAG, "Unable to get top activity"); + isBackgroundAuth = true; + } else { + final String topPackage = topActivity.getPackageName(); + if (!topPackage.contentEquals(getOwnerString())) { + Slog.e(TAG, "Background authentication detected, top: " + topPackage + + ", client: " + this); + isBackgroundAuth = true; + } + } + } + } catch (RemoteException e) { + Slog.e(TAG, "Unable to get running tasks", e); + isBackgroundAuth = true; + } + } + } + + // Fail authentication if we can't confirm the client activity is on top. + if (isBackgroundAuth) { + Slog.e(TAG, "Failing possible background authentication"); + authenticated = false; + + // SafetyNet logging for exploitation attempts of b/159249069. + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Attempted background authentication"); + } + IFingerprintServiceReceiver receiver = getReceiver(); if (receiver != null) { try { @@ -61,6 +122,14 @@ public abstract class AuthenticationClient extends ClientMonitor { if (!authenticated) { receiver.onAuthenticationFailed(getHalDeviceId()); } else { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", + appInfo != null ? appInfo.uid : -1, + "Successful background authentication! Receiver notified"); + } + if (DEBUG) { Slog.v(TAG, "onAuthenticated(owner=" + getOwnerString() + ", id=" + fingerId + ", gp=" + groupId + ")"); @@ -98,6 +167,14 @@ public abstract class AuthenticationClient extends ClientMonitor { } result |= lockoutMode != LOCKOUT_NONE; // in a lockout mode } else { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", + appInfo != null ? appInfo.uid : -1, + "Successful background authentication! Lockout reset"); + } + if (receiver != null) { FingerprintUtils.vibrateFingerprintSuccess(getContext()); } @@ -107,6 +184,17 @@ public abstract class AuthenticationClient extends ClientMonitor { return result; } + private static boolean isKeyguard(Context context, String clientPackage) { + final boolean hasPermission = context.checkCallingOrSelfPermission(USE_FINGERPRINT) + == PackageManager.PERMISSION_GRANTED; + + final ComponentName keyguardComponent = ComponentName.unflattenFromString( + context.getResources().getString(R.string.config_keyguardComponent)); + final String keyguardPackage = keyguardComponent != null + ? keyguardComponent.getPackageName() : null; + return hasPermission && keyguardPackage != null && keyguardPackage.equals(clientPackage); + } + /** * Start authentication */ -- GitLab From 752cb249a69218b803e52b8db88f1a5bdd29e797 Mon Sep 17 00:00:00 2001 From: David Su Date: Wed, 7 Oct 2020 04:08:45 +0000 Subject: [PATCH 036/382] RESTRICT AUTOMERGE Implement sendBroadcastAsUserMultiplePermissions in BridgeContext. sendBroadcastAsUserMultiplePermissions was added to Context.java. Implementing in BridgeContext. Fix oc-dev since BridgeContext is in frameworks/base/tools/layoutlib, whereas in later branches the file is in frameworks/layoutlib Test: Compile / build (actual usage is documented in other bugs) Bug: 159373687 Change-Id: I8715b6fce7039268eb29914cb15f68ab922f4d3f Merged-In: I857ea00cc58a0abbb77960643f361dd6dd9c8b56 --- .../android/layoutlib/bridge/android/BridgeContext.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 1fc5d7256310..c658c5d728a9 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -1676,6 +1676,13 @@ public class BridgeContext extends Context { } + @Override + public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user, + String[] receiverPermissions) { + // pass + + } + @Override public void sendBroadcast(Intent arg0, String arg1, Bundle arg2) { // pass -- GitLab From cb7d29269102d821fb4e3e531e3f34db8f7a2d85 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Wed, 7 Oct 2020 12:56:12 -0400 Subject: [PATCH 037/382] Allow notfication vibrations in DND Test: manual Fixes: 169609238 Change-Id: I5993a2519bfb63ce405c05169754750aaae7b105 --- .../notification/NotificationManagerService.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 81c72ef21aaa..14635ccc7bc7 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -59,6 +59,7 @@ import static android.content.pm.PackageManager.MATCH_ALL; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.media.AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; @@ -7100,8 +7101,15 @@ public class NotificationManagerService extends SystemService { // so need to check the notification still valide for vibrate. synchronized (mNotificationLock) { if (mNotificationsByKey.get(record.getKey()) != null) { + // Vibrator checks the appops for the op package, not the caller, + // so we need to add the bypass dnd flag to be heard. it's ok to + // always add this flag here because we've already checked that we can + // bypass dnd + AudioAttributes.Builder aab = + new AudioAttributes.Builder(record.getAudioAttributes()) + .setFlags(FLAG_BYPASS_INTERRUPTION_POLICY); mVibrator.vibrate(record.getSbn().getUid(), record.getSbn().getOpPkg(), - effect, "Notification (delayed)", record.getAudioAttributes()); + effect, "Notification (delayed)", aab.build()); } else { Slog.e(TAG, "No vibration for canceled notification : " + record.getKey()); -- GitLab From 0f1fd8c236a0320a873068c98c0518f930149aaa Mon Sep 17 00:00:00 2001 From: Emilian Peev Date: Wed, 9 Sep 2020 17:32:26 -0700 Subject: [PATCH 038/382] Camera: Track native metadata allocations Native camera metadata buffers can increase both in size and count over prolonged periods of camera usage. Register and track the native buffer allocation in the Java VM to improve GC. Bug: 168100424 Bug: 170243539 Test: Camera CTS Change-Id: I7a10c2f360307a6c1afeecde24dc42184106b872 --- .../camera2/impl/CameraMetadataNative.java | 30 +++++++++++++++++++ ...ndroid_hardware_camera2_CameraMetadata.cpp | 13 ++++++++ 2 files changed, 43 insertions(+) diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 986e6eafac2a..9d4ab0b08e92 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -72,6 +72,7 @@ import android.util.Range; import android.util.Size; import dalvik.annotation.optimization.FastNative; +import dalvik.system.VMRuntime; import java.io.IOException; import java.nio.ByteBuffer; @@ -351,6 +352,7 @@ public class CameraMetadataNative implements Parcelable { if (mMetadataPtr == 0) { throw new OutOfMemoryError("Failed to allocate native CameraMetadata"); } + updateNativeAllocation(); } /** @@ -362,6 +364,7 @@ public class CameraMetadataNative implements Parcelable { if (mMetadataPtr == 0) { throw new OutOfMemoryError("Failed to allocate native CameraMetadata"); } + updateNativeAllocation(); } /** @@ -443,6 +446,7 @@ public class CameraMetadataNative implements Parcelable { public void readFromParcel(Parcel in) { nativeReadFromParcel(in, mMetadataPtr); + updateNativeAllocation(); } /** @@ -533,6 +537,11 @@ public class CameraMetadataNative implements Parcelable { // Delete native pointer, but does not clear it nativeClose(mMetadataPtr); mMetadataPtr = 0; + + if (mBufferSize > 0) { + VMRuntime.getRuntime().registerNativeFree(mBufferSize); + } + mBufferSize = 0; } private T getBase(CameraCharacteristics.Key key) { @@ -1645,9 +1654,26 @@ public class CameraMetadataNative implements Parcelable { return true; } + private void updateNativeAllocation() { + long currentBufferSize = nativeGetBufferSize(mMetadataPtr); + + if (currentBufferSize != mBufferSize) { + if (mBufferSize > 0) { + VMRuntime.getRuntime().registerNativeFree(mBufferSize); + } + + mBufferSize = currentBufferSize; + + if (mBufferSize > 0) { + VMRuntime.getRuntime().registerNativeAllocation(mBufferSize); + } + } + } + private int mCameraId = -1; private boolean mHasMandatoryConcurrentStreams = false; private Size mDisplaySize = new Size(0, 0); + private long mBufferSize = 0; /** * Set the current camera Id. @@ -1705,6 +1731,8 @@ public class CameraMetadataNative implements Parcelable { private static synchronized native boolean nativeIsEmpty(long ptr); @FastNative private static synchronized native int nativeGetEntryCount(long ptr); + @FastNative + private static synchronized native long nativeGetBufferSize(long ptr); @UnsupportedAppUsage @FastNative @@ -1744,6 +1772,8 @@ public class CameraMetadataNative implements Parcelable { mCameraId = other.mCameraId; mHasMandatoryConcurrentStreams = other.mHasMandatoryConcurrentStreams; mDisplaySize = other.mDisplaySize; + updateNativeAllocation(); + other.updateNativeAllocation(); } /** diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp index 9ad4cd9e9ae8..b5955c4c46cc 100644 --- a/core/jni/android_hardware_camera2_CameraMetadata.cpp +++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp @@ -249,6 +249,16 @@ static jint CameraMetadata_getEntryCount(JNIEnv *env, jclass thiz, jlong ptr) { return metadata->entryCount(); } +static jlong CameraMetadata_getBufferSize(JNIEnv *env, jclass thiz, jlong ptr) { + ALOGV("%s", __FUNCTION__); + + CameraMetadata* metadata = CameraMetadata_getPointerThrow(env, ptr); + + if (metadata == NULL) return 0; + + return metadata->bufferSize(); +} + // idempotent. calling more than once has no effect. static void CameraMetadata_close(JNIEnv *env, jclass thiz, jlong ptr) { ALOGV("%s", __FUNCTION__); @@ -552,6 +562,9 @@ static const JNINativeMethod gCameraMetadataMethods[] = { { "nativeGetEntryCount", "(J)I", (void*)CameraMetadata_getEntryCount }, + { "nativeGetBufferSize", + "(J)J", + (void*)CameraMetadata_getBufferSize }, { "nativeClose", "(J)V", (void*)CameraMetadata_close }, -- GitLab From c5210dc59fcd2c0e4e0bf95c11a5c742fed21050 Mon Sep 17 00:00:00 2001 From: Michael Wachenschwanz Date: Tue, 1 Sep 2020 16:22:06 -0700 Subject: [PATCH 039/382] Ignore non test package events for AppStandbyControllerTests Fixes: 165604824 Test: atest AppStandbbyControllerTests --rerun-until-failure 10 Change-Id: Id444028fba7f7177613e4b49c2231745f4125b01 (cherry picked from commit 4eb996de3625ff62f8271ef67eb9bcc564a2b5b3) --- .../usage/AppStandbyControllerTests.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java index 4dec7a1a0ab9..fcd3a51a9635 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -139,10 +139,13 @@ public class AppStandbyControllerTests { private AppStandbyController mController; private CountDownLatch mStateChangedLatch = new CountDownLatch(1); + private String mLatchPkgName = null; private AppIdleStateChangeListener mListener = new AppIdleStateChangeListener() { @Override public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket, int reason) { + // Ignore events not related to mLatchPkgName, if set. + if (mLatchPkgName != null && !mLatchPkgName.equals(packageName)) return; mStateChangedLatch.countDown(); } }; @@ -374,6 +377,7 @@ public class AppStandbyControllerTests { mInjector.mElapsedRealtime, false)); controller.addListener(mListener); + mLatchPkgName = null; return controller; } @@ -1377,7 +1381,7 @@ public class AppStandbyControllerTests { @Test public void testUnexemptedSyncScheduled() throws Exception { - mStateChangedLatch = new CountDownLatch(1); + rearmLatch(PACKAGE_1); mController.addListener(mListener); assertEquals("Test package did not start in the Never bucket", STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1)); @@ -1389,7 +1393,7 @@ public class AppStandbyControllerTests { setAndAssertBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM); - mStateChangedLatch = new CountDownLatch(1); + rearmLatch(PACKAGE_1); mController.postReportSyncScheduled(PACKAGE_1, USER_ID, false); mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); assertEquals("Unexempted sync scheduled should not elevate a non Never bucket", @@ -1400,7 +1404,7 @@ public class AppStandbyControllerTests { public void testExemptedSyncScheduled() throws Exception { setAndAssertBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM); mInjector.mDeviceIdleMode = true; - mStateChangedLatch = new CountDownLatch(1); + rearmLatch(PACKAGE_1); mController.postReportSyncScheduled(PACKAGE_1, USER_ID, true); mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); assertEquals("Exempted sync scheduled in doze should set bucket to working set", @@ -1408,7 +1412,7 @@ public class AppStandbyControllerTests { setAndAssertBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM); mInjector.mDeviceIdleMode = false; - mStateChangedLatch = new CountDownLatch(1); + rearmLatch(PACKAGE_1); mController.postReportSyncScheduled(PACKAGE_1, USER_ID, true); mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); assertEquals("Exempted sync scheduled while not in doze should set bucket to active", @@ -1558,10 +1562,19 @@ public class AppStandbyControllerTests { } private void setAndAssertBucket(String pkg, int user, int bucket, int reason) throws Exception { - mStateChangedLatch = new CountDownLatch(1); + rearmLatch(pkg); mController.setAppStandbyBucket(pkg, user, bucket, reason); mStateChangedLatch.await(100, TimeUnit.MILLISECONDS); assertEquals("Failed to set package bucket", bucket, getStandbyBucket(mController, PACKAGE_1)); } + + private void rearmLatch(String pkgName) { + mLatchPkgName = pkgName; + mStateChangedLatch = new CountDownLatch(1); + } + + private void rearmLatch() { + rearmLatch(null); + } } -- GitLab From 90433d3f1295c92035b65d42908aead62ea0c8da Mon Sep 17 00:00:00 2001 From: Curtis Belmonte Date: Wed, 7 Oct 2020 15:51:09 -0700 Subject: [PATCH 040/382] DO NOT MERGE Check fingerprint client against top activity in auth callback Due to a race condition with activity task stack broadcasts, it's currently possible for fingerprint authentication to succeed for a non-top activity. This means, for example, that a malicious overlay could be drawn in order to mislead the user about what they are authenticating for. This commit addresses the issue by adding a check to the biometric authentication client interface that ensures the authenticating activity is on top at the time of authentication. Otherwise, the pending authentication will fail, as if an incorrect biometric had been presented. Test: Follow steps from b/159249069: 1. Install com.pro100svitlo.fingerprintauthdemo from the Play store. 2. Install the PoC attack app from b/159249069. 3. Start the PoC attack app and press the "Launch PoC attack" button. 4. Use fingerprint to authenticate while the overlay is showing. Before: Authentication succeeds, and a new activity is launched. After: Authentication fails, and no new activity is launched. Bug: 159249069 Change-Id: I3a810cd7e6b97333f648c978e44242662342ec57 Merged-In: I289d67e5c7055ed60f7a96725c523d07cd047b23 --- .../biometrics/AuthenticationClient.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java index ef1b574c29a8..b4d74e0900f9 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java @@ -16,16 +16,22 @@ package com.android.server.biometrics; +import android.app.ActivityManager; +import android.app.ActivityTaskManager; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricsProtoEnums; import android.os.IBinder; import android.os.RemoteException; import android.security.KeyStore; +import android.util.EventLog; import android.util.Slog; import java.util.ArrayList; +import java.util.List; /** * A class to keep track of the authentication state for a given client. @@ -148,7 +154,54 @@ public abstract class AuthenticationClient extends ClientMonitor { + ", requireConfirmation: " + mRequireConfirmation + ", user: " + getTargetUserId()); + // Ensure authentication only succeeds if the client activity is on top or is keyguard. + boolean isBackgroundAuth = false; + if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString())) { + try { + final List tasks = + ActivityTaskManager.getService().getTasks(1); + if (tasks == null || tasks.isEmpty()) { + Slog.e(TAG, "No running tasks reported"); + isBackgroundAuth = true; + } else { + final ComponentName topActivity = tasks.get(0).topActivity; + if (topActivity == null) { + Slog.e(TAG, "Unable to get top activity"); + isBackgroundAuth = true; + } else { + final String topPackage = topActivity.getPackageName(); + if (!topPackage.contentEquals(getOwnerString())) { + Slog.e(TAG, "Background authentication detected, top: " + topPackage + + ", client: " + this); + isBackgroundAuth = true; + } + } + } + } catch (RemoteException e) { + Slog.e(TAG, "Unable to get running tasks", e); + isBackgroundAuth = true; + } + } + + // Fail authentication if we can't confirm the client activity is on top. + if (isBackgroundAuth) { + Slog.e(TAG, "Failing possible background authentication"); + authenticated = false; + + // SafetyNet logging for exploitation attempts of b/159249069. + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Attempted background authentication"); + } + if (authenticated) { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Successful background authentication!"); + } + mAlreadyDone = true; if (listener != null) { -- GitLab From 09c1b8ebf9e58cd402ec6a7ae9b1948cf83982d1 Mon Sep 17 00:00:00 2001 From: Curtis Belmonte Date: Thu, 1 Oct 2020 17:57:27 -0700 Subject: [PATCH 041/382] DO NOT MERGE Check fingerprint client against top activity in auth callback Due to a race condition with activity task stack broadcasts, it's currently possible for fingerprint authentication to succeed for a non-top activity. This means, for example, that a malicious overlay could be drawn in order to mislead the user about what they are authenticating for. This commit addresses the issue by adding a check to the biometric authentication client interface that ensures the authenticating activity is on top at the time of authentication. Otherwise, the pending authentication will fail, as if an incorrect biometric had been presented. Test: Follow steps from b/159249069: 1. Install com.pro100svitlo.fingerprintauthdemo from the Play store. 2. Install the PoC attack app from b/159249069. 3. Start the PoC attack app and press the "Launch PoC attack" button. 4. Use fingerprint to authenticate while the overlay is showing. Before: Authentication succeeds, and a new activity is launched. After: Authentication fails, and no new activity is launched. Bug: 159249069 Change-Id: Ie5a0f8c3e9b92d348a78678a6ed192d440c45ffc Merged-In: I289d67e5c7055ed60f7a96725c523d07cd047b23 Merged-In: I3a810cd7e6b97333f648c978e44242662342ec57 --- .../biometrics/AuthenticationClient.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java index edc8f15a9a03..8ca37b813b63 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java @@ -16,16 +16,22 @@ package com.android.server.biometrics; +import android.app.ActivityManager; +import android.app.ActivityTaskManager; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricsProtoEnums; import android.os.IBinder; import android.os.RemoteException; import android.security.KeyStore; +import android.util.EventLog; import android.util.Slog; import java.util.ArrayList; +import java.util.List; /** * A class to keep track of the authentication state for a given client. @@ -148,7 +154,54 @@ public abstract class AuthenticationClient extends ClientMonitor { + ", requireConfirmation: " + mRequireConfirmation + ", user: " + getTargetUserId()); + // Ensure authentication only succeeds if the client activity is on top or is keyguard. + boolean isBackgroundAuth = false; + if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString())) { + try { + final List tasks = + ActivityTaskManager.getService().getTasks(1); + if (tasks == null || tasks.isEmpty()) { + Slog.e(TAG, "No running tasks reported"); + isBackgroundAuth = true; + } else { + final ComponentName topActivity = tasks.get(0).topActivity; + if (topActivity == null) { + Slog.e(TAG, "Unable to get top activity"); + isBackgroundAuth = true; + } else { + final String topPackage = topActivity.getPackageName(); + if (!topPackage.contentEquals(getOwnerString())) { + Slog.e(TAG, "Background authentication detected, top: " + topPackage + + ", client: " + this); + isBackgroundAuth = true; + } + } + } + } catch (RemoteException e) { + Slog.e(TAG, "Unable to get running tasks", e); + isBackgroundAuth = true; + } + } + + // Fail authentication if we can't confirm the client activity is on top. + if (isBackgroundAuth) { + Slog.e(TAG, "Failing possible background authentication"); + authenticated = false; + + // SafetyNet logging for exploitation attempts of b/159249069. + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Attempted background authentication"); + } + if (authenticated) { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Successful background authentication!"); + } + mAlreadyDone = true; if (listener != null) { -- GitLab From 1ba154b14deb03d3db4dee6d4aca82f6377875b5 Mon Sep 17 00:00:00 2001 From: Curtis Belmonte Date: Thu, 1 Oct 2020 19:37:17 -0700 Subject: [PATCH 042/382] DO NOT MERGE Check fingerprint client against top activity in auth callback Due to a race condition with activity task stack broadcasts, it's currently possible for fingerprint authentication to succeed for a non-top activity. This means, for example, that a malicious overlay could be drawn in order to mislead the user about what they are authenticating for. This commit addresses the issue by adding a check to the biometric authentication client interface that ensures the authenticating activity is on top at the time of authentication. Otherwise, the pending authentication will fail, as if an incorrect biometric had been presented. Test: Follow steps from b/159249069: 1. Install com.pro100svitlo.fingerprintauthdemo from the Play store. 2. Install the PoC attack app from b/159249069. 3. Start the PoC attack app and press the "Launch PoC attack" button. 4. Use fingerprint to authenticate while the overlay is showing. Before: Authentication succeeds, and a new activity is launched. After: Authentication fails, and no new activity is launched. Bug: 159249069 Change-Id: I1241a12eafa0bdbac59a8ddd4cf6a0637d467b19 Merged-In: Ie5a0f8c3e9b92d348a78678a6ed192d440c45ffc Merged-In: I289d67e5c7055ed60f7a96725c523d07cd047b23 Merged-In: I3a810cd7e6b97333f648c978e44242662342ec57 --- .../biometrics/AuthenticationClient.java | 53 +++++++++++++++++++ .../com/android/server/biometrics/Utils.java | 16 ++++++ 2 files changed, 69 insertions(+) diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java index edc8f15a9a03..8ca37b813b63 100644 --- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java +++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java @@ -16,16 +16,22 @@ package com.android.server.biometrics; +import android.app.ActivityManager; +import android.app.ActivityTaskManager; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricsProtoEnums; import android.os.IBinder; import android.os.RemoteException; import android.security.KeyStore; +import android.util.EventLog; import android.util.Slog; import java.util.ArrayList; +import java.util.List; /** * A class to keep track of the authentication state for a given client. @@ -148,7 +154,54 @@ public abstract class AuthenticationClient extends ClientMonitor { + ", requireConfirmation: " + mRequireConfirmation + ", user: " + getTargetUserId()); + // Ensure authentication only succeeds if the client activity is on top or is keyguard. + boolean isBackgroundAuth = false; + if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString())) { + try { + final List tasks = + ActivityTaskManager.getService().getTasks(1); + if (tasks == null || tasks.isEmpty()) { + Slog.e(TAG, "No running tasks reported"); + isBackgroundAuth = true; + } else { + final ComponentName topActivity = tasks.get(0).topActivity; + if (topActivity == null) { + Slog.e(TAG, "Unable to get top activity"); + isBackgroundAuth = true; + } else { + final String topPackage = topActivity.getPackageName(); + if (!topPackage.contentEquals(getOwnerString())) { + Slog.e(TAG, "Background authentication detected, top: " + topPackage + + ", client: " + this); + isBackgroundAuth = true; + } + } + } + } catch (RemoteException e) { + Slog.e(TAG, "Unable to get running tasks", e); + isBackgroundAuth = true; + } + } + + // Fail authentication if we can't confirm the client activity is on top. + if (isBackgroundAuth) { + Slog.e(TAG, "Failing possible background authentication"); + authenticated = false; + + // SafetyNet logging for exploitation attempts of b/159249069. + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Attempted background authentication"); + } + if (authenticated) { + // SafetyNet logging for b/159249069 if constraint is violated. + if (isBackgroundAuth) { + final ApplicationInfo appInfo = getContext().getApplicationInfo(); + EventLog.writeEvent(0x534e4554, "159249069", appInfo != null ? appInfo.uid : -1, + "Successful background authentication!"); + } + mAlreadyDone = true; if (listener != null) { diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java index 14378da0a90b..bf84f762caee 100644 --- a/services/core/java/com/android/server/biometrics/Utils.java +++ b/services/core/java/com/android/server/biometrics/Utils.java @@ -16,9 +16,12 @@ package com.android.server.biometrics; +import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; import static android.hardware.biometrics.BiometricManager.Authenticators; +import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricPrompt; @@ -29,6 +32,8 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.Slog; +import com.android.internal.R; + public class Utils { public static boolean isDebugEnabled(Context context, int targetUserId) { if (targetUserId == UserHandle.USER_NULL) { @@ -256,4 +261,15 @@ public class Utils { throw new IllegalArgumentException("Unsupported dismissal reason: " + reason); } } + + static boolean isKeyguard(Context context, String clientPackage) { + final boolean hasPermission = context.checkCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL) + == PackageManager.PERMISSION_GRANTED; + + final ComponentName keyguardComponent = ComponentName.unflattenFromString( + context.getResources().getString(R.string.config_keyguardComponent)); + final String keyguardPackage = keyguardComponent != null + ? keyguardComponent.getPackageName() : null; + return hasPermission && keyguardPackage != null && keyguardPackage.equals(clientPackage); + } } -- GitLab From 3b6145587facef65ea37d2494731eb712d7dd431 Mon Sep 17 00:00:00 2001 From: Sahana Rao Date: Wed, 30 Sep 2020 08:49:53 +0000 Subject: [PATCH 043/382] Flip ENABLE_DYNAMIC_PERMISSIONS, attempt #7. Ib0021d3fd34294bb7497c8827e7ee99d4ac64d73 fixes the app compatibility issue(b/159995598). Bug: 115619667 Test: atest ExternalStorageHostTest#testGrantUriPermission Test: atest ExternalStorageHostTest#testGrantUriPermission29 Merged-In: I413ccf8c31de6525a737c8336a904456fdbeb9e1 Change-Id: I413ccf8c31de6525a737c8336a904456fdbeb9e1 (cherry picked from commit 8bf78650b2bb895812f10d52a2a9654a822d652c) --- .../java/com/android/server/uri/UriGrantsManagerService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java index 8eefd8fa4a91..a106dc682208 100644 --- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java +++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java @@ -115,7 +115,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub { private static final String TAG = "UriGrantsManagerService"; // Maximum number of persisted Uri grants a package is allowed private static final int MAX_PERSISTED_URI_GRANTS = 512; - private static final boolean ENABLE_DYNAMIC_PERMISSIONS = false; + private static final boolean ENABLE_DYNAMIC_PERMISSIONS = true; private final Object mLock = new Object(); private final H mH; -- GitLab From 7f03b9f0cf775ec3326b628cbfa48e428fb0032c Mon Sep 17 00:00:00 2001 From: Alison Cichowlas Date: Fri, 25 Sep 2020 21:16:22 -0400 Subject: [PATCH 044/382] When logging ranking positions, use the number of displayed targets in calculating offset rather than the total number available. Test: ChooserActivityTest; log inspection Bug: 169344682 Change-Id: I40c841bf0f3e1cf90b0e4998bde1c9e8009c09c5 (cherry picked from commit b17dbd20c35fc12088f32d3626e50f485c92c36b) --- core/java/com/android/internal/app/ChooserActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 76c2f2e4c60b..460561b5091e 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -1761,7 +1761,7 @@ public class ChooserActivity extends ResolverActivity implements case ChooserListAdapter.TARGET_CALLER: case ChooserListAdapter.TARGET_STANDARD: cat = MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET; - value -= currentListAdapter.getSelectableServiceTargetCount(); + value -= currentListAdapter.getSurfacedTargetInfo().size(); numCallerProvided = currentListAdapter.getCallerTargetCount(); getChooserActivityLogger().logShareTargetSelected( SELECTION_TYPE_APP, -- GitLab From 2bf768e2cae9bf0b80b163d786602fb71354a025 Mon Sep 17 00:00:00 2001 From: Hai Zhang Date: Mon, 15 Jun 2020 18:18:33 -0700 Subject: [PATCH 045/382] Revoke install permissions when the permission defining app is uninstalled. Bug: 155648771 Test: atest RemovePermissionTest Change-Id: I4a5ecd9bede6f11d5023b3e8345b61d5b04e566f Merged-In: I4a5ecd9bede6f11d5023b3e8345b61d5b04e566f --- .../pm/permission/PermissionManagerService.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 9963cf7e212d..bc7554c54eb0 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -4224,6 +4224,20 @@ public class PermissionManagerService extends IPermissionManager.Stub { revokePermissionFromPackageForUser(p.getPackageName(), bp.getName(), true, userId, callback)); } + } else { + mPackageManagerInt.forEachPackage(p -> { + PackageSetting ps = mPackageManagerInt.getPackageSetting( + p.getPackageName()); + if (ps == null) { + return; + } + PermissionsState permissionsState = ps.getPermissionsState(); + if (permissionsState.getInstallPermissionState(bp.getName()) != null) { + permissionsState.revokeInstallPermission(bp); + permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL, + MASK_PERMISSION_FLAGS_ALL, 0); + } + }); } it.remove(); } -- GitLab From 719c9c520603e1d84d31864810d2237ae4d429ca Mon Sep 17 00:00:00 2001 From: Hai Zhang Date: Mon, 15 Jun 2020 18:18:33 -0700 Subject: [PATCH 046/382] DO NOT MERGE Revoke install permissions when the permission defining app is uninstalled. Bug: 155648771 Test: atest RemovePermissionTest Change-Id: I4a5ecd9bede6f11d5023b3e8345b61d5b04e566f --- .../pm/permission/PermissionManagerService.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index e35d25676de5..b3bee6f68b78 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -2690,6 +2690,20 @@ public class PermissionManagerService { } }); } + } else { + mPackageManagerInt.forEachPackage(p -> { + PackageSetting ps = (PackageSetting) p.mExtras; + if (ps == null) { + return; + } + PermissionsState permissionsState = ps.getPermissionsState(); + if (permissionsState.getInstallPermissionState(bp.getName()) + != null) { + permissionsState.revokeInstallPermission(bp); + permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL, + MASK_PERMISSION_FLAGS_ALL, 0); + } + }); } flags |= UPDATE_PERMISSIONS_ALL; it.remove(); -- GitLab From 334190f26e7bc1660ac0bbf9645b8e434a147062 Mon Sep 17 00:00:00 2001 From: Linus Tufvesson Date: Wed, 7 Oct 2020 16:43:30 +0100 Subject: [PATCH 047/382] Update javadoc for setLaunchDisplayId .. to match behavior post I1f9662c2bd14b34e00fbc8ebb926538f0329c37a Bug: 167593637 Test: Javadoc change only. Change-Id: I4cb9fe4a5ae74b1474f9da39b6aeb3a374f8cf12 --- core/java/android/app/ActivityOptions.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 80d2e6c60f69..4aedfeefb72b 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -1275,10 +1275,10 @@ public class ActivityOptions { } /** - * Sets the id of the display where activity should be launched. - * An app can launch activities on public displays or private displays that are owned by the app - * or where an app already has activities. Otherwise, trying to launch on a private display - * or providing an invalid display id will result in an exception. + * Sets the id of the display where the activity should be launched. + * An app can launch activities on public displays or displays where the app already has + * activities. Otherwise, trying to launch on a private display or providing an invalid display + * id will result in an exception. *

* Setting launch display id will be ignored on devices that don't have * {@link android.content.pm.PackageManager#FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS}. -- GitLab From 794cce7bf806d63ea785cbcc0c59e4861a45ed21 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 7 Oct 2020 10:57:48 -0700 Subject: [PATCH 048/382] IdleMaint: run IdleMaint if battery is charging We've got reports where this ate battery too much during 3 to 4 AM. Bug: 170441569 Bug: 168083554 Signed-off-by: Jaegeuk Kim Change-Id: I8f41a8922034d3d625b90f70a523155d7f1c51e4 Merged-In: I8f41a8922034d3d625b90f70a523155d7f1c51e4 --- services/core/java/com/android/server/MountServiceIdler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/services/core/java/com/android/server/MountServiceIdler.java b/services/core/java/com/android/server/MountServiceIdler.java index 6bc1a570b7c0..0f4c94bc8d4f 100644 --- a/services/core/java/com/android/server/MountServiceIdler.java +++ b/services/core/java/com/android/server/MountServiceIdler.java @@ -113,6 +113,7 @@ public class MountServiceIdler extends JobService { JobInfo.Builder builder = new JobInfo.Builder(MOUNT_JOB_ID, sIdleService); builder.setRequiresDeviceIdle(true); builder.setRequiresBatteryNotLow(true); + builder.setRequiresCharging(true); builder.setMinimumLatency(nextScheduleTime); tm.schedule(builder.build()); } -- GitLab From 734c374976d5553744367fbc82db8c543ee00729 Mon Sep 17 00:00:00 2001 From: Jeff DeCew Date: Mon, 28 Sep 2020 13:14:28 -0400 Subject: [PATCH 049/382] Media player attempts to dismiss notifications when players removed. NOTE: this is only a partial fix. See bug for discussion. (Cherry-picked from 725d67d88940fa03cfaac9f3df8b472a1a68f77d) Bug: 169271494 Test: manual Change-Id: I64db4cc618a812063c18a40ea4465aa4c520a3be Merged-In: I64db4cc618a812063c18a40ea4465aa4c520a3be --- .../statusbar/NotificationMediaManager.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index 8cd82cc77530..38e1de3cada0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -40,6 +40,7 @@ import android.os.Trace; import android.os.UserHandle; import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; +import android.service.notification.NotificationListenerService; import android.util.ArraySet; import android.util.Log; import android.view.View; @@ -52,6 +53,7 @@ import com.android.systemui.Dumpable; import com.android.systemui.Interpolators; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.media.MediaData; import com.android.systemui.media.MediaDataManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.dagger.StatusBarModule; @@ -250,6 +252,24 @@ public class NotificationMediaManager implements Dumpable { } }); + mMediaDataManager.addListener(new MediaDataManager.Listener() { + @Override + public void onMediaDataLoaded(@NonNull String key, + @Nullable String oldKey, @NonNull MediaData data) { + } + + @Override + public void onMediaDataRemoved(@NonNull String key) { + NotificationEntry entry = mEntryManager.getPendingOrActiveNotif(key); + if (entry != null) { + // TODO(b/160713608): "removing" this notification won't happen and + // won't send the 'deleteIntent' if the notification is ongoing. + mEntryManager.performRemoveNotification(entry.getSbn(), + NotificationListenerService.REASON_CANCEL); + } + } + }); + mShowCompactMediaSeekbar = "true".equals( DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED)); -- GitLab From 24c3abf63b4371e28abb41dc69998bba4c9c9502 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sat, 10 Oct 2020 07:05:01 -0700 Subject: [PATCH 050/382] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: If22a000ecaa8159c2f3c592ea7eec39fa2f0b79e --- core/res/res/values-az/strings.xml | 16 ++++++++-------- core/res/res/values-be/strings.xml | 14 +++++++------- core/res/res/values-en-rCA/strings.xml | 6 +++--- core/res/res/values-es/strings.xml | 2 +- core/res/res/values-fa/strings.xml | 8 ++++---- core/res/res/values-fi/strings.xml | 4 ++-- core/res/res/values-fr/strings.xml | 2 +- core/res/res/values-ky/strings.xml | 2 +- core/res/res/values-mk/strings.xml | 4 ++-- core/res/res/values-ml/strings.xml | 2 +- core/res/res/values-mn/strings.xml | 10 +++++----- core/res/res/values-my/strings.xml | 2 +- core/res/res/values-nb/strings.xml | 2 +- core/res/res/values-ne/strings.xml | 8 ++++---- core/res/res/values-ru/strings.xml | 2 +- core/res/res/values-uk/strings.xml | 4 ++-- 16 files changed, 44 insertions(+), 44 deletions(-) diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index 031690d548dc..1d5d6d87b2c5 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -701,7 +701,7 @@ "Bəzi ekran kilidi funksiyalarını deaktiv edin" "Bəzi ekran funksiyaları istifadəsinin qarşısını alın." - "Əsas səhifə" + "Ev" "Mobil" "İş" "İş Faksı" @@ -711,19 +711,19 @@ "Şəxsi" - "Ana səhifə" + "Ev" "İş" "Digər" "Fərdi" - "Əsas səhifə" + "Ev" "İş" "Digər" "Düzənləyin" - "Əsas səhifə" + "Ev" "İş" "Digər" "Fərdi" @@ -769,16 +769,16 @@ "İldönümü" "Digər" "Fərdi" - "Əsas səhifə" + "Şəxsi" "İş" "Digər" "Mobil" "Fərdi" - "Əsas səhifə" + "Ev" "İş" "Digər" "Fərdi" - "Ana səhifə" + "Ev" "İş" "Digər" "Şəxsi" @@ -810,7 +810,7 @@ "Bacı" "Həyat yoldaşı" "Fərdi" - "Əsas səhifə" + "Ev" "İş" "Digər" "Bu kontakta baxmaq üçün heç bir tətbiq tapılmadı." diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index df7fca0bc6e1..6fbdd4626b94 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -98,9 +98,9 @@ "Wi-Fi-тэлефанія" "Статус SIM-карты" "Стан SIM-карты з высокім прыярытэтам" - "Аднарангавая прылада запытала рэжым TTY FULL" - "Аднарангавая прылада запытала рэжым TTY НСО" - "Аднарангавая прылада запытала рэжым TTY VCO" + "Аднарангавая прылада запытала рэжым поўнафункцыянальнага TTY" + "Аднарангавая прылада запытала рэжым TTY з магчымасцю чуць суразмоўніка" + "Аднарангавая прылада запытала рэжым TTY з магчымасцю чуць суразмоўніка" "Аднарангавая прылада запытала рэжым TTY OFF" "Голас" "Дадзеныя" @@ -967,7 +967,7 @@ "дадаць галасавое паведамленне" "Дазваляе прыкладанням дадаваць паведамленні ў вашу скрыню галасавой пошты." "змяніць дазволы геапазіцыянавання для браўзэра" - "Дазваляе прыкладанням змяняць дазволы геалакацыі браўзэра. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб дазваляць адпраўку інфармацыі аб месцазнаходжанні выпадковым вэб-сайтам." + "Дазваляе праграме змяняць дазволы геалакацыі браўзера. Шкодныя праграмы могуць выкарыстоўваць гэта, каб адпраўляць даныя аб месцазнаходжанні на любыя вэб-сайты." "Вы хочаце, каб браўзэр запомніў гэты пароль?" "Не зараз" "Запомніць" @@ -1342,8 +1342,8 @@ "Рэжым USB-мадэма" "MIDI праз USB" "USB-прылада падключана" - "Дакраніцеся, каб атрымаць іншыя параметры." - "Зарадка падключанай прылады. Націсніце, каб убачыць іншыя параметры." + "Дакраніцеся, каб убачыць іншыя параметры." + "Падключаная прылада зараджаецца. Дакраніцеся, каб убачыць іншыя параметры." "Выяўлены аксесуар аналагавага аўдыя" "Далучаная прылада не сумяшчальная з гэтым тэлефонам. Націсніце, каб даведацца больш." "Адладка па USB падключана" @@ -1542,7 +1542,7 @@ "Не атрымалася запусціць %s" "Апублікаваць з дапамогай" "Адправiць з дапамогай прыкладання %s" - "Ручка для перасоўвання. Націсніце і ўтрымлівайце." + "Маркер для перасоўвання. Дакраніцеся і ўтрымлівайце." "Прагартайце, каб разблакаваць." "Перайсці да пачатковай старонкі" "Перайсці ўверх" diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index f303f3ffbcce..d6faf46ee74a 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -1120,8 +1120,8 @@ "Loading…" "ON" "OFF" - "ticked" - "not ticked" + "checked" + "not checked" "Complete action using" "Complete action using %1$s" "Complete action" @@ -2023,7 +2023,7 @@ "%1$s spreadsheet" "Presentation" "%1$s presentation" - "Bluetooth will stay on during aeroplane mode" + "Bluetooth will stay on in Airplane mode" "Loading" %s + %d files diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index bc703683184e..36dda0637bf7 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -325,7 +325,7 @@ "Controla el posicionamiento y el nivel de zoom de la pantalla." "Realizar gestos" "Puedes tocar y pellizcar la pantalla, deslizar el dedo y hacer otros gestos." - "Gestos de huellas digitales" + "Gestos de huella digital" "Puede capturar los gestos realizados en el sensor de huellas digitales del dispositivo." "Hacer captura" "Puede hacer capturas de la pantalla." diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index bbdfc62dbcc1..068551b45d68 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -1654,11 +1654,11 @@ "کلیدهای میزان صدا پایین نگه داشته شد. %1$s خاموش شد." "برای استفاده از %1$s، هر دو کلید صدا را فشار دهید و سه ثانیه نگه دارید" "ویژگی را انتخاب کنید که هنگام ضربه زدن روی دکمه دسترس‌پذیری استفاده می‌شود:" - "ویژگی را برای استفاده با اشاره دسترس‌پذیری انتخاب کنید (با دو انگشت صفحه را از پایین تند به بالا بکشید):" - "ویزگی را برای استفاده با اشاره دسترس‌پذیری انتخاب کنید (با سه انگشت صفحه را از پایین تند به بالا بکشید):" + "ویژگی را برای استفاده با اشاره دسترس‌پذیری انتخاب کنید (با دو انگشت صفحه را از پایین تند به‌بالا بکشید):" + "ویزگی را برای استفاده با اشاره دسترس‌پذیری انتخاب کنید (با سه انگشت صفحه را از پایین تند به‌بالا بکشید):" "برای جابه‌جایی بین ویژگی‌ها، دکمه دسترس‌پذیری را لمس کنید و نگه دارید." - "برای جابه‌جایی بین ویژگی‌ها، با دو انگشت صفحه را تند به بالا بکشید و نگه دارید." - "برای جابه‌جایی بین ویژگی‌ها، با سه انگشت صفحه را تند به بالا بکشید و نگه دارید." + "برای جابه‌جایی بین ویژگی‌ها، با دو انگشت صفحه را تند به‌بالا بکشید و نگه دارید." + "برای جابه‌جایی بین ویژگی‌ها، با سه انگشت صفحه را تند به‌بالا بکشید و نگه دارید." "درشت‌نمایی" "کاربر کنونی %1$s." "در حالت تغییر به %1$s…" diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 78f8ea4cb6f7..527d5a6a8087 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -302,7 +302,7 @@ "Tekstiviestit" "lähettää ja tarkastella tekstiviestejä" "Tiedostot ja media" - "käyttää laitteellesi tallennettuja valokuvia, mediatiedostoja ja muita tiedostoja" + "käyttää laitteellesi tallennettuja kuvia, mediatiedostoja ja muita tiedostoja" "Mikrofoni" "tallentaa ääntä" "Liikkuminen" @@ -1914,7 +1914,7 @@ "Pelit" "Musiikki ja ääni" "Elokuvat ja videot" - "Kuvat ja valokuvat" + "Kuvat ja kuvat" "Some ja viestintä" "Uutiset ja lehdet" "Kartat ja navigointi" diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index ba67e0b377fe..29e550c71438 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -325,7 +325,7 @@ "Contrôle le niveau de zoom et le positionnement de l\'écran." "Effectuer des gestes" "Permet d\'appuyer sur l\'écran, de le balayer, de le pincer et d\'effectuer d\'autres gestes." - "Gestes avec l\'empreinte digitale" + "Gestes d\'empreinte digitale" "Peut enregistrer des gestes effectués sur le lecteur d\'empreinte digitale de l\'appareil." "Prendre une capture d\'écran" "Peut prendre des captures d\'écran." diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 1517c17d9615..57e1789d2bc5 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -1199,7 +1199,7 @@ "%2$d ичинен %1$d колдонмо ыңгайлаштырылууда." "%1$s даярдалууда." "Колдонмолорду иштетип баштоо" - "Жүктөө аякталууда." + "Жүктөлүүдө" "%1$s иштеп жатат" "Оюнга кайтуу үчүн таптаңыз" "Оюн тандоо" diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 063bbbf0f066..f4ecaf898c27 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -985,7 +985,7 @@ "Пребарај" "Пребарај барање" "Исчисти барање" - "Поднеси барање" + "Испрати барање" "Гласовно пребарување" "Овозможи „Истражувај со допир“?" "%1$s сака да овозможи „Истражувај со допир“. Кога е вклучено „Истражувај со допир“, може да се слушнат или да се видат описи на она што е под вашиот прст или да се прават движења за комуницирање со таблетот." @@ -1436,7 +1436,7 @@ "Избери датотека" "Не е избрана датотека" "Ресетирај" - "Поднеси" + "Испрати" "Апликацијата за возење работи" "Допрете за да излезете од апликацијата за возење." "Назад" diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 94ac5ca66e34..d30861f22b75 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -325,7 +325,7 @@ "ഡിസ്പ്ലേയുടെ സൂം നിലയും പൊസിഷനിംഗും നിയന്ത്രിക്കുക." "ജെസ്‌റ്ററുകൾ നിർവഹിക്കുക" "ടാപ്പുചെയ്യാനോ സ്വൈപ്പുചെയ്യാനോ പിഞ്ചുചെയ്യാനോ മറ്റ് ജെസ്‌റ്ററുകൾ നിർവഹിക്കാനോ കഴിയും." - "ഫിംഗർപ്രിന്റ് ജെസ്‌റ്ററുകൾ" + "ഫിംഗർപ്രിന്റ് ജെസ്‌ച്ചറുകൾ" "ഉപകരണത്തിന്റെ ഫിംഗർപ്രിന്റ് സെൻസറിൽ ചെയ്‌ത ജെസ്‌റ്ററുകൾ ക്യാപ്‌ചർ ചെയ്യാനാകും." "സ്ക്രീന്‍ഷോട്ട് എടുക്കുക" "ഡിസ്‌പ്ലേയുടെ സ്‌ക്രീൻഷോട്ട് എടുക്കാൻ കഴിയും." diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 3833605fa78b..c306f8d10963 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -950,18 +950,18 @@ "Мөргөлч" "Хэсэг" "Эмират" - "өөрийн Вэб хавчуурга болон түүхийг унших" + "өөрийн Веб хавчуурга болон түүхийг унших" "Апп нь Хөтчийн зочилж байсан бүх URL-н түүх болон Хөтчийн бүх хавчуургыг унших боломжтой. Анхаар: Энэ зөвшөөрөл нь гуравдагч талын хөтөч эсвэл вебээр хөтөчлөх чадавхтай аппликейшнүүдэд ашиглагдахгүй байх боломжтой." - "вэб хавчуурга болон түүхийг бичих" + "веб хавчуурга болон түүхийг бичих" "Апп нь таны таблет дээр хадгалагдсан Хөтчийн түүх эсвэл хавчуургыг өөрчлөх боломжтой. Энэ нь апп-д Хөтчийн датаг арилгах эсвэл өөрчлөх боломжийг олгоно. Анхаар: Энэ зөвшөөрөл нь гуравдагч талын хөтөч эсвэл вебээр хөтөчлөх чадвартай аппликейшнд ажиллахгүй байх боломжтой." - "Аппад таны Android TV төхөөрөмжид хадгалсан Хөтчийн түүх эсвэл хавчуургыг өөрчлөхийг зөвшөөрнө. Энэ нь аппад Хөтчийн өгөгдлийг устгах эсвэл өөрчлөхийг зөвшөөрч болзошгүй. Санамж: энэ зөвшөөрөл нь гуравдагч талын хөтөч эсвэл вэб хөтчийн чадамжтай бусад аппад хэрэгжихгүй байж болзошгүй." + "Аппад таны Android TV төхөөрөмжид хадгалсан Хөтчийн түүх эсвэл хавчуургыг өөрчлөхийг зөвшөөрнө. Энэ нь аппад Хөтчийн өгөгдлийг устгах эсвэл өөрчлөхийг зөвшөөрч болзошгүй. Санамж: энэ зөвшөөрөл нь гуравдагч талын хөтөч эсвэл веб хөтчийн чадамжтай бусад аппад хэрэгжихгүй байж болзошгүй." "Апп нь таны утсан дээр хадгалагдсан Хөтчийн түүх эсвэл хавчуургыг өөрчлөх боломжтой. Энэ нь апп-д Хөтчийн датаг арилгах эсвэл өөрчлөх боломжийг олгоно. Анхаар: Энэ зөвшөөрөл нь гуравдагч талын хөтөч эсвэл вебээр хөтөчлөх чадвартай аппликейшнд ажиллахгүй байх боломжтой." "сэрүүлэг тохируулах" "Апп нь суулгагдсан сэрүүлэгний апп дээр сэрүүлэг тохируулах боломжтой. Зарим сэрүүлэгний апп нь энэ функцийг дэмжихгүй байж болзошгүй." "дуут шуудан нэмэх" "Таны дуут шуудангийн ирсэн мэйлд зурвас нэмэхийг апп-д зөвшөөрөх." "Хөтчийн геобайршлын зөвшөөрлийг өөрчлөх" - "Апп нь Хөтчийн гео байршлын зөвшөөрлийг өөрчлөх боломжтой. Хортой апп нь энийг ашиглан дурын вэб хуудасруу байршлын мэдээллийг илгээх боломжтой." + "Апп нь Хөтчийн гео байршлын зөвшөөрлийг өөрчлөх боломжтой. Хортой апп нь энийг ашиглан дурын веб хуудасруу байршлын мэдээллийг илгээх боломжтой." "Та хөтчид энэ нууц үгийг сануулах уу?" "Одоо биш" "Санах" @@ -1452,7 +1452,7 @@ "Хуваалцсан хадгалах санг устгаж байна…" "Хуваалцах" "Олох" - "Вэб хайлт" + "Веб хайлт" "Дараагийнхыг хайх" "Өмнөхөөс олох" "%s-н байршлын хүсэлт" diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index fd75192aa31f..9ba7fef63773 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -1093,7 +1093,7 @@ "ဖြတ်ရန်" "ကူးရန်" "ကလစ်ဘုတ်သို့ မိတ္တူကူးခြင်း မအောင်မြင်ပါ" - "Paste" + "ကူးထည့်ရန်" "စာသားအတိုင်း ကူးထည့်ပါ" "အစားထိုခြင်း" "ဖျက်ရန်" diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 1633fc5a8d07..292c51ac07db 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -1091,7 +1091,7 @@ "%1$d:%2$02d:%3$02d" "Merk alt" "Klipp ut" - "Kopier" + "Kopiér" "Kunne ikke kopiere til utklippstavlen" "Lim inn" "Lim inn som ren tekst" diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 520f97321e8c..7e944f44480d 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -1473,7 +1473,7 @@ "खाता थप्नुहोस्" "बढाउनुहोस्" "घटाउनुहोस्" - "%s छोइराख्नुहोस्।" + "%s टच एण्ड होल्ड गर्नुहोस्।" "बढाउन माथि र घटाउन तल सार्नुहोस्।" "मिनेट बढाउनुहोस्" "मिनेट घटाउनुहोस्" @@ -1656,9 +1656,9 @@ "तपाईंले पहुँचको बटन ट्याप गर्दा प्रयोग गर्न चाहनुभएको सुविधा छनौट गर्नुहोस्:" "तपाईंले पहुँचको इसारामार्फत प्रयोग गर्न चाहनुभएको सुविधा छनौट गर्नुहोस् (दुईवटा औँलाले स्क्रिनको फेदबाट माथितिर स्वाइप गर्नुहोस्):" "तपाईंले पहुँचको इसारामार्फत प्रयोग गर्न चाहनुभएको सुविधा छनौट गर्नुहोस् (तीनवटा औँलाले स्क्रिनको फेदबाट माथितिर स्वाइप गर्नुहोस्):" - "एउटा सुविधाबाट अर्को सुविधामा जान पहुँच बटन छोइराख्नुहोस्।" - "एउटा सुविधाबाट अर्को सुविधामा जान दुईवटा औँलाले माथितिर स्वाइप गरी स्क्रिनमा छोइराख्नुहोस्।" - "एउटा सुविधाबाट अर्को सुविधामा जान तीनवटा औँलाले माथितिर स्वाइप गरी स्क्रिनमा छोइराख्नुहोस्।" + "एउटा सुविधाबाट अर्को सुविधामा जान पहुँच बटन टच एण्ड होल्ड गर्नुहोस्।" + "एउटा सुविधाबाट अर्को सुविधामा जान दुईवटा औँलाले माथितिर स्वाइप गरी स्क्रिनमा टच एण्ड होल्ड गर्नुहोस्।" + "एउटा सुविधाबाट अर्को सुविधामा जान तीनवटा औँलाले माथितिर स्वाइप गरी स्क्रिनमा टच एण्ड होल्ड गर्नुहोस्।" "म्याग्निफिकेसन" "अहिलेको प्रयोगकर्ता %1$s।" "%1$s मा स्विच गर्दै..." diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index f75a637cd3d8..a547e72c5201 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -1312,7 +1312,7 @@ "Отмена" "Запомнить выбор" "Это можно изменить позже в разделе настроек \"Приложения\"." - "Всегда разрешать" + "Разрешать всегда" "Не разрешать" "SIM-карта удалена" "Пока вы не вставите действующую SIM-карту, мобильная сеть будет недоступна." diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 825a8a83bb01..807fff0cf7bd 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1130,7 +1130,7 @@ "%1$02d:%2$02d" "%1$d:%2$02d:%3$02d" "Вибрати все" - "Виріз." + "Вирізати" "Копіювати" "Не вдалося скопіювати в буфер обміну" "Вставити" @@ -1856,7 +1856,7 @@ Протягом %1$d хв (до %2$s) - %1$d годину (до %2$s) + %1$d година (до %2$s) %1$d години (до %2$s) %1$d годин (до %2$s) %1$d години (до %2$s) -- GitLab From 4532bdf3a76a783e010fa71440742317842ddb66 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sat, 10 Oct 2020 15:23:42 -0700 Subject: [PATCH 051/382] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: Ibef3abb6fef8118e9f2972337ad5f5173130988c --- packages/SoundPicker/res/values-uz/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/SoundPicker/res/values-uz/strings.xml b/packages/SoundPicker/res/values-uz/strings.xml index 9018e660d8fc..a617733737e7 100644 --- a/packages/SoundPicker/res/values-uz/strings.xml +++ b/packages/SoundPicker/res/values-uz/strings.xml @@ -21,7 +21,7 @@ "Standart signal tovushi" "Rington qo‘shish" "Signal qo‘shish" - "Bildirishnoma qo‘shish" + "Bildirishnoma kiritish" "O‘chirish" "Maxsus rington qo‘shib bo‘lmadi" "Maxsus ringtonni o‘chirib bo‘lmadi" -- GitLab From 71b921af5ade3e815dab0a50e98c3190851583cf Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sat, 10 Oct 2020 16:19:30 -0700 Subject: [PATCH 052/382] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: I1d9f3f3a47a85e480c68f3a241b4dcf30265bf61 --- packages/SystemUI/res/values-az/strings.xml | 2 +- packages/SystemUI/res/values-bs/strings.xml | 2 +- packages/SystemUI/res/values-fa/strings.xml | 6 ++--- packages/SystemUI/res/values-iw/strings.xml | 2 +- packages/SystemUI/res/values-mn/strings.xml | 28 ++++++++++----------- packages/SystemUI/res/values-ne/strings.xml | 16 ++++++------ 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index acd6ddbdc482..449956ced021 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -789,7 +789,7 @@ "Yuxarı Səhifə" "Aşağı Səhifə" "Silin" - "Əsas səhifə" + "Home" "Son" "Daxil edin" "Nömrələr" diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index f70d3fde1048..9a3d1388123b 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -724,7 +724,7 @@ "Nema nedavnih oblačića" "Nedavni i odbačeni oblačići će se pojaviti ovdje" "Ta obavještenja se ne mogu izmijeniti." - "Ovdje nije moguće konfigurirati ovu grupu obavještenja" + "Ovu grupu obavještenja nije moguće konfigurirati ovdje" "Obavještenje preko proksi servera" "Sva obavještenja aplikacije %1$s" "Prikaži više" diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 0e7345d0db34..feb2e4da96e6 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -431,7 +431,7 @@ "شروع" "توقف" "دستگاه" - "برای تغییر برنامه‌ها،‌ تند به بالا بکشید" + "برای تغییر برنامه‌ها،‌ تند به‌بالا بکشید" "برای جابه‌جایی سریع میان برنامه‌ها، به چپ بکشید" "تغییر وضعیت نمای کلی" "شارژ کامل شد" @@ -450,8 +450,8 @@ "+%d" "اعلان‌های کمتر فوری در زیر" "دوباره ضربه بزنید تا باز شود" - "برای باز کردن، انگشتتان را تند به بالا بکشید" - "برای امتحان مجدد، انگشتتان را تند به بالا بکشید" + "برای باز کردن، انگشتتان را تند به‌بالا بکشید" + "برای امتحان مجدد، انگشتتان را تند به‌بالا بکشید" "این دستگاه به سازمان شما تعلق دارد" "این دستگاه به %s تعلق دارد" "انگشتتان را از نماد تلفن تند بکشید" diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index fc586355b0c1..87233dc5f44e 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -961,7 +961,7 @@ "הודעות כלליות" "אחסון" "טיפים" - "אפליקציות אינסטנט" + "אפליקציות ללא התקנה" "%1$s פועלת" "האפליקציה נפתחת בלי התקנה." "האפליקציה נפתחת בלי התקנה. אפשר להקיש כדי לקבל מידע נוסף." diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 0a0fbd7a8081..f3bd44258740 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -549,29 +549,29 @@ "Таны байгууллага таны ажлын профайлд сертификатын зөвшөөрөл суулгасан байна. Таны аюулгүй сүлжээний ачааллыг өөрчлөх эсвэл хянах боломжтой." "Сертификатын зөвшөөрлийг энэ төхөөрөмжид суулгасан байна. Таны аюулгүй сүлжээний ачааллыг өөрчлөх эсвэл хянах боломжтой." "Таны админ төхөөрөмжийн ачааллыг хянадаг сүлжээний логийг асаасан байна." - "Та имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой %1$s-д холбогдсон байна." - "Та имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой %1$s, %2$s-д холбогдсон байна." - "Таны ажлын профайл %1$s-д холбогдсон байна. Энэ нь таны имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой." - "Таны хувийн профайлыг имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой %1$s-д холбосон байна." + "Та имэйл, апп, веб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой %1$s-д холбогдсон байна." + "Та имэйл, апп, веб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой %1$s, %2$s-д холбогдсон байна." + "Таны ажлын профайл %1$s-д холбогдсон байна. Энэ нь таны имэйл, апп, веб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой." + "Таны хувийн профайлыг имэйл, апп, веб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой %1$s-д холбосон байна." "Таны төхөөрөмжийг %1$s удирддаг." "%1$s таны төхөөрөмжийг удирдахын тулд %2$s-г ашигладаг." "Таны админ тохиргоо, байгууллагын хандалт, апп, төхөөрөмжтэй холбоотой өгөгдөл болон таны төхөөрөмжийн байршлын мэдээллийг хянах, удирдах боломжтой." " " "Дэлгэрэнгүй үзэх" - "Таны имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой %1$s-д холбогдсон байна." + "Таны имэйл, апп, веб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой %1$s-д холбогдсон байна." " " "VPN тохиргоог нээх" " " "Итгэмжлэгдсэн мандат үнэмлэхийг нээх" "Таны админ төхөөрөмжийн ачааллыг хянадаг сүлжээний логийг асаасан байна.\n\nДэлгэрэнгүй мэдээлэл авах бол админтайгаа холбогдоно уу." - "Та апп-д VPN холболт хийхийг зөвшөөрсөн байна.\n\nЭнэхүү апп нь таны имэйл, апп, вэбсайт зэрэг төхөөрөмж болон сүлжээний үйл ажиллагааг хянах боломжтой." - "%1$s таны ажлын профайлыг удирддаг.\n\nТаны админ имэйл, апп болон вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээлэл авах бол админтайгаа холбогдоно уу.\n\nТа сүлжээний үйл ажиллагааг хянах боломжтой VPN-д холбогдсон байна." + "Та апп-д VPN холболт хийхийг зөвшөөрсөн байна.\n\nЭнэхүү апп нь таны имэйл, апп, вебсайт зэрэг төхөөрөмж болон сүлжээний үйл ажиллагааг хянах боломжтой." + "%1$s таны ажлын профайлыг удирддаг.\n\nТаны админ имэйл, апп болон веб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой.\n\nДэлгэрэнгүй мэдээлэл авах бол админтайгаа холбогдоно уу.\n\nТа сүлжээний үйл ажиллагааг хянах боломжтой VPN-д холбогдсон байна." "VPN" - "Та %1$s-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вэбсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой." - "Та %1$s-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вэбсайт зэрэг сүлжээний хувийн үйл ажиллагааг хянах боломжтой." - "Та имэйл, апп, вэб хуудас зэрэг хувийн сүлжээнийхээ үйл ажиллагааг хянах боломжтой %1$s-д холбогдсон байна." - "Таны ажлын профайлыг %1$s удирддаг. Энэ нь таны имэйл, апп, вэб хуудас зэрэг ажлын сүлжээний үйл ажиллагааг хянах боломжтой %2$s-д холбогдсон. \n\nДэлгэрэнгүй мэдээллийг авахын тулд админтай холбогдоно уу." - "Таны ажлын профайлыг %1$s удирддаг. Энэ нь таны имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой %2$s-тай холбогдсон. \n\nМөн таны сүлжээний хувийн үйл ажиллагааг хянах боломжтой %3$s-д холбогдсон байна." + "Та %1$s-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний үйл ажиллагааг хянах боломжтой." + "Та %1$s-д холбогдсон бөгөөд энэ нь таны имэйл, апп, вебсайт зэрэг сүлжээний хувийн үйл ажиллагааг хянах боломжтой." + "Та имэйл, апп, веб хуудас зэрэг хувийн сүлжээнийхээ үйл ажиллагааг хянах боломжтой %1$s-д холбогдсон байна." + "Таны ажлын профайлыг %1$s удирддаг. Энэ нь таны имэйл, апп, веб хуудас зэрэг ажлын сүлжээний үйл ажиллагааг хянах боломжтой %2$s-д холбогдсон. \n\nДэлгэрэнгүй мэдээллийг авахын тулд админтай холбогдоно уу." + "Таны ажлын профайлыг %1$s удирддаг. Энэ нь таны имэйл, апп, веб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой %2$s-тай холбогдсон. \n\nМөн таны сүлжээний хувийн үйл ажиллагааг хянах боломжтой %3$s-д холбогдсон байна." "TrustAgent-р түгжээгүй байлгасан" "Таныг гараар нээх хүртэл төхөөрөмж түгжээтэй байх болно" "%1$s\n%2$s" @@ -653,8 +653,8 @@ "Сэрүүлэг" "Ажлын профайл" "Нислэгийн горим" - "Вэбсайтын цонх нэмэх" - "Вэбсайтын цонх дамжуулах" + "Вебсайтын цонх нэмэх" + "Вебсайтын цонх дамжуулах" "Та өмнө нь унтраагаагүй тохиолдолд %1$s-т сэрүүлгээ сонсохгүй" "%1$s-т та дараагийн сэрүүлгээ сонсохгүй" "%1$s цагт" diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 8eecf9b882db..92c8cf686d84 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -339,7 +339,7 @@ "Dessert Case" "स्क्रिन सेभर" "Ethernet" - "थप विकल्पहरूका लागि आइकनहरूमा छोइराख्नुहोस्" + "थप विकल्पहरूका लागि आइकनहरूमा टच एण्ड होल्ड गर्नुहोस्" "बाधा नपुऱ्याउनुहोस्" "प्राथमिकता मात्र" "अलार्महरू मात्र" @@ -591,16 +591,16 @@ "असक्षम पार्नुहोस्" "आउटपुट यन्त्र बदल्नुहोस्" "एप पिन गरिएको छ" - "तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र परिदृश्य बटनलाई छोइराख्नुहोस्।" - "तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र गृह नामक बटनहरूलाई छोइराख्नुहोस्।" + "तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र परिदृश्य बटनलाई टच एण्ड होल्ड गर्नुहोस्।" + "तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र गृह नामक बटनहरूलाई टच एण्ड होल्ड गर्नुहोस्।" "तपाईंले यो एप अनपिन नगरेसम्म यो एप यहाँ देखिइरहने छ। अनपिन गर्न माथितिर स्वाइप गरी होल्ड गर्नुहोस्।" - "तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न परिदृश्य बटनलाई छोइराख्नुहोस्।" - "तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न गृह नामक बटनलाई छोइराख्नुहोस्।" + "तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न परिदृश्य बटनलाई टच एण्ड होल्ड गर्नुहोस्।" + "तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न गृह नामक बटनलाई टच एण्ड होल्ड गर्नुहोस्।" "स्क्रिनमा व्यक्तिगत डेटा (जस्तै सम्पर्क ठेगाना र इमेलको सामग्री) देखिन सक्छ।" "पिन गरिएको एपले अन्य एप खोल्न सक्छ।" - "यो एप अनपनि गर्न पछाडि र विवरण नामक बटनहरूलाई छोइराख्नुहोस्" - "यो एप अनपनि गर्न पछाडि र होम बटनलाई छोइराख्नुहोस्" - "यो एप अनपिन गर्न माथितिर स्वाइप गरी स्क्रिनमा छोइराख्नुहोस्" + "यो एप अनपनि गर्न पछाडि र विवरण नामक बटनहरूलाई टच एण्ड होल्ड गर्नुहोस्" + "यो एप अनपनि गर्न पछाडि र होम बटनलाई टच एण्ड होल्ड गर्नुहोस्" + "यो एप अनपिन गर्न माथितिर स्वाइप गरी स्क्रिनमा टच एण्ड होल्ड गर्नुहोस्" "बुझेँ" "धन्यवाद पर्दैन" "एप पिन गरियो" -- GitLab From abfaf269a9922cd338a4ec4134f29fc35ccfd346 Mon Sep 17 00:00:00 2001 From: Ameer Armaly Date: Tue, 28 Jul 2020 13:49:15 -0700 Subject: [PATCH 053/382] [DO NOT MERGE] Enable two-finger passthrough swipes. Bug: 162521649 Test: atest GestureManifoldTest TouchExplorerTest AccessibilityGestureDetectorTest FrameworksServicesTests:TouchExplorerTest Change-Id: I9e6b691295a0fa006578d7b8ad8468579c66939c --- .../AccessibilityServiceInfo.java | 15 ++ ...bstractAccessibilityServiceConnection.java | 12 +- .../AccessibilityInputFilter.java | 13 +- .../AccessibilityManagerService.java | 6 + .../accessibility/AccessibilityUserState.java | 12 ++ .../gestures/GestureManifold.java | 35 ++++- .../accessibility/gestures/TouchExplorer.java | 141 ++++++++++++++---- .../gestures/TouchExplorerTest.java | 14 +- 8 files changed, 206 insertions(+), 42 deletions(-) diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index ca22bf4a62dc..d334de60713a 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -364,6 +364,18 @@ public class AccessibilityServiceInfo implements Parcelable { */ public static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x0001000; + /** + * This flag requests that when when {@link #FLAG_REQUEST_MULTI_FINGER_GESTURES} is enabled, + * two-finger passthrough gestures are re-enabled. Two-finger swipe gestures are not detected, + * but instead passed through as one-finger gestures. In addition, three-finger swipes from the + * bottom of the screen are not detected, and instead are passed through unchanged. If {@link + * #FLAG_REQUEST_MULTI_FINGER_GESTURES} is disabled this flag has no effect. + * + * @see #FLAG_REQUEST_TOUCH_EXPLORATION_MODE + * @hide + */ + public static final int FLAG_REQUEST_2_FINGER_PASSTHROUGH = 0x0002000; + /** {@hide} */ public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000; @@ -624,6 +636,7 @@ public class AccessibilityServiceInfo implements Parcelable { 0); flags = asAttributes.getInt( com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0); + flags |= FLAG_REQUEST_2_FINGER_PASSTHROUGH; mSettingsActivityName = asAttributes.getString( com.android.internal.R.styleable.AccessibilityService_settingsActivity); if (asAttributes.getBoolean(com.android.internal.R.styleable @@ -1261,6 +1274,8 @@ public class AccessibilityServiceInfo implements Parcelable { return "FLAG_SERVICE_HANDLES_DOUBLE_TAP"; case FLAG_REQUEST_MULTI_FINGER_GESTURES: return "FLAG_REQUEST_MULTI_FINGER_GESTURES"; + case FLAG_REQUEST_2_FINGER_PASSTHROUGH: + return "FLAG_REQUEST_2_FINGER_PASSTHROUGH"; case FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY: return "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY"; case FLAG_REPORT_VIEW_IDS: diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index 40a2816ee7de..8822d55cc30f 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -148,6 +148,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ private boolean mRequestMultiFingerGestures; + private boolean mRequestTwoFingerPassthrough; + boolean mRequestFilterKeyEvents; boolean mRetrieveInteractiveWindows; @@ -323,8 +325,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ & AccessibilityServiceInfo.FLAG_SERVICE_HANDLES_DOUBLE_TAP) != 0; mRequestMultiFingerGestures = (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0; - mRequestFilterKeyEvents = (info.flags - & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0; + mRequestTwoFingerPassthrough = + (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_2_FINGER_PASSTHROUGH) != 0; + mRequestFilterKeyEvents = + (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0; mRetrieveInteractiveWindows = (info.flags & AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0; mCaptureFingerprintGestures = (info.flags @@ -1773,6 +1777,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ return mRequestMultiFingerGestures; } + public boolean isTwoFingerPassthroughEnabled() { + return mRequestTwoFingerPassthrough; + } + @Override public void setGestureDetectionPassthroughRegion(int displayId, Region region) { mSystemSupport.setGestureDetectionPassthroughRegion(displayId, region); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java index 020f2253743d..a04a7c570b5c 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java @@ -114,6 +114,13 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo */ static final int FLAG_REQUEST_MULTI_FINGER_GESTURES = 0x00000100; + /** + * Flag for enabling multi-finger gestures. + * + * @see #setUserAndEnabledFeatures(int, int) + */ + static final int FLAG_REQUEST_2_FINGER_PASSTHROUGH = 0x00000200; + static final int FEATURES_AFFECTING_MOTION_EVENTS = FLAG_FEATURE_INJECT_MOTION_EVENTS | FLAG_FEATURE_AUTOCLICK @@ -121,7 +128,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo | FLAG_FEATURE_SCREEN_MAGNIFIER | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER | FLAG_SERVICE_HANDLES_DOUBLE_TAP - | FLAG_REQUEST_MULTI_FINGER_GESTURES; + | FLAG_REQUEST_MULTI_FINGER_GESTURES + | FLAG_REQUEST_2_FINGER_PASSTHROUGH; private final Context mContext; @@ -417,6 +425,9 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo if ((mEnabledFeatures & FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0) { explorer.setMultiFingerGesturesEnabled(true); } + if ((mEnabledFeatures & FLAG_REQUEST_2_FINGER_PASSTHROUGH) != 0) { + explorer.setTwoFingerPassthroughEnabled(true); + } addFirstEventHandler(displayId, explorer); mTouchExplorer.put(displayId, explorer); } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 499a2711d8e6..75fcc4c490ea 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1742,6 +1742,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (userState.isMultiFingerGesturesEnabledLocked()) { flags |= AccessibilityInputFilter.FLAG_REQUEST_MULTI_FINGER_GESTURES; } + if (userState.isTwoFingerPassthroughEnabledLocked()) { + flags |= AccessibilityInputFilter.FLAG_REQUEST_2_FINGER_PASSTHROUGH; + } } if (userState.isFilterKeyEventsEnabledLocked()) { flags |= AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS; @@ -2020,6 +2023,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub boolean touchExplorationEnabled = mUiAutomationManager.isTouchExplorationEnabledLocked(); boolean serviceHandlesDoubleTapEnabled = false; boolean requestMultiFingerGestures = false; + boolean requestTwoFingerPassthrough = false; final int serviceCount = userState.mBoundServices.size(); for (int i = 0; i < serviceCount; i++) { AccessibilityServiceConnection service = userState.mBoundServices.get(i); @@ -2027,6 +2031,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub touchExplorationEnabled = true; serviceHandlesDoubleTapEnabled = service.isServiceHandlesDoubleTapEnabled(); requestMultiFingerGestures = service.isMultiFingerGesturesEnabled(); + requestTwoFingerPassthrough = service.isTwoFingerPassthroughEnabled(); break; } } @@ -2043,6 +2048,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } userState.setServiceHandlesDoubleTapLocked(serviceHandlesDoubleTapEnabled); userState.setMultiFingerGesturesLocked(requestMultiFingerGestures); + userState.setTwoFingerPassthroughLocked(requestTwoFingerPassthrough); } private boolean readAccessibilityShortcutKeySettingLocked(AccessibilityUserState userState) { diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java index 0845d019c060..299a776df1d0 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java @@ -109,6 +109,7 @@ class AccessibilityUserState { private boolean mIsTouchExplorationEnabled; private boolean mServiceHandlesDoubleTap; private boolean mRequestMultiFingerGestures; + private boolean mRequestTwoFingerPassthrough; private int mUserInteractiveUiTimeout; private int mUserNonInteractiveUiTimeout; private int mNonInteractiveUiTimeout = 0; @@ -160,6 +161,7 @@ class AccessibilityUserState { mIsTouchExplorationEnabled = false; mServiceHandlesDoubleTap = false; mRequestMultiFingerGestures = false; + mRequestTwoFingerPassthrough = false; mIsDisplayMagnificationEnabled = false; mIsAutoclickEnabled = false; mUserNonInteractiveUiTimeout = 0; @@ -446,6 +448,8 @@ class AccessibilityUserState { .append(String.valueOf(mServiceHandlesDoubleTap)); pw.append(", requestMultiFingerGestures=") .append(String.valueOf(mRequestMultiFingerGestures)); + pw.append(", requestTwoFingerPassthrough=") + .append(String.valueOf(mRequestTwoFingerPassthrough)); pw.append(", displayMagnificationEnabled=").append(String.valueOf( mIsDisplayMagnificationEnabled)); pw.append(", autoclickEnabled=").append(String.valueOf(mIsAutoclickEnabled)); @@ -733,6 +737,14 @@ class AccessibilityUserState { public void setMultiFingerGesturesLocked(boolean enabled) { mRequestMultiFingerGestures = enabled; } + public boolean isTwoFingerPassthroughEnabledLocked() { + return mRequestTwoFingerPassthrough; + } + + public void setTwoFingerPassthroughLocked(boolean enabled) { + mRequestTwoFingerPassthrough = enabled; + } + public int getUserInteractiveUiTimeoutLocked() { return mUserInteractiveUiTimeout; diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java index e9c70c60a322..8604fe7a7359 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java @@ -94,8 +94,13 @@ class GestureManifold implements GestureMatcher.StateChangeListener { private boolean mServiceHandlesDoubleTap = false; // Whether multi-finger gestures are enabled. boolean mMultiFingerGesturesEnabled; + // Whether the two-finger passthrough is enabled when multi-finger gestures are enabled. + private boolean mTwoFingerPassthroughEnabled; // A list of all the multi-finger gestures, for easy adding and removal. private final List mMultiFingerGestures = new ArrayList<>(); + // A list of two-finger swipes, for easy adding and removal when turning on or off two-finger + // passthrough. + private final List mTwoFingerSwipes = new ArrayList<>(); // Shared state information. private TouchState mState; @@ -105,6 +110,7 @@ class GestureManifold implements GestureMatcher.StateChangeListener { mListener = listener; mState = state; mMultiFingerGesturesEnabled = false; + mTwoFingerPassthroughEnabled = false; // Set up gestures. // Start with double tap. mGestures.add(new MultiTap(context, 2, GESTURE_DOUBLE_TAP, this)); @@ -161,14 +167,14 @@ class GestureManifold implements GestureMatcher.StateChangeListener { mMultiFingerGestures.add( new MultiFingerMultiTap(mContext, 4, 3, GESTURE_4_FINGER_TRIPLE_TAP, this)); // Two-finger swipes. - mMultiFingerGestures.add( + mTwoFingerSwipes.add( new MultiFingerSwipe(context, 2, DOWN, GESTURE_2_FINGER_SWIPE_DOWN, this)); - mMultiFingerGestures.add( + mTwoFingerSwipes.add( new MultiFingerSwipe(context, 2, LEFT, GESTURE_2_FINGER_SWIPE_LEFT, this)); - mMultiFingerGestures.add( + mTwoFingerSwipes.add( new MultiFingerSwipe(context, 2, RIGHT, GESTURE_2_FINGER_SWIPE_RIGHT, this)); - mMultiFingerGestures.add( - new MultiFingerSwipe(context, 2, UP, GESTURE_2_FINGER_SWIPE_UP, this)); + mTwoFingerSwipes.add(new MultiFingerSwipe(context, 2, UP, GESTURE_2_FINGER_SWIPE_UP, this)); + mMultiFingerGestures.addAll(mTwoFingerSwipes); // Three-finger swipes. mMultiFingerGestures.add( new MultiFingerSwipe(context, 3, DOWN, GESTURE_3_FINGER_SWIPE_DOWN, this)); @@ -360,6 +366,25 @@ class GestureManifold implements GestureMatcher.StateChangeListener { } } + public boolean isTwoFingerPassthroughEnabled() { + return mTwoFingerPassthroughEnabled; + } + + public void setTwoFingerPassthroughEnabled(boolean mode) { + if (mTwoFingerPassthroughEnabled != mode) { + mTwoFingerPassthroughEnabled = mode; + if (!mode) { + mMultiFingerGestures.addAll(mTwoFingerSwipes); + if (mMultiFingerGesturesEnabled) { + mGestures.addAll(mTwoFingerSwipes); + } + } else { + mMultiFingerGestures.removeAll(mTwoFingerSwipes); + mGestures.removeAll(mTwoFingerSwipes); + } + } + } + public void setServiceHandlesDoubleTap(boolean mode) { mServiceHandlesDoubleTap = mode; } diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index fbc986bdd730..b2b37ddbb31e 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -24,6 +24,7 @@ import android.accessibilityservice.AccessibilityGestureEvent; import android.content.Context; import android.graphics.Region; import android.os.Handler; +import android.util.DisplayMetrics; import android.util.Slog; import android.view.InputDevice; import android.view.MotionEvent; @@ -73,12 +74,21 @@ public class TouchExplorer extends BaseEventStreamTransformation // The timeout after which we are no longer trying to detect a gesture. private static final int EXIT_GESTURE_DETECTION_TIMEOUT = 2000; + // The height of the top and bottom edges for edge-swipes. + // For now this is only used to allow three-finger edge-swipes from the bottom. + private static final float EDGE_SWIPE_HEIGHT_CM = 0.25f; + + // The calculated edge height for the top and bottom edges. + private final float mEdgeSwipeHeightPixels; // Timeout before trying to decide what the user is trying to do. private final int mDetermineUserIntentTimeout; // Slop between the first and second tap to be a double tap. private final int mDoubleTapSlop; + // Slop to move before being considered a move rather than a tap. + private final int mTouchSlop; + // The current state of the touch explorer. private TouchState mState; @@ -151,6 +161,9 @@ public class TouchExplorer extends BaseEventStreamTransformation mDispatcher = new EventDispatcher(context, mAms, super.getNext(), mState); mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout(); mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop(); + mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); + mEdgeSwipeHeightPixels = metrics.ydpi / GestureUtils.CM_PER_INCH * EDGE_SWIPE_HEIGHT_CM; mHandler = new Handler(context.getMainLooper()); mExitGestureDetectionModeDelayed = new ExitGestureDetectionModeDelayed(); mSendHoverEnterAndMoveDelayed = new SendHoverEnterAndMoveDelayed(); @@ -196,16 +209,10 @@ public class TouchExplorer extends BaseEventStreamTransformation if (mState.isTouchExploring()) { // If a touch exploration gesture is in progress send events for its end. sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); - } else if (mState.isDragging()) { - mDraggingPointerId = INVALID_POINTER_ID; - // Send exit to all pointers that we have delivered. - mDispatcher.sendUpForInjectedDownPointers(event, policyFlags); - } else if (mState.isDelegating()) { - // Send exit to all pointers that we have delivered. - mDispatcher.sendUpForInjectedDownPointers(event, policyFlags); - } else if (mState.isGestureDetecting()) { - // No state specific cleanup required. } + mDraggingPointerId = INVALID_POINTER_ID; + // Send exit to any pointers that we have delivered as part of delegating or dragging. + mDispatcher.sendUpForInjectedDownPointers(event, policyFlags); // Remove all pending callbacks. mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); @@ -532,7 +539,26 @@ public class TouchExplorer extends BaseEventStreamTransformation // stream consistent. sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); } + if (mGestureDetector.isMultiFingerGesturesEnabled() + && mGestureDetector.isTwoFingerPassthroughEnabled()) { + if (event.getPointerCount() == 3) { + boolean isOnBottomEdge = false; + // If three fingers go down on the bottom edge of the screen, delegate immediately. + final long screenHeight = mContext.getResources().getDisplayMetrics().heightPixels; + for (int i = 0; i < TouchState.MAX_POINTER_COUNT; ++i) { + if (mReceivedPointerTracker.getReceivedPointerDownY(i) + > (screenHeight - mEdgeSwipeHeightPixels)) { + isOnBottomEdge = true; + } + } + if (isOnBottomEdge) { + mState.startDelegating(); + mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags); + } + } + } } + /** * Handles ACTION_MOVE while in the touch interacting state. This is where transitions to * delegating and dragging states are handled. @@ -541,7 +567,7 @@ public class TouchExplorer extends BaseEventStreamTransformation MotionEvent event, MotionEvent rawEvent, int policyFlags) { final int pointerId = mReceivedPointerTracker.getPrimaryPointerId(); final int pointerIndex = event.findPointerIndex(pointerId); - final int pointerIdBits = (1 << pointerId); + int pointerIdBits = (1 << pointerId); switch (event.getPointerCount()) { case 1: // We have not started sending events since we try to @@ -552,12 +578,26 @@ public class TouchExplorer extends BaseEventStreamTransformation } break; case 2: - if (mGestureDetector.isMultiFingerGesturesEnabled()) { + if (mGestureDetector.isMultiFingerGesturesEnabled() + && !mGestureDetector.isTwoFingerPassthroughEnabled()) { return; } // Make sure we don't have any pending transitions to touch exploration mSendHoverEnterAndMoveDelayed.cancel(); mSendHoverExitDelayed.cancel(); + if (mGestureDetector.isMultiFingerGesturesEnabled() + && mGestureDetector.isTwoFingerPassthroughEnabled()) { + final float deltaX = + mReceivedPointerTracker.getReceivedPointerDownX(pointerId) + - rawEvent.getX(pointerIndex); + final float deltaY = + mReceivedPointerTracker.getReceivedPointerDownY(pointerId) + - rawEvent.getY(pointerIndex); + final double moveDelta = Math.hypot(deltaX, deltaY); + if (moveDelta < mTouchSlop) { + return; + } + } // More than one pointer so the user is not touch exploring // and now we have to decide whether to delegate or drag. // Remove move history before send injected non-move events @@ -566,8 +606,8 @@ public class TouchExplorer extends BaseEventStreamTransformation // Two pointers moving in the same direction within // a given distance perform a drag. mState.startDragging(); - mDraggingPointerId = pointerId; adjustEventLocationForDrag(event); + pointerIdBits = 1 << mDraggingPointerId; event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags()); mDispatcher.sendMotionEvent( event, MotionEvent.ACTION_DOWN, rawEvent, pointerIdBits, policyFlags); @@ -626,7 +666,8 @@ public class TouchExplorer extends BaseEventStreamTransformation event, MotionEvent.ACTION_HOVER_MOVE, rawEvent, pointerIdBits, policyFlags); break; case 2: - if (mGestureDetector.isMultiFingerGesturesEnabled()) { + if (mGestureDetector.isMultiFingerGesturesEnabled() + && !mGestureDetector.isTwoFingerPassthroughEnabled()) { return; } if (mSendHoverEnterAndMoveDelayed.isPending()) { @@ -681,7 +722,8 @@ public class TouchExplorer extends BaseEventStreamTransformation */ private void handleMotionEventStateDragging( MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (mGestureDetector.isMultiFingerGesturesEnabled()) { + if (mGestureDetector.isMultiFingerGesturesEnabled() + && !mGestureDetector.isTwoFingerPassthroughEnabled()) { // Multi-finger gestures conflict with this functionality. return; } @@ -734,6 +776,7 @@ public class TouchExplorer extends BaseEventStreamTransformation // The two pointers are moving either in different directions or // no close enough => delegate the gesture to the view hierarchy. mState.startDelegating(); + mDraggingPointerId = INVALID_POINTER_ID; // Remove move history before send injected non-move events event = MotionEvent.obtainNoHistory(event); // Send an event to the end of the drag gesture. @@ -749,6 +792,7 @@ public class TouchExplorer extends BaseEventStreamTransformation } break; default: { mState.startDelegating(); + mDraggingPointerId = INVALID_POINTER_ID; event = MotionEvent.obtainNoHistory(event); // Send an event to the end of the drag gesture. mDispatcher.sendMotionEvent( @@ -772,17 +816,15 @@ public class TouchExplorer extends BaseEventStreamTransformation } } break; case MotionEvent.ACTION_UP: { - mAms.onTouchInteractionEnd(); - // Announce the end of a new touch interaction. - mDispatcher.sendAccessibilityEvent( - AccessibilityEvent.TYPE_TOUCH_INTERACTION_END); final int pointerId = event.getPointerId(event.getActionIndex()); if (pointerId == mDraggingPointerId) { - mDraggingPointerId = INVALID_POINTER_ID; - // Send an event to the end of the drag gesture. mDispatcher.sendMotionEvent( event, MotionEvent.ACTION_UP, rawEvent, pointerIdBits, policyFlags); } + mAms.onTouchInteractionEnd(); + // Announce the end of a new touch interaction. + mDispatcher.sendAccessibilityEvent( + AccessibilityEvent.TYPE_TOUCH_INTERACTION_END); } break; } } @@ -901,21 +943,55 @@ public class TouchExplorer extends BaseEventStreamTransformation } /** - * Adjust the location of an injected event when performing a drag The new location will be in - * between the two fingers touching the screen. + * Adjust the location of an injected event when performing a drag. The location will be the + * location of the finger closest to an edge of the screen. */ private void adjustEventLocationForDrag(MotionEvent event) { - final float firstPtrX = event.getX(0); final float firstPtrY = event.getY(0); + final int firstPtrId = event.getPointerId(0); final float secondPtrX = event.getX(1); final float secondPtrY = event.getY(1); - final int pointerIndex = event.findPointerIndex(mDraggingPointerId); - final float deltaX = - (pointerIndex == 0) ? (secondPtrX - firstPtrX) : (firstPtrX - secondPtrX); - final float deltaY = - (pointerIndex == 0) ? (secondPtrY - firstPtrY) : (firstPtrY - secondPtrY); - event.offsetLocation(deltaX / 2, deltaY / 2); + final int secondPtrId = event.getPointerId(1); + float draggingX; + float draggingY; + if (mDraggingPointerId == INVALID_POINTER_ID) { + // The goal is to use the coordinates of the finger that is closest to its closest edge. + if (getDistanceToClosestEdge(firstPtrX, firstPtrY) + < getDistanceToClosestEdge(secondPtrX, secondPtrY)) { + draggingX = firstPtrX; + draggingY = firstPtrY; + mDraggingPointerId = firstPtrId; + } else { + draggingX = secondPtrX; + draggingY = secondPtrY; + mDraggingPointerId = secondPtrId; + } + } else { + // Just use the coordinates of the dragging pointer. + int pointerIndex = event.findPointerIndex(mDraggingPointerId); + draggingX = event.getX(pointerIndex); + draggingY = event.getY(pointerIndex); + } + event.setLocation(draggingX, draggingY); + } + + private float getDistanceToClosestEdge(float x, float y) { + final long width = mContext.getResources().getDisplayMetrics().widthPixels; + final long height = mContext.getResources().getDisplayMetrics().heightPixels; + float distance = Float.MAX_VALUE; + if (x < (width - x)) { + distance = x; + } else { + distance = width - x; + } + if (distance > y) { + distance = y; + } + if (distance > (height - y)) { + distance = (height - y); + } + return distance; } public TouchState getState() { @@ -944,6 +1020,13 @@ public class TouchExplorer extends BaseEventStreamTransformation mGestureDetector.setMultiFingerGesturesEnabled(enabled); } + /** + * This function turns on and off two-finger passthrough gestures such as drag and pinch when + * multi-finger gestures are enabled. + */ + public void setTwoFingerPassthroughEnabled(boolean enabled) { + mGestureDetector.setTwoFingerPassthroughEnabled(enabled); + } public void setGestureDetectionPassthroughRegion(Region region) { mGestureDetectionPassthroughRegion = region; } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java index 9053234aa220..f929321a61be 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java @@ -31,6 +31,7 @@ import android.os.SystemClock; import android.testing.DexmakerShareClassLoaderRule; import android.view.InputDevice; import android.view.MotionEvent; +import android.view.ViewConfiguration; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; @@ -72,6 +73,8 @@ public class TouchExplorerTest { private EventStreamTransformation mCaptor; private MotionEvent mLastEvent; private TouchExplorer mTouchExplorer; + private Context mContext; + private int mTouchSlop; private long mLastDownTime = Integer.MIN_VALUE; // mock package-private GestureManifold class @@ -109,11 +112,12 @@ public class TouchExplorerTest { @Before public void setUp() { - Context context = InstrumentationRegistry.getContext(); - AccessibilityManagerService ams = new AccessibilityManagerService(context); + mContext = InstrumentationRegistry.getContext(); + mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); + AccessibilityManagerService ams = new AccessibilityManagerService(mContext); GestureManifold detector = mock(GestureManifold.class); mCaptor = new EventCaptor(); - mTouchExplorer = new TouchExplorer(context, ams, detector); + mTouchExplorer = new TouchExplorer(mContext, ams, detector); mTouchExplorer.setNext(mCaptor); } @@ -226,13 +230,13 @@ public class TouchExplorerTest { break; case STATE_DRAGGING_2FINGERS: { goFromStateClearTo(STATE_TOUCH_EXPLORING_2FINGER); - moveEachPointers(mLastEvent, p(10, 0), p(10, 0)); + moveEachPointers(mLastEvent, p(mTouchSlop, 0), p(mTouchSlop, 0)); send(mLastEvent); } break; case STATE_PINCH_2FINGERS: { goFromStateClearTo(STATE_DRAGGING_2FINGERS); - moveEachPointers(mLastEvent, p(10, 0), p(-10, 1)); + moveEachPointers(mLastEvent, p(mTouchSlop, 0), p(-mTouchSlop, 1)); send(mLastEvent); } break; -- GitLab From c39597b6343c19a08a95b195c06b4054678b6fe2 Mon Sep 17 00:00:00 2001 From: Phil Weaver Date: Fri, 7 Aug 2020 18:07:16 +0000 Subject: [PATCH 054/382] [DO NOT MERGE] Fix crash with multifinger touch exploration Range check index into motion event x and y before using it. Bug: 163107812 Test: Relying on treehugger. I can't reproduce the crash, so I'm just adding checks. Change-Id: I4ac5023ef9b5c101748b870a01a425a1365fb85c --- .../accessibility/gestures/TouchExplorer.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index b2b37ddbb31e..a4961178cc89 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -587,6 +587,9 @@ public class TouchExplorer extends BaseEventStreamTransformation mSendHoverExitDelayed.cancel(); if (mGestureDetector.isMultiFingerGesturesEnabled() && mGestureDetector.isTwoFingerPassthroughEnabled()) { + if (pointerIndex < 0) { + return; + } final float deltaX = mReceivedPointerTracker.getReceivedPointerDownX(pointerId) - rawEvent.getX(pointerIndex); @@ -953,25 +956,32 @@ public class TouchExplorer extends BaseEventStreamTransformation final float secondPtrX = event.getX(1); final float secondPtrY = event.getY(1); final int secondPtrId = event.getPointerId(1); - float draggingX; - float draggingY; + float draggingX = firstPtrX; + float draggingY = firstPtrY; + if (mDraggingPointerId != INVALID_POINTER_ID) { + // Just use the coordinates of the dragging pointer. + int pointerIndex = event.findPointerIndex(mDraggingPointerId); + if (pointerIndex >= 0) { + draggingX = event.getX(pointerIndex); + draggingY = event.getY(pointerIndex); + } else { + // We've lost track of the dragging pointer. Try to recover by invalidating it. + // We'll the drop into the code below to choose a new one. + mDraggingPointerId = INVALID_POINTER_ID; + } + } + // Not quite an else, since the above code can invalidate the pointer if (mDraggingPointerId == INVALID_POINTER_ID) { // The goal is to use the coordinates of the finger that is closest to its closest edge. if (getDistanceToClosestEdge(firstPtrX, firstPtrY) < getDistanceToClosestEdge(secondPtrX, secondPtrY)) { - draggingX = firstPtrX; - draggingY = firstPtrY; + // X and Y initialized to firstPtrX and Y was right mDraggingPointerId = firstPtrId; } else { draggingX = secondPtrX; draggingY = secondPtrY; mDraggingPointerId = secondPtrId; } - } else { - // Just use the coordinates of the dragging pointer. - int pointerIndex = event.findPointerIndex(mDraggingPointerId); - draggingX = event.getX(pointerIndex); - draggingY = event.getY(pointerIndex); } event.setLocation(draggingX, draggingY); } -- GitLab From 1f49d41a6a637f04e29a843bdef27709eb49557d Mon Sep 17 00:00:00 2001 From: Phil Weaver Date: Fri, 7 Aug 2020 22:25:17 +0000 Subject: [PATCH 055/382] [DO NOT MERGE] Address drag unreliability during touch exploration The code was trying to set the location of the drag, but MotionEvent doesn't behave consistently when setting a single location to a multi-touch event. All that's needed is to select the correct pointer, so removing messing with the location gives more consistent behavior. Bug: 163105030 Change-Id: I6c315cf0a1e48847cc778ec8c34b382d13ce3555 Test: Manually testing at this point of the passthrough, and relying on treehugger. --- .../accessibility/gestures/TouchExplorer.java | 49 ++++++------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index a4961178cc89..b5417cc1504d 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -609,7 +609,7 @@ public class TouchExplorer extends BaseEventStreamTransformation // Two pointers moving in the same direction within // a given distance perform a drag. mState.startDragging(); - adjustEventLocationForDrag(event); + computeDraggingPointerIdIfNeeded(event); pointerIdBits = 1 << mDraggingPointerId; event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags()); mDispatcher.sendMotionEvent( @@ -768,7 +768,7 @@ public class TouchExplorer extends BaseEventStreamTransformation case 2: { if (isDraggingGesture(event)) { // If still dragging send a drag event. - adjustEventLocationForDrag(event); + computeDraggingPointerIdIfNeeded(event); mDispatcher.sendMotionEvent( event, MotionEvent.ACTION_MOVE, @@ -946,44 +946,27 @@ public class TouchExplorer extends BaseEventStreamTransformation } /** - * Adjust the location of an injected event when performing a drag. The location will be the - * location of the finger closest to an edge of the screen. + * Computes {@link #mDraggingPointerId} if it is invalid. The pointer will be the finger + * closet to an edge of the screen. */ - private void adjustEventLocationForDrag(MotionEvent event) { + private void computeDraggingPointerIdIfNeeded(MotionEvent event) { + if (mDraggingPointerId != INVALID_POINTER_ID) { + // If we have a valid pointer ID, we should be good + final int pointerIndex = event.findPointerIndex(mDraggingPointerId); + if (event.findPointerIndex(pointerIndex) >= 0) { + return; + } + } + // Use the pointer that is closest to its closest edge. final float firstPtrX = event.getX(0); final float firstPtrY = event.getY(0); final int firstPtrId = event.getPointerId(0); final float secondPtrX = event.getX(1); final float secondPtrY = event.getY(1); final int secondPtrId = event.getPointerId(1); - float draggingX = firstPtrX; - float draggingY = firstPtrY; - if (mDraggingPointerId != INVALID_POINTER_ID) { - // Just use the coordinates of the dragging pointer. - int pointerIndex = event.findPointerIndex(mDraggingPointerId); - if (pointerIndex >= 0) { - draggingX = event.getX(pointerIndex); - draggingY = event.getY(pointerIndex); - } else { - // We've lost track of the dragging pointer. Try to recover by invalidating it. - // We'll the drop into the code below to choose a new one. - mDraggingPointerId = INVALID_POINTER_ID; - } - } - // Not quite an else, since the above code can invalidate the pointer - if (mDraggingPointerId == INVALID_POINTER_ID) { - // The goal is to use the coordinates of the finger that is closest to its closest edge. - if (getDistanceToClosestEdge(firstPtrX, firstPtrY) - < getDistanceToClosestEdge(secondPtrX, secondPtrY)) { - // X and Y initialized to firstPtrX and Y was right - mDraggingPointerId = firstPtrId; - } else { - draggingX = secondPtrX; - draggingY = secondPtrY; - mDraggingPointerId = secondPtrId; - } - } - event.setLocation(draggingX, draggingY); + mDraggingPointerId = (getDistanceToClosestEdge(firstPtrX, firstPtrY) + < getDistanceToClosestEdge(secondPtrX, secondPtrY)) + ? firstPtrId : secondPtrId; } private float getDistanceToClosestEdge(float x, float y) { -- GitLab From aa25d2041fd1e53058f8a6342172231de3822f79 Mon Sep 17 00:00:00 2001 From: Ameer Armaly Date: Tue, 18 Aug 2020 13:49:44 -0700 Subject: [PATCH 056/382] [DO NOT MERGE] Start dragging where the fingers initially went down. This does not apply when transitioning from touch exploration to dragging. Bug: 162521649 Test: manual Change-Id: I92022ca0359040a6563e6a48c110face574dc9df --- .../accessibility/gestures/TouchExplorer.java | 57 ++++++++++++++++++- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index b5417cc1504d..90806969816e 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -608,12 +608,20 @@ public class TouchExplorer extends BaseEventStreamTransformation if (isDraggingGesture(event)) { // Two pointers moving in the same direction within // a given distance perform a drag. - mState.startDragging(); computeDraggingPointerIdIfNeeded(event); pointerIdBits = 1 << mDraggingPointerId; event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags()); - mDispatcher.sendMotionEvent( - event, MotionEvent.ACTION_DOWN, rawEvent, pointerIdBits, policyFlags); + MotionEvent downEvent = computeDownEventForDrag(event); + if (downEvent != null) { + mDispatcher.sendMotionEvent(downEvent, MotionEvent.ACTION_DOWN, rawEvent, + pointerIdBits, policyFlags); + mDispatcher.sendMotionEvent(event, MotionEvent.ACTION_MOVE, rawEvent, + pointerIdBits, policyFlags); + } else { + mDispatcher.sendMotionEvent(event, MotionEvent.ACTION_DOWN, rawEvent, + pointerIdBits, policyFlags); + } + mState.startDragging(); } else { // Two pointers moving arbitrary are delegated to the view hierarchy. mState.startDelegating(); @@ -987,6 +995,49 @@ public class TouchExplorer extends BaseEventStreamTransformation return distance; } + /** + * Creates a down event using the down coordinates of the dragging pointer and other information + * from the supplied event. The supplied event's down time is adjusted to reflect the time when + * the dragging pointer initially went down. + */ + private MotionEvent computeDownEventForDrag(MotionEvent event) { + // Creating a down event only makes sense if we haven't started touch exploring yet. + if (mState.isTouchExploring() + || mDraggingPointerId == INVALID_POINTER_ID + || event == null) { + return null; + } + final float x = mReceivedPointerTracker.getReceivedPointerDownX(mDraggingPointerId); + final float y = mReceivedPointerTracker.getReceivedPointerDownY(mDraggingPointerId); + final long time = mReceivedPointerTracker.getReceivedPointerDownTime(mDraggingPointerId); + MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[1]; + coords[0] = new MotionEvent.PointerCoords(); + coords[0].x = x; + coords[0].y = y; + MotionEvent.PointerProperties[] properties = new MotionEvent.PointerProperties[1]; + properties[0] = new MotionEvent.PointerProperties(); + properties[0].id = mDraggingPointerId; + properties[0].toolType = MotionEvent.TOOL_TYPE_FINGER; + MotionEvent downEvent = + MotionEvent.obtain( + time, + time, + MotionEvent.ACTION_DOWN, + 1, + properties, + coords, + event.getMetaState(), + event.getButtonState(), + event.getXPrecision(), + event.getYPrecision(), + event.getDeviceId(), + event.getEdgeFlags(), + event.getSource(), + event.getFlags()); + event.setDownTime(time); + return downEvent; + } + public TouchState getState() { return mState; } -- GitLab From a7da0f4f6d9a0c5e7959831867ddc5c3bd1baf43 Mon Sep 17 00:00:00 2001 From: Ameer Armaly Date: Tue, 18 Aug 2020 18:09:42 -0700 Subject: [PATCH 057/382] [DO NOT MERGE] Require both fingers to move before starting two-finger passthrough. Bug: 162521649 Test: manual Change-Id: Ia6b7bf84fd0c7777f21afbd0e0c09bf3f4a10fb2 --- .../accessibility/gestures/TouchExplorer.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index 90806969816e..5509b3fdaa1b 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -590,15 +590,23 @@ public class TouchExplorer extends BaseEventStreamTransformation if (pointerIndex < 0) { return; } - final float deltaX = - mReceivedPointerTracker.getReceivedPointerDownX(pointerId) - - rawEvent.getX(pointerIndex); - final float deltaY = - mReceivedPointerTracker.getReceivedPointerDownY(pointerId) - - rawEvent.getY(pointerIndex); - final double moveDelta = Math.hypot(deltaX, deltaY); - if (moveDelta < mTouchSlop) { - return; + // Require both fingers to have moved a certain amount before starting a drag. + for (int index = 0; index < event.getPointerCount(); ++index) { + int id = event.getPointerId(index); + if (!mReceivedPointerTracker.isReceivedPointerDown(id)) { + // Something is wrong with the event stream. + Slog.e(LOG_TAG, "Invalid pointer id: " + id); + } + final float deltaX = + mReceivedPointerTracker.getReceivedPointerDownX(id) + - rawEvent.getX(index); + final float deltaY = + mReceivedPointerTracker.getReceivedPointerDownY(id) + - rawEvent.getY(index); + final double moveDelta = Math.hypot(deltaX, deltaY); + if (moveDelta < mTouchSlop) { + return; + } } } // More than one pointer so the user is not touch exploring -- GitLab From 217bb3b1d2182d83101337cff0930d2696254699 Mon Sep 17 00:00:00 2001 From: Ameer Armaly Date: Tue, 11 Aug 2020 17:27:02 -0700 Subject: [PATCH 058/382] [DO NOT MERGE] Fix edge swipe logic. 1) Only start delegating upon first move event, if all three fingers went down on the bottom edge. 2) The previous logic only required one finger to be in the edge boundary. It now requires all fingers to be in the edge boundary. Bug: 162521649 Test: manual Change-Id: I829c463c63b384642d129ff3b5ccdb0db816ddcd --- .../accessibility/gestures/TouchExplorer.java | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index 5509b3fdaa1b..a13f59c2e549 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -539,24 +539,6 @@ public class TouchExplorer extends BaseEventStreamTransformation // stream consistent. sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags); } - if (mGestureDetector.isMultiFingerGesturesEnabled() - && mGestureDetector.isTwoFingerPassthroughEnabled()) { - if (event.getPointerCount() == 3) { - boolean isOnBottomEdge = false; - // If three fingers go down on the bottom edge of the screen, delegate immediately. - final long screenHeight = mContext.getResources().getDisplayMetrics().heightPixels; - for (int i = 0; i < TouchState.MAX_POINTER_COUNT; ++i) { - if (mReceivedPointerTracker.getReceivedPointerDownY(i) - > (screenHeight - mEdgeSwipeHeightPixels)) { - isOnBottomEdge = true; - } - } - if (isOnBottomEdge) { - mState.startDelegating(); - mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags); - } - } - } } /** @@ -638,12 +620,34 @@ public class TouchExplorer extends BaseEventStreamTransformation break; default: if (mGestureDetector.isMultiFingerGesturesEnabled()) { - return; + if (mGestureDetector.isTwoFingerPassthroughEnabled()) { + if (event.getPointerCount() == 3) { + boolean isOnBottomEdge = true; + // If three fingers went down on the bottom edge of the screen, delegate + // immediately. + final long screenHeight = + mContext.getResources().getDisplayMetrics().heightPixels; + for (int i = 0; i < TouchState.MAX_POINTER_COUNT; ++i) { + if (mReceivedPointerTracker.getReceivedPointerDownY(i) + < (screenHeight - mEdgeSwipeHeightPixels)) { + isOnBottomEdge = false; + } + } + if (isOnBottomEdge) { + if (DEBUG) { + Slog.d(LOG_TAG, "Three-finger edge swipe detected."); + } + mState.startDelegating(); + mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags); + } + } + } + } else { + // More than two pointers are delegated to the view hierarchy. + mState.startDelegating(); + event = MotionEvent.obtainNoHistory(event); + mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags); } - // More than two pointers are delegated to the view hierarchy. - mState.startDelegating(); - event = MotionEvent.obtainNoHistory(event); - mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags); break; } } -- GitLab From dd8ef30adfc6e47b6d48c2aa558c1a793ce8eab9 Mon Sep 17 00:00:00 2001 From: ryanlwlin Date: Thu, 20 Aug 2020 09:53:58 +0800 Subject: [PATCH 059/382] [DO NOT MERGE] Fix hardly to perform 3-finger swipe from the bottom We accidentky checked invalid pointers down position. In stead of checking all pointers, we check the pointer ids from the motion event. Bug: 165576902 Test: manually test atest TouchExplorerTest Change-Id: Id530bf4b760351215726b2afd781433b590f57ce --- .../accessibility/gestures/TouchExplorer.java | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index a13f59c2e549..abde43076c4e 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -622,18 +622,9 @@ public class TouchExplorer extends BaseEventStreamTransformation if (mGestureDetector.isMultiFingerGesturesEnabled()) { if (mGestureDetector.isTwoFingerPassthroughEnabled()) { if (event.getPointerCount() == 3) { - boolean isOnBottomEdge = true; // If three fingers went down on the bottom edge of the screen, delegate // immediately. - final long screenHeight = - mContext.getResources().getDisplayMetrics().heightPixels; - for (int i = 0; i < TouchState.MAX_POINTER_COUNT; ++i) { - if (mReceivedPointerTracker.getReceivedPointerDownY(i) - < (screenHeight - mEdgeSwipeHeightPixels)) { - isOnBottomEdge = false; - } - } - if (isOnBottomEdge) { + if (allPointersDownOnBottomEdge(event)) { if (DEBUG) { Slog.d(LOG_TAG, "Three-finger edge swipe detected."); } @@ -1050,6 +1041,22 @@ public class TouchExplorer extends BaseEventStreamTransformation return downEvent; } + private boolean allPointersDownOnBottomEdge(MotionEvent event) { + final long screenHeight = + mContext.getResources().getDisplayMetrics().heightPixels; + for (int i = 0; i < event.getPointerCount(); ++i) { + final int pointerId = event.getPointerId(i); + final float pointerDownY = mReceivedPointerTracker.getReceivedPointerDownY(pointerId); + if (pointerDownY < (screenHeight - mEdgeSwipeHeightPixels)) { + if (DEBUG) { + Slog.d(LOG_TAG, "The pointer is not on the bottom edge" + pointerDownY); + } + return false; + } + } + return true; + } + public TouchState getState() { return mState; } -- GitLab From 81570aa5ade3cbaba15ca0517e0c7a5218fe04d1 Mon Sep 17 00:00:00 2001 From: ryanlwlin Date: Tue, 25 Aug 2020 17:45:40 +0800 Subject: [PATCH 060/382] [DO NOT MERGE] Fix sometime couldn't trigger A11y button with 3-finger We inject the down events from where we detect the 3-finger swipe gesture. It may not trigger the A11y Button if the event is not inside the system gesture detection area. We inject the original down location to injection all down events. Bug: 166187595 Test: manually test Change-Id: I0c0f84047fc24e40724332d51d7e3dc414bd0186 --- .../gestures/EventDispatcher.java | 69 +++++++++++++++++++ .../accessibility/gestures/TouchExplorer.java | 8 ++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java index 070626be9f80..c70dfcc93e49 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java @@ -256,6 +256,7 @@ class EventDispatcher { return actionMasked; } } + /** * Sends down events to the view hierarchy for all pointers which are not already being * delivered i.e. pointers that are not yet injected. @@ -285,6 +286,74 @@ class EventDispatcher { } /** + * Sends down events to the view hierarchy for all pointers which are not already being + * delivered with original down location. i.e. pointers that are not yet injected. + * + * @param prototype The prototype from which to create the injected events. + * @param policyFlags The policy flags associated with the event. + */ + void sendDownForAllNotInjectedPointersWithOriginalDown(MotionEvent prototype, int policyFlags) { + // Inject the injected pointers. + int pointerIdBits = 0; + final int pointerCount = prototype.getPointerCount(); + final MotionEvent event = computeEventWithOriginalDown(prototype); + for (int i = 0; i < pointerCount; i++) { + final int pointerId = prototype.getPointerId(i); + // Do not send event for already delivered pointers. + if (!mState.isInjectedPointerDown(pointerId)) { + pointerIdBits |= (1 << pointerId); + final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i); + sendMotionEvent( + event, + action, + mState.getLastReceivedEvent(), + pointerIdBits, + policyFlags); + } + } + } + + private MotionEvent computeEventWithOriginalDown(MotionEvent prototype) { + final int pointerCount = prototype.getPointerCount(); + if (pointerCount != mState.getReceivedPointerTracker().getReceivedPointerDownCount()) { + Slog.w(LOG_TAG, "The pointer count doesn't match the received count."); + return MotionEvent.obtain(prototype); + } + MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[pointerCount]; + MotionEvent.PointerProperties[] properties = + new MotionEvent.PointerProperties[pointerCount]; + for (int i = 0; i < pointerCount; ++i) { + final int pointerId = prototype.getPointerId(i); + final float x = mState.getReceivedPointerTracker().getReceivedPointerDownX(pointerId); + final float y = mState.getReceivedPointerTracker().getReceivedPointerDownY(pointerId); + coords[i] = new MotionEvent.PointerCoords(); + coords[i].x = x; + coords[i].y = y; + properties[i] = new MotionEvent.PointerProperties(); + properties[i].id = pointerId; + properties[i].toolType = MotionEvent.TOOL_TYPE_FINGER; + } + MotionEvent event = + MotionEvent.obtain( + prototype.getDownTime(), + prototype.getEventTime(), + prototype.getAction(), + pointerCount, + properties, + coords, + prototype.getMetaState(), + prototype.getButtonState(), + prototype.getXPrecision(), + prototype.getYPrecision(), + prototype.getDeviceId(), + prototype.getEdgeFlags(), + prototype.getSource(), + prototype.getFlags()); + return event; + } + + /** + * * Sends up events to the view hierarchy for all pointers which are already being delivered i.e. * pointers that are injected. * diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index abde43076c4e..2b1e872420bc 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -629,7 +629,13 @@ public class TouchExplorer extends BaseEventStreamTransformation Slog.d(LOG_TAG, "Three-finger edge swipe detected."); } mState.startDelegating(); - mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags); + if (mState.isTouchExploring()) { + mDispatcher.sendDownForAllNotInjectedPointers(event, + policyFlags); + } else { + mDispatcher.sendDownForAllNotInjectedPointersWithOriginalDown( + event, policyFlags); + } } } } -- GitLab From be8a943e46f53b1bceaa112349e03dfd4bb4c2e1 Mon Sep 17 00:00:00 2001 From: Ameer Armaly Date: Tue, 25 Aug 2020 19:00:17 -0700 Subject: [PATCH 061/382] [DO NOT MERGE] Use correct touch slop value for two-finger passthrough. Throughout the gesture system we scale the touch slop radius to the number of fingers that are down at any given moment. Therefore the correct value to trigger two-finger passthrough should be 2 * mTouchSlop. This should make three-finger taps less problematic. Bug: 163438921 Bug: 162521649 Test: manual Change-Id: I4b36b5575bf11ad767d83effd6292dc84eadb27d Change-Id: I9fb9d58ef679151c9fc595bcb375f6209ea3a5af Change-Id: Ibcae2a5a3fde37b97859165efabf2b0df13ded9b --- .../android/server/accessibility/gestures/TouchExplorer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java index 2b1e872420bc..bfb59f43aa1d 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java @@ -586,7 +586,7 @@ public class TouchExplorer extends BaseEventStreamTransformation mReceivedPointerTracker.getReceivedPointerDownY(id) - rawEvent.getY(index); final double moveDelta = Math.hypot(deltaX, deltaY); - if (moveDelta < mTouchSlop) { + if (moveDelta < (2 * mTouchSlop)) { return; } } -- GitLab From a070cca5e207a6f475e467adf123ecf1285f8bbf Mon Sep 17 00:00:00 2001 From: Ameer Armaly Date: Tue, 25 Aug 2020 19:05:55 -0700 Subject: [PATCH 062/382] [DO NOT MERGE] MultiFingerSwipe: scale touch slop to number of fingers. Bug: 162521649 Test: manual Change-Id: I990693ac07f4653f7d8ff9c097b5720593235afb --- .../android/server/accessibility/gestures/MultiFingerSwipe.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java index 4b89731b75b6..2a305397924f 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java @@ -294,7 +294,7 @@ class MultiFingerSwipe extends GestureMatcher { + Float.toString(mGestureDetectionThresholdPixels)); } if (getState() == STATE_CLEAR) { - if (moveDelta < mTouchSlop) { + if (moveDelta < (mTargetFingerCount * mTouchSlop)) { // This still counts as a touch not a swipe. continue; } else if (mStrokeBuffers[pointerIndex].size() == 0) { -- GitLab From 8c662c346ceae0e0b05499aacc6ba5432e130dfd Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Mon, 5 Oct 2020 10:47:33 -0400 Subject: [PATCH 063/382] Remove SQLlite log It's expensive and the in memory stats are sufficient for now. Also migrate the remote views logging to use the in memory stats Test: atest Fixes: 159975422 Change-Id: Ifcb2418fcb3a13d40b93d676bfaf1d8e2b6ca445 (cherry picked from commit 8325c40f006e0ed02f4c0e9b3ebb7e2643851f03) --- .../notification/NotificationUsageStats.java | 386 +----------------- 1 file changed, 7 insertions(+), 379 deletions(-) diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java index b42fe929549a..9e91875bfd86 100644 --- a/services/core/java/com/android/server/notification/NotificationUsageStats.java +++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java @@ -77,7 +77,6 @@ public class NotificationUsageStats { private final Map mStats = new HashMap<>(); private final ArrayDeque mStatsArrays = new ArrayDeque<>(); private ArraySet mStatExpiredkeys = new ArraySet<>(); - private final SQLiteLog mSQLiteLog; private final Context mContext; private final Handler mHandler; private long mLastEmitTime; @@ -85,7 +84,6 @@ public class NotificationUsageStats { public NotificationUsageStats(Context context) { mContext = context; mLastEmitTime = SystemClock.elapsedRealtime(); - mSQLiteLog = ENABLE_SQLITE_LOG ? new SQLiteLog(context) : null; mHandler = new Handler(mContext.getMainLooper()) { @Override public void handleMessage(Message msg) { @@ -152,9 +150,6 @@ public class NotificationUsageStats { stats.numUndecoratedRemoteViews += (notification.hasUndecoratedRemoteView() ? 1 : 0); } releaseAggregatedStatsLocked(aggregatedStatsArray); - if (ENABLE_SQLITE_LOG) { - mSQLiteLog.logPosted(notification); - } } /** @@ -170,9 +165,6 @@ public class NotificationUsageStats { stats.countApiUse(notification); } releaseAggregatedStatsLocked(aggregatedStatsArray); - if (ENABLE_SQLITE_LOG) { - mSQLiteLog.logPosted(notification); - } } /** @@ -185,9 +177,6 @@ public class NotificationUsageStats { stats.numRemovedByApp++; } releaseAggregatedStatsLocked(aggregatedStatsArray); - if (ENABLE_SQLITE_LOG) { - mSQLiteLog.logRemoved(notification); - } } /** @@ -197,9 +186,6 @@ public class NotificationUsageStats { MetricsLogger.histogram(mContext, "note_dismiss_longevity", (int) (System.currentTimeMillis() - notification.getRankingTimeMs()) / (60 * 1000)); notification.stats.onDismiss(); - if (ENABLE_SQLITE_LOG) { - mSQLiteLog.logDismissed(notification); - } } /** @@ -209,9 +195,6 @@ public class NotificationUsageStats { MetricsLogger.histogram(mContext, "note_click_longevity", (int) (System.currentTimeMillis() - notification.getRankingTimeMs()) / (60 * 1000)); notification.stats.onClick(); - if (ENABLE_SQLITE_LOG) { - mSQLiteLog.logClicked(notification); - } } public synchronized void registerPeopleAffinity(NotificationRecord notification, boolean valid, @@ -328,21 +311,18 @@ public class NotificationUsageStats { // pass } } - if (ENABLE_SQLITE_LOG) { - try { - dump.put("historical", mSQLiteLog.dumpJson(filter)); - } catch (JSONException e) { - // pass - } - } return dump; } public PulledStats remoteViewStats(long startMs, boolean aggregate) { - if (ENABLE_SQLITE_LOG) { - if (aggregate) { - return mSQLiteLog.remoteViewAggStats(startMs); + if (ENABLE_AGGREGATED_IN_MEMORY_STATS) { + PulledStats stats = new PulledStats(startMs); + for (AggregatedStats as : mStats.values()) { + if (as.numUndecoratedRemoteViews > 0) { + stats.addUndecoratedPackage(as.key, as.mCreated); + } } + return stats; } return null; } @@ -357,9 +337,6 @@ public class NotificationUsageStats { pw.println(indent + "mStatsArrays.size(): " + mStatsArrays.size()); pw.println(indent + "mStats.size(): " + mStats.size()); } - if (ENABLE_SQLITE_LOG) { - mSQLiteLog.dump(pw, indent, filter); - } } public synchronized void emit() { @@ -1046,353 +1023,4 @@ public class NotificationUsageStats { '}'; } } - - private static class SQLiteLog { - private static final String TAG = "NotificationSQLiteLog"; - - // Message types passed to the background handler. - private static final int MSG_POST = 1; - private static final int MSG_CLICK = 2; - private static final int MSG_REMOVE = 3; - private static final int MSG_DISMISS = 4; - - private static final String DB_NAME = "notification_log.db"; - private static final int DB_VERSION = 7; - - /** Age in ms after which events are pruned from the DB. */ - private static final long HORIZON_MS = 7 * 24 * 60 * 60 * 1000L; // 1 week - /** Delay between pruning the DB. Used to throttle pruning. */ - private static final long PRUNE_MIN_DELAY_MS = 6 * 60 * 60 * 1000L; // 6 hours - /** Mininum number of writes between pruning the DB. Used to throttle pruning. */ - private static final long PRUNE_MIN_WRITES = 1024; - - // Table 'log' - private static final String TAB_LOG = "log"; - private static final String COL_EVENT_USER_ID = "event_user_id"; - private static final String COL_EVENT_TYPE = "event_type"; - private static final String COL_EVENT_TIME = "event_time_ms"; - private static final String COL_KEY = "key"; - private static final String COL_PKG = "pkg"; - private static final String COL_NOTIFICATION_ID = "nid"; - private static final String COL_TAG = "tag"; - private static final String COL_WHEN_MS = "when_ms"; - private static final String COL_DEFAULTS = "defaults"; - private static final String COL_FLAGS = "flags"; - private static final String COL_IMPORTANCE_REQ = "importance_request"; - private static final String COL_IMPORTANCE_FINAL = "importance_final"; - private static final String COL_NOISY = "noisy"; - private static final String COL_MUTED = "muted"; - private static final String COL_DEMOTED = "demoted"; - private static final String COL_CATEGORY = "category"; - private static final String COL_ACTION_COUNT = "action_count"; - private static final String COL_POSTTIME_MS = "posttime_ms"; - private static final String COL_AIRTIME_MS = "airtime_ms"; - private static final String COL_FIRST_EXPANSIONTIME_MS = "first_expansion_time_ms"; - private static final String COL_AIRTIME_EXPANDED_MS = "expansion_airtime_ms"; - private static final String COL_EXPAND_COUNT = "expansion_count"; - private static final String COL_UNDECORATED = "undecorated"; - - - private static final int EVENT_TYPE_POST = 1; - private static final int EVENT_TYPE_CLICK = 2; - private static final int EVENT_TYPE_REMOVE = 3; - private static final int EVENT_TYPE_DISMISS = 4; - - private static final int IDLE_CONNECTION_TIMEOUT_MS = 30000; - - private static long sLastPruneMs; - - private static long sNumWrites; - private final SQLiteOpenHelper mHelper; - - private final Handler mWriteHandler; - private static final long DAY_MS = 24 * 60 * 60 * 1000; - private static final String STATS_QUERY = "SELECT " + - COL_EVENT_USER_ID + ", " + - COL_PKG + ", " + - // Bucket by day by looking at 'floor((midnight - eventTimeMs) / dayMs)' - "CAST(((%d - " + COL_EVENT_TIME + ") / " + DAY_MS + ") AS int) " + - "AS day, " + - "COUNT(*) AS cnt, " + - "SUM(" + COL_MUTED + ") as muted, " + - "SUM(" + COL_NOISY + ") as noisy, " + - "SUM(" + COL_DEMOTED + ") as demoted, " + - "SUM(" + COL_UNDECORATED + ") as undecorated " + - "FROM " + TAB_LOG + " " + - "WHERE " + - COL_EVENT_TYPE + "=" + EVENT_TYPE_POST + - " AND " + COL_EVENT_TIME + " > %d " + - " GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG; - private static final String UNDECORATED_QUERY = "SELECT " + - COL_PKG + ", " + - "MAX(" + COL_EVENT_TIME + ") as max_time " + - "FROM " + TAB_LOG + " " + - "WHERE " + COL_UNDECORATED + "> 0 " + - " AND " + COL_EVENT_TIME + " > %d " + - "GROUP BY " + COL_PKG; - - public SQLiteLog(Context context) { - HandlerThread backgroundThread = new HandlerThread("notification-sqlite-log", - android.os.Process.THREAD_PRIORITY_BACKGROUND); - backgroundThread.start(); - mWriteHandler = new Handler(backgroundThread.getLooper()) { - @Override - public void handleMessage(Message msg) { - NotificationRecord r = (NotificationRecord) msg.obj; - long nowMs = System.currentTimeMillis(); - switch (msg.what) { - case MSG_POST: - writeEvent(r.getSbn().getPostTime(), EVENT_TYPE_POST, r); - break; - case MSG_CLICK: - writeEvent(nowMs, EVENT_TYPE_CLICK, r); - break; - case MSG_REMOVE: - writeEvent(nowMs, EVENT_TYPE_REMOVE, r); - break; - case MSG_DISMISS: - writeEvent(nowMs, EVENT_TYPE_DISMISS, r); - break; - default: - Log.wtf(TAG, "Unknown message type: " + msg.what); - break; - } - } - }; - mHelper = new SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) { - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + TAB_LOG + " (" + - "_id INTEGER PRIMARY KEY AUTOINCREMENT," + - COL_EVENT_USER_ID + " INT," + - COL_EVENT_TYPE + " INT," + - COL_EVENT_TIME + " INT," + - COL_KEY + " TEXT," + - COL_PKG + " TEXT," + - COL_NOTIFICATION_ID + " INT," + - COL_TAG + " TEXT," + - COL_WHEN_MS + " INT," + - COL_DEFAULTS + " INT," + - COL_FLAGS + " INT," + - COL_IMPORTANCE_REQ + " INT," + - COL_IMPORTANCE_FINAL + " INT," + - COL_NOISY + " INT," + - COL_MUTED + " INT," + - COL_DEMOTED + " INT," + - COL_CATEGORY + " TEXT," + - COL_ACTION_COUNT + " INT," + - COL_POSTTIME_MS + " INT," + - COL_AIRTIME_MS + " INT," + - COL_FIRST_EXPANSIONTIME_MS + " INT," + - COL_AIRTIME_EXPANDED_MS + " INT," + - COL_EXPAND_COUNT + " INT," + - COL_UNDECORATED + " INT" + - ")"); - } - - @Override - public void onConfigure(SQLiteDatabase db) { - // Memory optimization - close idle connections after 30s of inactivity - setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - if (oldVersion != newVersion) { - db.execSQL("DROP TABLE IF EXISTS " + TAB_LOG); - onCreate(db); - } - } - }; - } - - public void logPosted(NotificationRecord notification) { - mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_POST, notification)); - } - - public void logClicked(NotificationRecord notification) { - mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_CLICK, notification)); - } - - public void logRemoved(NotificationRecord notification) { - mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_REMOVE, notification)); - } - - public void logDismissed(NotificationRecord notification) { - mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_DISMISS, notification)); - } - - private JSONArray jsonPostFrequencies(DumpFilter filter) throws JSONException { - JSONArray frequencies = new JSONArray(); - SQLiteDatabase db = mHelper.getReadableDatabase(); - long midnight = getMidnightMs(); - String q = String.format(STATS_QUERY, midnight, filter.since); - Cursor cursor = db.rawQuery(q, null); - try { - for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { - int userId = cursor.getInt(0); - String pkg = cursor.getString(1); - if (filter != null && !filter.matches(pkg)) continue; - int day = cursor.getInt(2); - int count = cursor.getInt(3); - int muted = cursor.getInt(4); - int noisy = cursor.getInt(5); - int demoted = cursor.getInt(6); - JSONObject row = new JSONObject(); - row.put("user_id", userId); - row.put("package", pkg); - row.put("day", day); - row.put("count", count); - row.put("noisy", noisy); - row.put("muted", muted); - row.put("demoted", demoted); - frequencies.put(row); - } - } finally { - cursor.close(); - } - return frequencies; - } - - public void printPostFrequencies(PrintWriter pw, String indent, DumpFilter filter) { - SQLiteDatabase db = mHelper.getReadableDatabase(); - long midnight = getMidnightMs(); - String q = String.format(STATS_QUERY, midnight, filter.since); - Cursor cursor = db.rawQuery(q, null); - try { - for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { - int userId = cursor.getInt(0); - String pkg = cursor.getString(1); - if (filter != null && !filter.matches(pkg)) continue; - int day = cursor.getInt(2); - int count = cursor.getInt(3); - int muted = cursor.getInt(4); - int noisy = cursor.getInt(5); - int demoted = cursor.getInt(6); - pw.println(indent + "post_frequency{user_id=" + userId + ",pkg=" + pkg + - ",day=" + day + ",count=" + count + ",muted=" + muted + "/" + noisy + - ",demoted=" + demoted + "}"); - } - } finally { - cursor.close(); - } - } - - private long getMidnightMs() { - GregorianCalendar midnight = new GregorianCalendar(); - midnight.set(midnight.get(Calendar.YEAR), midnight.get(Calendar.MONTH), - midnight.get(Calendar.DATE), 23, 59, 59); - return midnight.getTimeInMillis(); - } - - private void writeEvent(long eventTimeMs, int eventType, NotificationRecord r) { - ContentValues cv = new ContentValues(); - cv.put(COL_EVENT_USER_ID, r.getSbn().getUser().getIdentifier()); - cv.put(COL_EVENT_TIME, eventTimeMs); - cv.put(COL_EVENT_TYPE, eventType); - putNotificationIdentifiers(r, cv); - if (eventType == EVENT_TYPE_POST) { - putNotificationDetails(r, cv); - } else { - putPosttimeVisibility(r, cv); - } - cv.put(COL_UNDECORATED, (r.hasUndecoratedRemoteView() ? 1 : 0)); - SQLiteDatabase db = mHelper.getWritableDatabase(); - if (db.insert(TAB_LOG, null, cv) < 0) { - Log.wtf(TAG, "Error while trying to insert values: " + cv); - } - sNumWrites++; - pruneIfNecessary(db); - } - - private void pruneIfNecessary(SQLiteDatabase db) { - // Prune if we haven't in a while. - long nowMs = System.currentTimeMillis(); - if (sNumWrites > PRUNE_MIN_WRITES || - nowMs - sLastPruneMs > PRUNE_MIN_DELAY_MS) { - sNumWrites = 0; - sLastPruneMs = nowMs; - long horizonStartMs = nowMs - HORIZON_MS; - try { - int deletedRows = db.delete(TAB_LOG, COL_EVENT_TIME + " < ?", - new String[]{String.valueOf(horizonStartMs)}); - Log.d(TAG, "Pruned event entries: " + deletedRows); - } catch (SQLiteFullException e) { - Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); - } - } - } - - private static void putNotificationIdentifiers(NotificationRecord r, ContentValues outCv) { - outCv.put(COL_KEY, r.getSbn().getKey()); - outCv.put(COL_PKG, r.getSbn().getPackageName()); - } - - private static void putNotificationDetails(NotificationRecord r, ContentValues outCv) { - outCv.put(COL_NOTIFICATION_ID, r.getSbn().getId()); - if (r.getSbn().getTag() != null) { - outCv.put(COL_TAG, r.getSbn().getTag()); - } - outCv.put(COL_WHEN_MS, r.getSbn().getPostTime()); - outCv.put(COL_FLAGS, r.getNotification().flags); - final int before = r.stats.requestedImportance; - final int after = r.getImportance(); - final boolean noisy = r.stats.isNoisy; - outCv.put(COL_IMPORTANCE_REQ, before); - outCv.put(COL_IMPORTANCE_FINAL, after); - outCv.put(COL_DEMOTED, after < before ? 1 : 0); - outCv.put(COL_NOISY, noisy); - if (noisy && after < IMPORTANCE_HIGH) { - outCv.put(COL_MUTED, 1); - } else { - outCv.put(COL_MUTED, 0); - } - if (r.getNotification().category != null) { - outCv.put(COL_CATEGORY, r.getNotification().category); - } - outCv.put(COL_ACTION_COUNT, r.getNotification().actions != null ? - r.getNotification().actions.length : 0); - } - - private static void putPosttimeVisibility(NotificationRecord r, ContentValues outCv) { - outCv.put(COL_POSTTIME_MS, r.stats.getCurrentPosttimeMs()); - outCv.put(COL_AIRTIME_MS, r.stats.getCurrentAirtimeMs()); - outCv.put(COL_EXPAND_COUNT, r.stats.userExpansionCount); - outCv.put(COL_AIRTIME_EXPANDED_MS, r.stats.getCurrentAirtimeExpandedMs()); - outCv.put(COL_FIRST_EXPANSIONTIME_MS, r.stats.posttimeToFirstVisibleExpansionMs); - } - - public void dump(PrintWriter pw, String indent, DumpFilter filter) { - printPostFrequencies(pw, indent, filter); - } - - public JSONObject dumpJson(DumpFilter filter) { - JSONObject dump = new JSONObject(); - try { - dump.put("post_frequency", jsonPostFrequencies(filter)); - dump.put("since", filter.since); - dump.put("now", System.currentTimeMillis()); - } catch (JSONException e) { - // pass - } - return dump; - } - - public PulledStats remoteViewAggStats(long startMs) { - PulledStats stats = new PulledStats(startMs); - SQLiteDatabase db = mHelper.getReadableDatabase(); - String q = String.format(UNDECORATED_QUERY, startMs); - Cursor cursor = db.rawQuery(q, null); - try { - for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { - String pkg = cursor.getString(0); - long maxTimeMs = cursor.getLong(1); - stats.addUndecoratedPackage(pkg, maxTimeMs); - } - } finally { - cursor.close(); - } - return stats; - } - } } -- GitLab From 9eb06f996568eb87b888aa03b6b84f9e767645f7 Mon Sep 17 00:00:00 2001 From: Agatha Man Date: Mon, 12 Oct 2020 12:45:41 -0700 Subject: [PATCH 064/382] Remove accidentally added diff file Bug: 169889379 Test: presubmit Change-Id: Ib81ba3288a986546bc570c3759c55d026add591a --- diff | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 diff diff --git a/diff b/diff deleted file mode 100644 index 5c75d88e6789..000000000000 --- a/diff +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java -index fc43882..832dc91 100644 ---- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java -+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java -@@ -67,6 +67,7 @@ import java.util.Arrays; - import java.util.HashSet; - import java.util.List; - import java.util.Set; -+import java.util.NoSuchElementException; - - /** - * This class represents an accessibility client - either an AccessibilityService or a UiAutomation. -@@ -978,7 +979,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ - /* ignore */ - } - if (mService != null) { -- mService.unlinkToDeath(this, 0); -+ try { -+ mService.unlinkToDeath(this, 0); -+ }catch(NoSuchElementException e) { -+ Slog.e(LOG_TAG, "Failed unregistering death link"); -+ } - mService = null; - } - -- GitLab From e81d5f63121dbd26cc4478f00054ad2c5434da96 Mon Sep 17 00:00:00 2001 From: Jay Aliomer Date: Fri, 18 Sep 2020 12:20:52 -0400 Subject: [PATCH 065/382] Rememeber the last dark mode before shutdown when in auto mode Twilight mode is not available when the phone starts. So the last state is rememebered until the phone screen turns off Fixes: 160842085 Test: manual testing Merged-In: I78a490c0f083e92022e1995b3e19dc7dd567a7c3 Change-Id: I78a490c0f083e92022e1995b3e19dc7dd567a7c3 (cherry picked from commit 7bddda48fcc7a13d35b763141806e304fe7c03b3) --- core/java/android/provider/Settings.java | 6 +++ .../android/server/UiModeManagerService.java | 45 ++++++++++++------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index b07dabd4bb39..df1472009353 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7896,6 +7896,12 @@ public final class Settings { */ public static final String UI_NIGHT_MODE_OVERRIDE_ON = "ui_night_mode_override_on"; + /** + * The last computed night mode bool the last time the phone was on + * @hide + */ + public static final String UI_NIGHT_MODE_LAST_COMPUTED = "ui_night_mode_last_computed"; + /** * The current night mode that has been overridden to turn off by the system. Owned * and controlled by UiModeManagerService. Constants are as per diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index daae1a11059c..4ff6dac08b85 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -327,6 +327,13 @@ final class UiModeManagerService extends SystemService { mCurrentUser = userHandle; getContext().getContentResolver().unregisterContentObserver(mSetupWizardObserver); verifySetupWizardCompleted(); + synchronized (mLock) { + // only update if the value is actually changed + if (updateNightModeFromSettingsLocked(getContext(), getContext().getResources(), + mCurrentUser)) { + updateLocked(0, 0); + } + } } @Override @@ -354,11 +361,10 @@ final class UiModeManagerService extends SystemService { new IntentFilter(Intent.ACTION_DOCK_EVENT)); IntentFilter batteryFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); context.registerReceiver(mBatteryReceiver, batteryFilter); - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_USER_SWITCHED); context.registerReceiver(mSettingsRestored, new IntentFilter(Intent.ACTION_SETTING_RESTORED)); - context.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler); + context.registerReceiver(mOnShutdown, + new IntentFilter(Intent.ACTION_SHUTDOWN)); updateConfigurationLocked(); applyConfigurationExternallyLocked(); } @@ -405,6 +411,21 @@ final class UiModeManagerService extends SystemService { publishLocalService(UiModeManagerInternal.class, mLocalService); } + private final BroadcastReceiver mOnShutdown = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (mNightMode == MODE_NIGHT_AUTO) { + persistComputedNightMode(mCurrentUser); + } + } + }; + + private void persistComputedNightMode(int userId) { + Secure.putIntForUser(getContext().getContentResolver(), + Secure.UI_NIGHT_MODE_LAST_COMPUTED, mComputedNightMode ? 1 : 0, + userId); + } + private final BroadcastReceiver mSettingsRestored = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -506,6 +527,10 @@ final class UiModeManagerService extends SystemService { Secure.getLongForUser(context.getContentResolver(), Secure.DARK_THEME_CUSTOM_END_TIME, DEFAULT_CUSTOM_NIGHT_END_TIME.toNanoOfDay() / 1000L, userId) * 1000); + if (mNightMode == MODE_NIGHT_AUTO) { + mComputedNightMode = Secure.getIntForUser(context.getContentResolver(), + Secure.UI_NIGHT_MODE_LAST_COMPUTED, 0, userId) != 0; + } } return oldNightMode != mNightMode; @@ -1596,18 +1621,4 @@ final class UiModeManagerService extends SystemService { } } } - - private final class UserSwitchedReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - synchronized (mLock) { - final int currentId = intent.getIntExtra( - Intent.EXTRA_USER_HANDLE, USER_SYSTEM); - // only update if the value is actually changed - if (updateNightModeFromSettingsLocked(context, context.getResources(), currentId)) { - updateLocked(0, 0); - } - } - } - } } -- GitLab From 12dacb460037e290c606eae214116c8d6ccac4d4 Mon Sep 17 00:00:00 2001 From: Jay Aliomer Date: Tue, 29 Sep 2020 13:50:42 -0400 Subject: [PATCH 066/382] Typo in the sand icon shape a typo in the sand style shape results in the style not applying Fixes: 169674631 Test: manual Change-Id: Ib2c8509d9128879b5233795039bb5560a771b422 (cherry picked from commit 4ecf0d3793f0e0e2d49b0a1f5655d6614647e5e2) --- packages/overlays/IconShapePebbleOverlay/res/values/config.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/overlays/IconShapePebbleOverlay/res/values/config.xml b/packages/overlays/IconShapePebbleOverlay/res/values/config.xml index 2465fe015538..e7eeb30501b5 100644 --- a/packages/overlays/IconShapePebbleOverlay/res/values/config.xml +++ b/packages/overlays/IconShapePebbleOverlay/res/values/config.xml @@ -18,7 +18,7 @@ --> - "MM55,0 C25,0 0,25 0,50 0,78 28,100 55,100 85,100 100,85 100,58 100,30 86,0 55,0 Z" + "M55,0 C25,0 0,25 0,50 0,78 28,100 55,100 85,100 100,85 100,58 100,30 86,0 55,0 Z" false -- GitLab From c947b10f996a381eb3dfa5cfacb353e87da86d31 Mon Sep 17 00:00:00 2001 From: Charles Chen Date: Tue, 13 Oct 2020 01:14:25 +0000 Subject: [PATCH 067/382] [RESTRICT AUTOMERGE] Revert "[RESTRICT AUTOMERGE] Revert "Require permission to create trusted displays"" This reverts commit ae03031efe8b751f4513b42cad68db4559a8edfd. Reason for revert: Merge the reverted patch by accident. Bug: 162627132 Change-Id: Ic2f072730050cb47926cec6ed24af7ef9e5e7055 --- core/java/android/app/ActivityView.java | 15 +++++++++++++-- .../window/VirtualDisplayTaskEmbedder.java | 9 ++++++++- core/tests/coretests/AndroidManifest.xml | 1 + .../hardware/display/VirtualDisplayTest.java | 19 +++++++++++++++++++ .../systemui/bubbles/BubbleExpandedView.java | 2 +- .../server/display/DisplayManagerService.java | 15 +++++++++++---- 6 files changed, 53 insertions(+), 8 deletions(-) diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 98a23f2b0075..3cb6293f0706 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -105,7 +105,8 @@ public class ActivityView extends ViewGroup implements android.window.TaskEmbedd public ActivityView( @NonNull Context context, @NonNull AttributeSet attrs, int defStyle, boolean singleTaskInstance, boolean usePublicVirtualDisplay) { - this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay, false); + this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay, + false /* disableSurfaceViewBackgroundLayer */); } /** @hide */ @@ -113,12 +114,22 @@ public class ActivityView extends ViewGroup implements android.window.TaskEmbedd @NonNull Context context, @NonNull AttributeSet attrs, int defStyle, boolean singleTaskInstance, boolean usePublicVirtualDisplay, boolean disableSurfaceViewBackgroundLayer) { + this(context, attrs, defStyle, singleTaskInstance, usePublicVirtualDisplay, + disableSurfaceViewBackgroundLayer, false /* useTrustedDisplay */); + } + + // TODO(b/162901735): Refactor ActivityView with Builder + /** @hide */ + public ActivityView( + @NonNull Context context, @NonNull AttributeSet attrs, int defStyle, + boolean singleTaskInstance, boolean usePublicVirtualDisplay, + boolean disableSurfaceViewBackgroundLayer, boolean useTrustedDisplay) { super(context, attrs, defStyle); if (useTaskOrganizer()) { mTaskEmbedder = new TaskOrganizerTaskEmbedder(context, this); } else { mTaskEmbedder = new VirtualDisplayTaskEmbedder(context, this, singleTaskInstance, - usePublicVirtualDisplay); + usePublicVirtualDisplay, useTrustedDisplay); } mSurfaceView = new SurfaceView(context, null, 0, 0, disableSurfaceViewBackgroundLayer); // Since ActivityView#getAlpha has been overridden, we should use parent class's alpha diff --git a/core/java/android/window/VirtualDisplayTaskEmbedder.java b/core/java/android/window/VirtualDisplayTaskEmbedder.java index 9ccb4c172158..9013da36007e 100644 --- a/core/java/android/window/VirtualDisplayTaskEmbedder.java +++ b/core/java/android/window/VirtualDisplayTaskEmbedder.java @@ -19,6 +19,7 @@ package android.window; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; import static android.view.Display.INVALID_DISPLAY; import android.app.ActivityManager; @@ -63,6 +64,7 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { private int mDisplayDensityDpi; private final boolean mSingleTaskInstance; private final boolean mUsePublicVirtualDisplay; + private final boolean mUseTrustedDisplay; private VirtualDisplay mVirtualDisplay; private Insets mForwardedInsets; private DisplayMetrics mTmpDisplayMetrics; @@ -77,10 +79,12 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { * only applicable if virtual displays are used */ public VirtualDisplayTaskEmbedder(Context context, VirtualDisplayTaskEmbedder.Host host, - boolean singleTaskInstance, boolean usePublicVirtualDisplay) { + boolean singleTaskInstance, boolean usePublicVirtualDisplay, + boolean useTrustedDisplay) { super(context, host); mSingleTaskInstance = singleTaskInstance; mUsePublicVirtualDisplay = usePublicVirtualDisplay; + mUseTrustedDisplay = useTrustedDisplay; } /** @@ -103,6 +107,9 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder { if (mUsePublicVirtualDisplay) { virtualDisplayFlags |= VIRTUAL_DISPLAY_FLAG_PUBLIC; } + if (mUseTrustedDisplay) { + virtualDisplayFlags |= VIRTUAL_DISPLAY_FLAG_TRUSTED; + } mVirtualDisplay = displayManager.createVirtualDisplay( DISPLAY_NAME + "@" + System.identityHashCode(this), mHost.getWidth(), diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index 5c2841aff1d8..7597e8732153 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -129,6 +129,7 @@ + diff --git a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java index daf613976358..0f6284d22d10 100644 --- a/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java +++ b/core/tests/coretests/src/android/hardware/display/VirtualDisplayTest.java @@ -247,6 +247,25 @@ public class VirtualDisplayTest extends AndroidTestCase { assertDisplayUnregistered(display); } + /** + * Ensures that an application can create a trusted virtual display with the permission + * {@code ADD_TRUSTED_DISPLAY}. + */ + public void testTrustedVirtualDisplay() throws Exception { + VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(NAME, + WIDTH, HEIGHT, DENSITY, mSurface, + DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED); + assertNotNull("virtual display must not be null", virtualDisplay); + + Display display = virtualDisplay.getDisplay(); + try { + assertDisplayRegistered(display, Display.FLAG_PRIVATE | Display.FLAG_TRUSTED); + } finally { + virtualDisplay.release(); + } + assertDisplayUnregistered(display); + } + private void assertDisplayRegistered(Display display, int flags) { assertNotNull("display object must not be null", display); assertTrue("display must be valid", display.isValid()); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index 3d3171208b15..110a5ab67f0d 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -301,7 +301,7 @@ public class BubbleExpandedView extends LinearLayout { mActivityView = new ActivityView(mContext, null /* attrs */, 0 /* defStyle */, true /* singleTaskInstance */, false /* usePublicVirtualDisplay*/, - true /* disableSurfaceViewBackgroundLayer */); + true /* disableSurfaceViewBackgroundLayer */, true /* useTrustedDisplay */); // Set ActivityView's alpha value as zero, since there is no view content to be shown. setContentVisibility(false); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 1058000e0b68..9a8be287690f 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -86,6 +86,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.text.TextUtils; +import android.util.EventLog; import android.util.IntArray; import android.util.Pair; import android.util.Slog; @@ -2191,10 +2192,16 @@ public final class DisplayManagerService extends SystemService { } } - if (callingUid == Process.SYSTEM_UID - || checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) { - flags |= VIRTUAL_DISPLAY_FLAG_TRUSTED; - } else { + if (callingUid != Process.SYSTEM_UID && (flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) { + if (!checkCallingPermission(ADD_TRUSTED_DISPLAY, "createVirtualDisplay()")) { + EventLog.writeEvent(0x534e4554, "162627132", callingUid, + "Attempt to create a trusted display without holding permission!"); + throw new SecurityException("Requires ADD_TRUSTED_DISPLAY permission to " + + "create a trusted virtual display."); + } + } + + if ((flags & VIRTUAL_DISPLAY_FLAG_TRUSTED) == 0) { flags &= ~VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; } -- GitLab From bf402bd69882538acacc42baec09d8f95c53a2f7 Mon Sep 17 00:00:00 2001 From: ryanlwlin Date: Thu, 27 Aug 2020 18:58:24 +0800 Subject: [PATCH 068/382] [DO NOT MERGE] Fix Accidently trigger A11y button long pressed We used the original down location while injecting all down events. It accidently increases the velocity in the beginning and cause Launcher detect the gesture into unexpected state. Test: manually Bug: 162521649 Change-Id: I527f3e785ee1082f86ef1a60e57ccd825bdfeae9 --- .../server/accessibility/gestures/EventDispatcher.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java index c70dfcc93e49..a4fec82bcf56 100644 --- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java +++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java @@ -287,7 +287,9 @@ class EventDispatcher { /** * Sends down events to the view hierarchy for all pointers which are not already being - * delivered with original down location. i.e. pointers that are not yet injected. + * delivered with original down location. i.e. pointers that are not yet injected. The down time + * is also replaced by the original one. + * * * @param prototype The prototype from which to create the injected events. * @param policyFlags The policy flags associated with the event. @@ -336,7 +338,10 @@ class EventDispatcher { MotionEvent event = MotionEvent.obtain( prototype.getDownTime(), - prototype.getEventTime(), + // The event time is used for downTime while sending ACTION_DOWN. We adjust + // it to avoid the motion velocity is too fast in the beginning after + // Delegating. + prototype.getDownTime(), prototype.getAction(), pointerCount, properties, -- GitLab From 0295f94356b40d4582a12dd061160d97f216b473 Mon Sep 17 00:00:00 2001 From: Ameer Armaly Date: Thu, 8 Oct 2020 08:25:00 -0700 Subject: [PATCH 069/382] [DO NOT MERGE ] Stop setting flag to enable two-finger passthrough swipes. Bug: 162521649 Test: atest GestureManifoldTest TouchExplorerTest AccessibilityGestureDetectorTest FrameworksServicesTests:TouchExplorerTest Change-Id: I7718ac2ae86d46aa05d45a1ac3abc556e000e39d --- .../android/accessibilityservice/AccessibilityServiceInfo.java | 1 - .../server/accessibility/gestures/TouchExplorerTest.java | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index d334de60713a..a41fa6431d4d 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -636,7 +636,6 @@ public class AccessibilityServiceInfo implements Parcelable { 0); flags = asAttributes.getInt( com.android.internal.R.styleable.AccessibilityService_accessibilityFlags, 0); - flags |= FLAG_REQUEST_2_FINGER_PASSTHROUGH; mSettingsActivityName = asAttributes.getString( com.android.internal.R.styleable.AccessibilityService_settingsActivity); if (asAttributes.getBoolean(com.android.internal.R.styleable diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java index f929321a61be..c18cad42b494 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java @@ -162,7 +162,7 @@ public class TouchExplorerTest { goFromStateClearTo(STATE_DRAGGING_2FINGERS); assertState(STATE_DRAGGING); - assertCapturedEvents(MotionEvent.ACTION_DOWN); + assertCapturedEvents(MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE); assertCapturedEventsNoHistory(); } @@ -174,6 +174,7 @@ public class TouchExplorerTest { assertState(STATE_DELEGATING); assertCapturedEvents( /* goto dragging state */ MotionEvent.ACTION_DOWN, + MotionEvent.ACTION_MOVE, /* leave dragging state */ MotionEvent.ACTION_UP, MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN); -- GitLab From fb21535b26a7ae93e860050d4f3cfaf9f29c3699 Mon Sep 17 00:00:00 2001 From: Jeff DeCew Date: Mon, 12 Oct 2020 14:11:22 -0400 Subject: [PATCH 070/382] Notifications starting paused shall still be subject to timeout. Bug: 169271494 Test: manual Change-Id: Iebb4f113d73179d7314ae1c6db3856ee0fd10b07 Merged-In: Iebb4f113d73179d7314ae1c6db3856ee0fd10b07 --- .../com/android/systemui/media/MediaTimeoutListener.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt index dcb7767a680a..63a361de4d87 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt @@ -46,7 +46,7 @@ class MediaTimeoutListener @Inject constructor( /** * Callback representing that a media object is now expired: * @param token Media session unique identifier - * @param pauseTimeuot True when expired for {@code PAUSED_MEDIA_TIMEOUT} + * @param pauseTimeout True when expired for {@code PAUSED_MEDIA_TIMEOUT} */ lateinit var timeoutCallback: (String, Boolean) -> Unit @@ -57,11 +57,10 @@ class MediaTimeoutListener @Inject constructor( // Having an old key means that we're migrating from/to resumption. We should update // the old listener to make sure that events will be dispatched to the new location. val migrating = oldKey != null && key != oldKey - var wasPlaying = false if (migrating) { val reusedListener = mediaListeners.remove(oldKey) if (reusedListener != null) { - wasPlaying = reusedListener.playing ?: false + val wasPlaying = reusedListener.playing ?: false if (DEBUG) Log.d(TAG, "migrating key $oldKey to $key, for resumption") reusedListener.mediaData = data reusedListener.key = key @@ -159,9 +158,8 @@ class MediaTimeoutListener @Inject constructor( Log.v(TAG, "Execute timeout for $key") } timedOut = true - if (dispatchEvents) { - timeoutCallback(key, timedOut) - } + // this event is async, so it's safe even when `dispatchEvents` is false + timeoutCallback(key, timedOut) }, PAUSED_MEDIA_TIMEOUT) } else { expireMediaTimeout(key, "playback started - $state, $key") -- GitLab From a49a320e4935f4ffbea0dc31448b90adcac45730 Mon Sep 17 00:00:00 2001 From: Jeff DeCew Date: Mon, 12 Oct 2020 16:34:55 -0400 Subject: [PATCH 071/382] Disable player's "Dismiss" button when notification is not dismissible. Bug: 169271494 Test: manual Change-Id: I3c2a73e4885642965ec553387b5e91f0cb16ff2f Merged-In: I3c2a73e4885642965ec553387b5e91f0cb16ff2f --- packages/SystemUI/res/values/strings.xml | 2 ++ .../systemui/media/MediaControlPanel.java | 8 +++++++ .../systemui/media/PlayerViewHolder.kt | 4 +++- .../systemui/media/MediaControlPanelTest.kt | 23 +++++++++++++++++-- 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 77ce39fe9953..95de4860ddfa 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2820,6 +2820,8 @@ Media Hide the current session. + + Current session cannot be hidden. Dismiss diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index 810cecca517f..d853e3d4a57c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -359,7 +359,15 @@ public class MediaControlPanel { final MediaController controller = getController(); mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller)); + // Guts label + boolean isDismissible = data.isClearable(); + mViewHolder.getSettingsText().setText(isDismissible + ? R.string.controls_media_close_session + : R.string.controls_media_active_session); + // Dismiss + mViewHolder.getDismissLabel().setAlpha(isDismissible ? 1 : DISABLED_ALPHA); + mViewHolder.getDismiss().setEnabled(isDismissible); mViewHolder.getDismiss().setOnClickListener(v -> { if (mKey != null) { closeGuts(); diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt index 666a6038a8b6..16327bd9064a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt @@ -60,8 +60,10 @@ class PlayerViewHolder private constructor(itemView: View) { val action4 = itemView.requireViewById(R.id.action4) // Settings screen + val settingsText = itemView.requireViewById(R.id.remove_text) val cancel = itemView.requireViewById(R.id.cancel) - val dismiss = itemView.requireViewById(R.id.dismiss) + val dismiss = itemView.requireViewById(R.id.dismiss) + val dismissLabel = dismiss.getChildAt(0) val settings = itemView.requireViewById(R.id.settings) init { diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt index 81139f192070..ad703614fdb4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt @@ -109,9 +109,11 @@ public class MediaControlPanelTest : SysuiTestCase() { private lateinit var action2: ImageButton private lateinit var action3: ImageButton private lateinit var action4: ImageButton + private lateinit var settingsText: TextView private lateinit var settings: View private lateinit var cancel: View - private lateinit var dismiss: View + private lateinit var dismiss: FrameLayout + private lateinit var dismissLabel: View private lateinit var session: MediaSession private val device = MediaDeviceData(true, null, DEVICE_NAME) @@ -168,12 +170,16 @@ public class MediaControlPanelTest : SysuiTestCase() { whenever(holder.action3).thenReturn(action3) action4 = ImageButton(context) whenever(holder.action4).thenReturn(action4) + settingsText = TextView(context) + whenever(holder.settingsText).thenReturn(settingsText) settings = View(context) whenever(holder.settings).thenReturn(settings) cancel = View(context) whenever(holder.cancel).thenReturn(cancel) - dismiss = View(context) + dismiss = FrameLayout(context) whenever(holder.dismiss).thenReturn(dismiss) + dismissLabel = View(context) + whenever(holder.dismissLabel).thenReturn(dismissLabel) // Create media session val metadataBuilder = MediaMetadata.Builder().apply { @@ -327,6 +333,7 @@ public class MediaControlPanelTest : SysuiTestCase() { notificationKey = KEY) player.bind(state, mediaKey) + assertThat(dismiss.isEnabled).isEqualTo(true) dismiss.callOnClick() val captor = ArgumentCaptor.forClass(ActivityStarter.OnDismissAction::class.java) verify(keyguardDismissUtil).executeWhenUnlocked(captor.capture(), anyBoolean()) @@ -334,4 +341,16 @@ public class MediaControlPanelTest : SysuiTestCase() { captor.value.onDismiss() verify(mediaDataManager).dismissMediaData(eq(mediaKey), anyLong()) } + + @Test + fun dismissButtonDisabled() { + val mediaKey = "key for dismissal" + player.attach(holder) + val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), + emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null, + isClearable = false, notificationKey = KEY) + player.bind(state, mediaKey) + + assertThat(dismiss.isEnabled).isEqualTo(false) + } } -- GitLab From 427bdc1c86904649dc7c12cf917c05d61f2fe3fa Mon Sep 17 00:00:00 2001 From: Tiger Huang Date: Wed, 14 Oct 2020 11:40:09 +0000 Subject: [PATCH 072/382] DO NOT MERGE: Revert "Don't let IME window fit status bar" This reverts commit 3cd311415ba00d5d75660a8607d1ece5e68f0534. Reason for revert: The CL causes the regression b/170474494 And it also makes status bar color incorrect while FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is cleared Fix: 170474494 Change-Id: I26bed08456197721d07f2fab563be0c54e43efd2 --- .../InputMethodService.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index e0195e4eafc1..4f0c84e586a2 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -16,11 +16,11 @@ package android.inputmethodservice; -import static android.graphics.Color.TRANSPARENT; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; import static android.view.WindowInsets.Type.navigationBars; +import static android.view.WindowInsets.Type.statusBars; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; import static java.lang.annotation.RetentionPolicy.SOURCE; @@ -69,6 +69,7 @@ import android.view.ViewGroup; import android.view.ViewRootImpl; import android.view.ViewTreeObserver; import android.view.Window; +import android.view.WindowInsets; import android.view.WindowInsets.Side; import android.view.WindowManager; import android.view.animation.AnimationUtils; @@ -1202,22 +1203,25 @@ public class InputMethodService extends AbstractInputMethodService { Context.LAYOUT_INFLATER_SERVICE); mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState, WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false); - mWindow.getWindow().getAttributes().setFitInsetsTypes(navigationBars()); + mWindow.getWindow().getAttributes().setFitInsetsTypes(statusBars() | navigationBars()); mWindow.getWindow().getAttributes().setFitInsetsSides(Side.all() & ~Side.BOTTOM); mWindow.getWindow().getAttributes().setFitInsetsIgnoringVisibility(true); - // Our window will extend into the status bar area no matter the bar is visible or not. - // We don't want the ColorView to be visible when status bar is shown. - mWindow.getWindow().setStatusBarColor(TRANSPARENT); - - // Automotive devices may request the navigation bar to be hidden when the IME shows up - // (controlled via config_automotiveHideNavBarForKeyboard) in order to maximize the visible - // screen real estate. When this happens, the IME window should animate from the bottom of - // the screen to reduce the jank that happens from the lack of synchronization between the - // bottom system window and the IME window. + // IME layout should always be inset by navigation bar, no matter its current visibility, + // unless automotive requests it. Automotive devices may request the navigation bar to be + // hidden when the IME shows up (controlled via config_automotiveHideNavBarForKeyboard) + // in order to maximize the visible screen real estate. When this happens, the IME window + // should animate from the bottom of the screen to reduce the jank that happens from the + // lack of synchronization between the bottom system window and the IME window. if (mIsAutomotive && mAutomotiveHideNavBarForKeyboard) { mWindow.getWindow().setDecorFitsSystemWindows(false); } + mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener( + (v, insets) -> v.onApplyWindowInsets( + new WindowInsets.Builder(insets).setInsets( + navigationBars(), + insets.getInsetsIgnoringVisibility(navigationBars())) + .build())); // For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set // by default (but IME developers can opt this out later if they want a new behavior). -- GitLab From 1d50760050a7c4e819d5a25d074dfaca04e68fde Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Thu, 8 Oct 2020 10:14:05 -0700 Subject: [PATCH 073/382] remove sensitive pii from safetynet logging Bug: 159145361 Test: manual Change-Id: I8f1be55971672c7e8f5aa8848f65b1b9d9f40fb5 Merged-In: I8f1be55971672c7e8f5aa8848f65b1b9d9f40fb5 (cherry picked from commit 3b6905bf6a39de7789f93a7ce6ca5d65a3fe589e) --- .../src/com/android/systemui/SlicePermissionActivity.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java index 1b241b743242..57e656827f1c 100644 --- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java @@ -106,9 +106,7 @@ public class SlicePermissionActivity extends Activity implements OnClickListener final String providerPkg = getIntent().getStringExtra(SliceProvider.EXTRA_PROVIDER_PKG); if (providerPkg == null || mProviderPkg.equals(providerPkg)) return; final String callingPkg = getCallingPkg(); - EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg), String.format( - "pkg %s (disguised as %s) attempted to request permission to show %s slices in %s", - callingPkg, providerPkg, mProviderPkg, mCallingPkg)); + EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg)); } @Nullable -- GitLab From efa3c1fcca0807531ed5ed80d14dd6f716f9d881 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Thu, 8 Oct 2020 10:14:05 -0700 Subject: [PATCH 074/382] remove sensitive pii from safetynet logging Bug: 159145361 Test: manual Change-Id: I8f1be55971672c7e8f5aa8848f65b1b9d9f40fb5 Merged-In: I8f1be55971672c7e8f5aa8848f65b1b9d9f40fb5 (cherry picked from commit 3b6905bf6a39de7789f93a7ce6ca5d65a3fe589e) --- .../src/com/android/systemui/SlicePermissionActivity.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java index 2365f128532e..47adffc216a5 100644 --- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java @@ -111,9 +111,7 @@ public class SlicePermissionActivity extends Activity implements OnClickListener final String providerPkg = getIntent().getStringExtra("provider_pkg"); if (providerPkg == null || mProviderPkg.equals(providerPkg)) return; final String callingPkg = getCallingPkg(); - EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg), String.format( - "pkg %s (disguised as %s) attempted to request permission to show %s slices in %s", - callingPkg, providerPkg, mProviderPkg, mCallingPkg)); + EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg)); } @Nullable -- GitLab From 6d0599f07e4a496627cfaa714df7f4dfb6f77ec3 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Thu, 8 Oct 2020 10:14:05 -0700 Subject: [PATCH 075/382] remove sensitive pii from safetynet logging Bug: 159145361 Test: manual Change-Id: I8f1be55971672c7e8f5aa8848f65b1b9d9f40fb5 Merged-In: I8f1be55971672c7e8f5aa8848f65b1b9d9f40fb5 (cherry picked from commit 3b6905bf6a39de7789f93a7ce6ca5d65a3fe589e) --- .../src/com/android/systemui/SlicePermissionActivity.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java index 2365f128532e..47adffc216a5 100644 --- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java @@ -111,9 +111,7 @@ public class SlicePermissionActivity extends Activity implements OnClickListener final String providerPkg = getIntent().getStringExtra("provider_pkg"); if (providerPkg == null || mProviderPkg.equals(providerPkg)) return; final String callingPkg = getCallingPkg(); - EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg), String.format( - "pkg %s (disguised as %s) attempted to request permission to show %s slices in %s", - callingPkg, providerPkg, mProviderPkg, mCallingPkg)); + EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg)); } @Nullable -- GitLab From 391c14341808227cbc848e80d29a2636ab877737 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Thu, 8 Oct 2020 10:14:05 -0700 Subject: [PATCH 076/382] remove sensitive pii from safetynet logging Bug: 159145361 Test: manual Change-Id: I8f1be55971672c7e8f5aa8848f65b1b9d9f40fb5 Merged-In: I8f1be55971672c7e8f5aa8848f65b1b9d9f40fb5 (cherry picked from commit 3b6905bf6a39de7789f93a7ce6ca5d65a3fe589e) --- .../src/com/android/systemui/SlicePermissionActivity.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java index 2365f128532e..47adffc216a5 100644 --- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java @@ -111,9 +111,7 @@ public class SlicePermissionActivity extends Activity implements OnClickListener final String providerPkg = getIntent().getStringExtra("provider_pkg"); if (providerPkg == null || mProviderPkg.equals(providerPkg)) return; final String callingPkg = getCallingPkg(); - EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg), String.format( - "pkg %s (disguised as %s) attempted to request permission to show %s slices in %s", - callingPkg, providerPkg, mProviderPkg, mCallingPkg)); + EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg)); } @Nullable -- GitLab From 6d9794aa9ff786f98252d859b8a1de7429f5441a Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Thu, 8 Oct 2020 10:14:05 -0700 Subject: [PATCH 077/382] remove sensitive pii from safetynet logging Bug: 159145361 Test: manual Change-Id: I8f1be55971672c7e8f5aa8848f65b1b9d9f40fb5 Merged-In: I8f1be55971672c7e8f5aa8848f65b1b9d9f40fb5 (cherry picked from commit 3b6905bf6a39de7789f93a7ce6ca5d65a3fe589e) --- .../src/com/android/systemui/SlicePermissionActivity.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java index 8e92818db083..2cba7405a018 100644 --- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java @@ -101,9 +101,7 @@ public class SlicePermissionActivity extends Activity implements OnClickListener final String providerPkg = getIntent().getStringExtra("provider_pkg"); if (providerPkg == null || mProviderPkg.equals(providerPkg)) return; final String callingPkg = getCallingPkg(); - EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg), String.format( - "pkg %s (disguised as %s) attempted to request permission to show %s slices in %s", - callingPkg, providerPkg, mProviderPkg, mCallingPkg)); + EventLog.writeEvent(0x534e4554, "159145361", getUid(callingPkg)); } @Nullable -- GitLab From d5726423ca08fcfb6af0c4392d286b072c34b2a6 Mon Sep 17 00:00:00 2001 From: Mark Goldstein Date: Tue, 13 Oct 2020 20:41:32 +0000 Subject: [PATCH 078/382] Doc: Fix typo the right way. Supersedes cl/318172931 Bug: 170764224 Change-Id: Iaef1aa4fd3143e6e9019d06834001b3bfa3d887d Exempt-from-owner-approval: Docs-only typo fix --- core/java/android/view/accessibility/AccessibilityEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index 3b8368380dda..9d66a21848db 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -199,7 +199,7 @@ import java.util.List; * Window state changed - represents the event of a change to a section of * the user interface that is visually distinct. Should be sent from either the * root view of a window or from a view that is marked as a pane - * {@link android.view.View#setAccessibilityPaneTitle(CharSequence)}. Not that changes + * {@link android.view.View#setAccessibilityPaneTitle(CharSequence)}. Note that changes * to true windows are represented by {@link #TYPE_WINDOWS_CHANGED}.
* Type: {@link #TYPE_WINDOW_STATE_CHANGED}
* Properties:
-- GitLab From 762f34000cc2d0c6edd3aed0daa1514837d7881c Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Mon, 12 Oct 2020 19:03:35 +0800 Subject: [PATCH 079/382] Ignore orientation from invisible non-activity window This restores the orientation condition as in Q. Otherwise the display orientation may still be controlled by an invisible overlay window (e.g. its root view has set View.GONE) . Bug: 169468732 Test: DisplayAreaTest#testGetOrientation Change-Id: I517be9fb135eeb69722054e6191ef500f2f47da9 Merged-In: I517be9fb135eeb69722054e6191ef500f2f47da9 (cherry picked from commit 4136db264624a343d92c818efb8453a2a5f0852a) --- .../com/android/server/wm/DisplayArea.java | 4 ++ .../android/server/wm/WindowContainer.java | 3 +- .../android/server/wm/DisplayAreaTest.java | 43 +++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java index 2be3acc52058..fa2a42e72054 100644 --- a/services/core/java/com/android/server/wm/DisplayArea.java +++ b/services/core/java/com/android/server/wm/DisplayArea.java @@ -200,6 +200,9 @@ public class DisplayArea extends WindowContainer { Comparator.comparingInt(WindowToken::getWindowLayerFromType); private final Predicate mGetOrientingWindow = w -> { + if (!w.isVisible() || !w.mLegacyPolicyVisibilityAfterAnim) { + return false; + } final WindowManagerPolicy policy = mWmService.mPolicy; if (policy.isKeyguardHostWindow(w.mAttrs)) { if (mWmService.mKeyguardGoingAway) { @@ -235,6 +238,7 @@ public class DisplayArea extends WindowContainer { @Override int getOrientation(int candidate) { + mLastOrientationSource = null; // Find a window requesting orientation. final WindowState win = getWindow(mGetOrientingWindow); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 0ade5867d059..dd5afdd4f2b9 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -2555,8 +2555,9 @@ class WindowContainer extends ConfigurationContainer< pw.print(prefix); pw.println("ContainerAnimator:"); mSurfaceAnimator.dump(pw, prefix + " "); } - if (mLastOrientationSource != null) { + if (mLastOrientationSource != null && this == mDisplayContent) { pw.println(prefix + "mLastOrientationSource=" + mLastOrientationSource); + pw.println(prefix + "deepestLastOrientationSource=" + getLastOrientationSource()); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java index 880c486c15af..d42ab72a22b7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java @@ -20,6 +20,9 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS; import static com.android.server.wm.DisplayArea.Type.ANY; import static com.android.server.wm.DisplayArea.Type.BELOW_TASKS; @@ -29,11 +32,15 @@ import static com.android.server.wm.DisplayArea.Type.typeOf; import static com.android.server.wm.testing.Assert.assertThrows; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; +import android.content.pm.ActivityInfo; import android.os.Binder; import android.platform.test.annotations.Presubmit; import android.view.SurfaceControl; +import android.view.View; +import android.view.WindowManager; import org.junit.Rule; import org.junit.Test; @@ -97,6 +104,42 @@ public class DisplayAreaTest { assertThrows(IllegalStateException.class, () -> checkChild(BELOW_TASKS, ANY)); } + + @Test + public void testGetOrientation() { + final DisplayArea.Tokens area = new DisplayArea.Tokens(mWmsRule.getWindowManagerService(), + ABOVE_TASKS, "test"); + final WindowToken token = createWindowToken(TYPE_APPLICATION_OVERLAY); + spyOn(token); + doReturn(mock(DisplayContent.class)).when(token).getDisplayContent(); + doNothing().when(token).setParent(any()); + final WindowState win = createWindowState(token); + spyOn(win); + doNothing().when(win).setParent(any()); + win.mAttrs.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; + token.addChild(win, 0); + area.addChild(token); + + doReturn(true).when(win).isVisible(); + + assertEquals("Visible window can request orientation", + ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, + area.getOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR)); + + doReturn(false).when(win).isVisible(); + + assertEquals("Invisible window cannot request orientation", + ActivityInfo.SCREEN_ORIENTATION_NOSENSOR, + area.getOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR)); + } + + private WindowState createWindowState(WindowToken token) { + return new WindowState(mWmsRule.getWindowManagerService(), mock(Session.class), + new TestIWindow(), token, null /* parentWindow */, 0 /* appOp */, 0 /* seq*/, + new WindowManager.LayoutParams(), View.VISIBLE, 0 /* ownerId */, 0 /* showUserId */, + false /* ownerCanAddInternalSystemWindow */, null); + } + private WindowToken createWindowToken(int type) { return new WindowToken(mWmsRule.getWindowManagerService(), new Binder(), type, false /* persist */, null /* displayContent */, -- GitLab From 47994f37433e5f3e6f4522403e645ff0826e77ba Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Thu, 13 Aug 2020 19:40:13 +0100 Subject: [PATCH 080/382] Make framework-res dep in stubs explicit The android.jar stubs includes the resource from framework-res. This dependency was previously added implicitly inside the build system, but using a java_genrule we can add it directly, which makes it easier to make changes to this rule. This change has the side-effect of adding the resources to some stubs that did not previously include the resources (e.g. module-libs), which I think is desired. Bug: 161214753 Test: build sdk, diff out/dist before and after (shows resources added to some stubs) Change-Id: I1829789af207cc45c49c0c68369fc7c0c085bcb0 Merged-In: I1829789af207cc45c49c0c68369fc7c0c085bcb0 --- StubLibraries.bp | 3 +++ core/res/Android.bp | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/StubLibraries.bp b/StubLibraries.bp index ef4e202fdfe2..3eb482dc5dc5 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -305,6 +305,9 @@ droidstubs { java_defaults { name: "android_defaults_stubs_current", libs: [ "stub-annotations" ], + static_libs: [ + "framework-res-package-jar", // Export package of framework-res + ], errorprone: { javacflags: [ "-XepDisableAllChecks", diff --git a/core/res/Android.bp b/core/res/Android.bp index b365de4f4630..f94a2b08e6c3 100644 --- a/core/res/Android.bp +++ b/core/res/Android.bp @@ -46,6 +46,13 @@ android_app { }, } +java_genrule { + name: "framework-res-package-jar", + srcs: [":framework-res{.export-package.apk}"], + out: ["framework-res-package.jar"], + cmd: "cp $(in) $(out)", +} + // This logic can be removed once robolectric's transition to binary resources is complete filegroup { name: "robolectric_framework_raw_res_files", -- GitLab From 9dc721018f096a4a13372436b9830b7352ecc8ce Mon Sep 17 00:00:00 2001 From: Beverly Date: Thu, 15 Oct 2020 14:21:49 -0400 Subject: [PATCH 081/382] Update ranking for uninflated updated notifs Also updates notif pipeline filter name: IsDozingFilter => DndSuppressVisualEffectsFilter. Fixes: 170386608 Test: atest NotificationEntryManagerTest Test: manual 1. Turn on DND with visual effects not allowed and all messages allowed to bypass 2. In a test app post two notifications after one another (one w/o messaging style, another with messaging style) Observe: HUN, as expected Change-Id: Ife8c1b52415cd749fecdbdc59fa5b3773b543acf Merged-In: Ife8c1b52415cd749fecdbdc59fa5b3773b543acf --- .../NotificationEntryManager.java | 1 + .../coordinator/RankingCoordinator.java | 10 +++---- .../row/ExpandableNotificationRow.java | 2 +- .../NotificationEntryManagerTest.java | 30 +++++++++++++++++++ 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index d04389d6cbe8..9fd729f425c1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -574,6 +574,7 @@ public class NotificationEntryManager implements NotificationEntry entry = mPendingNotifications.get(key); if (entry != null) { entry.setSbn(notification); + entry.setRanking(ranking); } else { entry = new NotificationEntry( notification, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java index e9cbf32ee052..943ace968632 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java @@ -32,8 +32,6 @@ import javax.inject.Singleton; */ @Singleton public class RankingCoordinator implements Coordinator { - private static final String TAG = "RankingNotificationCoordinator"; - private final StatusBarStateController mStatusBarStateController; @Inject @@ -46,7 +44,7 @@ public class RankingCoordinator implements Coordinator { mStatusBarStateController.addCallback(mStatusBarStateCallback); pipeline.addPreGroupFilter(mSuspendedFilter); - pipeline.addPreGroupFilter(mDozingFilter); + pipeline.addPreGroupFilter(mDndVisualEffectsFilter); } /** @@ -61,10 +59,10 @@ public class RankingCoordinator implements Coordinator { } }; - private final NotifFilter mDozingFilter = new NotifFilter("IsDozingFilter") { + private final NotifFilter mDndVisualEffectsFilter = new NotifFilter( + "DndSuppressingVisualEffects") { @Override public boolean shouldFilterOut(NotificationEntry entry, long now) { - // Dozing + DND Settings from Ranking object if (mStatusBarStateController.isDozing() && entry.shouldSuppressAmbient()) { return true; } @@ -77,7 +75,7 @@ public class RankingCoordinator implements Coordinator { new StatusBarStateController.StateListener() { @Override public void onDozingChanged(boolean isDozing) { - mDozingFilter.invalidateList(); + mDndVisualEffectsFilter.invalidateList(); } }; } 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 94e12e82f850..70dd80e71e7a 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 @@ -504,7 +504,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView /** * Returns whether this row is considered non-blockable (i.e. it's a non-blockable system notif - * or is in a whitelist). + * or is in an allowList). */ public boolean getIsNonblockable() { boolean isNonblockable = Dependency.get(NotificationBlockingHelperManager.class) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index 90423c18216a..f1e6bf604a14 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -381,6 +381,36 @@ public class NotificationEntryManagerTest extends SysuiTestCase { assertEquals("action", mEntry.getSmartActions().get(0).title); } + @Test + public void testUpdatePendingNotification_rankingUpdated() { + // GIVEN a notification with ranking is pending + final Ranking originalRanking = mEntry.getRanking(); + mEntryManager.mPendingNotifications.put(mEntry.getKey(), mEntry); + + // WHEN the same notification has been updated with a new ranking + final int newRank = 2345; + doAnswer(invocationOnMock -> { + Ranking ranking = (Ranking) + invocationOnMock.getArguments()[1]; + ranking.populate( + mEntry.getKey(), + newRank, /* this changed!! */ + false, + 0, + 0, + IMPORTANCE_DEFAULT, + null, null, + null, null, null, true, + Ranking.USER_SENTIMENT_NEUTRAL, false, -1, + false, null, null, false, false, false, null, false); + return true; + }).when(mRankingMap).getRanking(eq(mEntry.getKey()), any(Ranking.class)); + mEntryManager.addNotification(mSbn, mRankingMap); + + // THEN ranking for the entry has been updated with new ranking + assertEquals(newRank, mEntry.getRanking().getRank()); + } + @Test public void testLifetimeExtenders_ifNotificationIsRetainedItIsntRemoved() { // GIVEN an entry manager with a notification -- GitLab From 158f5dd7f0ef9148df4df953624063762d4d418b Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Fri, 16 Oct 2020 15:58:31 +0000 Subject: [PATCH 082/382] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: I29969d431759d25dded634d41268c3c138759f2e --- packages/SystemUI/res/values-de/strings.xml | 24 ++++++++++----------- packages/SystemUI/res/values-fa/strings.xml | 6 +++--- packages/SystemUI/res/values-mr/strings.xml | 8 +++---- packages/SystemUI/res/values-ne/strings.xml | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 82b8b09778e4..090698c78905 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -28,15 +28,15 @@ "%s verbleibend" "Noch %1$s übrig; bei deinem Nutzungsmuster hast du noch ca. %2$s" "%1$s ausstehend; noch ca. %2$s" - "Noch %s. Der Stromsparmodus ist aktiviert." + "Noch %s. Der Energiesparmodus ist aktiviert." "Aufladen über USB nicht möglich. Verwende das mit dem Gerät gelieferte Ladegerät." "Aufladen über USB nicht möglich" "Verwende das mit dem Gerät gelieferte Ladegerät" "Einstellungen" - "Stromsparmodus aktivieren?" - "Über den Stromsparmodus" + "Energiesparmodus aktivieren?" + "Über den Energiesparmodus" "Aktivieren" - "Stromsparmodus aktivieren" + "Energiesparmodus aktivieren" "Einstellungen" "WLAN" "Bildschirm automatisch drehen" @@ -419,7 +419,7 @@ "An um %s" "Bis %s" "Dunkles Design" - "Stromsparmodus" + "Energiesparmodus" "An bei Sonnenuntergang" "Bis Sonnenaufgang" "An um %s" @@ -497,9 +497,9 @@ "Nutzer entfernen?" "Alle Apps und Daten dieses Nutzers werden gelöscht." "Entfernen" - "Stromsparmodus ist aktiviert" + "Energiesparmodus ist aktiviert" "Reduzierung der Leistung und Hintergrunddaten" - "Stromsparmodus deaktivieren" + "Energiesparmodus deaktivieren" "Die App \"%s\" erhält Zugriff auf alle Informationen, die auf deinem Bildschirm sichtbar sind oder von deinem Gerät wiedergegeben werden, während du aufnimmst oder streamst. Dazu gehören beispielsweise angezeigte Passwörter und Zahlungsdetails, Fotos, Nachrichten und Audioinhalte." "Der Anbieter dieser App erhält Zugriff auf alle Informationen, die auf deinem Bildschirm sichtbar sind oder von deinem Gerät wiedergegeben werden, während du aufnimmst oder streamst. Dazu gehören beispielsweise Passwörter, Zahlungsdetails, Fotos, Nachrichten und Audioinhalte." "Aufnahme oder Stream starten?" @@ -765,8 +765,8 @@ %d Minute
"Akkunutzung" - "Der Stromsparmodus ist beim Aufladen nicht verfügbar." - "Stromsparmodus" + "Der Energiesparmodus ist beim Aufladen nicht verfügbar." + "Energiesparmodus" "Reduzierung der Leistung und Hintergrunddaten" "Taste %1$s" "Pos1" @@ -981,11 +981,11 @@ "%1$s darf Teile aus jeder beliebigen App anzeigen" "Zulassen" "Ablehnen" - "Tippen zum Planen des Stromsparmodus" + "Tippen zum Planen des Energiesparmodus" "Aktivieren, wenn der Akku wahrscheinlich nicht mehr lange hält" "Nein danke" - "Geplanter Stromsparmodus aktiviert" - "Der Stromsparmodus wird bei einem Akkustand von %d %% automatisch aktiviert." + "Geplanter Energiesparmodus aktiviert" + "Der Energiesparmodus wird bei einem Akkustand von %d %% automatisch aktiviert." "Einstellungen" "Ok" "Dump SysUI Heap" diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index feb2e4da96e6..71575b7e468d 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -142,7 +142,7 @@ "برای لغو راستی‌آزمایی ضربه بزنید" "لطفاً دوباره امتحان کنید" "درحال جستجوی چهره" - "چهره احراز هویت شد" + "چهره اصالت‌سنجی شد" "تأیید شد" "برای تکمیل، روی تأیید ضربه بزنید" "راستی‌آزمایی‌شده" @@ -307,8 +307,8 @@ "حالت کار روشن شد." "صرفه‌جویی داده خاموش شد." "صرفه‌جویی داده روشن شد." - "«حریم خصوصی حسگر» خاموش است." - "«حریم خصوصی حسگر» روشن است." + "«حریم‌خصوصی حسگر» خاموش است." + "«حریم‌خصوصی حسگر» روشن است." "روشنایی نمایشگر" "درحال شارژ شدن" "‏داده 2G-3G موقتاً متوقف شده است" diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 5a4f64ecb1d4..c71b0f645caa 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -265,7 +265,7 @@ "%1$s." "Wifi बंद झाले." "Wifi सुरू झाले." - "मोबाईल %1$s. %2$s. %3$s." + "मोबाइल %1$s. %2$s. %3$s." "बॅटरी %s." "विमान मोड बंद." "विमान मोड सुरू." @@ -298,8 +298,8 @@ "फ्लॅशलाइट सुरू केला." "रंग उत्क्रमण बंद केले." "रंग उत्क्रमण सुरू केले." - "मोबाईल हॉटस्पॉट बंद केला." - "मोबाईल हॉटस्पॉट सुरू केला." + "मोबाइल हॉटस्पॉट बंद केला." + "मोबाइल हॉटस्पॉट सुरू केला." "स्क्रीन कास्ट करणे थांबले." "कार्य मोड बंद." "कार्य मोड सुरू." @@ -721,7 +721,7 @@ "अलीकडील कोणतेही बबल नाहीत" "अलीकडील बबल आणि डिसमिस केलेले बबल येथे दिसतील" "या सूचनांमध्ये सुधारणा केली जाऊ शकत नाही." - "या सूचनांचा संच येथे कॉन्फिगर केला जाऊ शकत नाही" + "या सूचनांचा संच येथे कॉंफिगर केला जाऊ शकत नाही" "प्रॉक्सी केलेल्या सूचना" "सर्व %1$s वरील सूचना" "आणखी पाहा" diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 92c8cf686d84..9655b6358ca3 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -366,7 +366,7 @@ "स्थान बन्द छ" "मिडिया उपकरण" "RSSI" - "आपतकालीन कल मात्र" + "आपत्‌कालीन कल मात्र" "सेटिङहरू" "समय" "मलाई" -- GitLab From 52537c1ea2b4bd0acd25bf66cadc47b880ad684b Mon Sep 17 00:00:00 2001 From: Heemin Seog Date: Fri, 16 Oct 2020 16:01:50 -0700 Subject: [PATCH 083/382] Allow permission to change application state Needed to give KitchenSink control over enabling/disabling rotary functionality. Bug: 170232080 Test: manual Change-Id: Ic69222642884444597e7411b17b6c6f363076981 --- data/etc/car/com.google.android.car.kitchensink.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/data/etc/car/com.google.android.car.kitchensink.xml b/data/etc/car/com.google.android.car.kitchensink.xml index 7292e0796bf5..f21e9bff16ec 100644 --- a/data/etc/car/com.google.android.car.kitchensink.xml +++ b/data/etc/car/com.google.android.car.kitchensink.xml @@ -43,5 +43,8 @@ + + + -- GitLab From fcd519fde9ba4a3fa7c6415685eb03019560df02 Mon Sep 17 00:00:00 2001 From: Kevin Hufnagle Date: Mon, 19 Oct 2020 21:08:17 -0400 Subject: [PATCH 084/382] docs: Use correct profile for intent The ACTION_AUDIO_STATE_CHANGED intent action uses the HDP profile, not the A2DP profile. Bug: 158742305 Test: m ds-docs-java Exempt-From-Owner-Approval: Docs-only change Change-Id: I4358aac8c8aa9fc8b36e517e568e5a9db538555e --- core/java/android/bluetooth/BluetoothHeadset.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index 6ce05f984cca..e6d6e7ac5dda 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -79,7 +79,7 @@ public final class BluetoothHeadset implements BluetoothProfile { /** * Intent used to broadcast the change in the Audio Connection state of the - * A2DP profile. + * HDP profile. * *

This intent will have 3 extras: *