From 7461b08f9fe3dea74bb8b713d0ff94f5ee25fdf2 Mon Sep 17 00:00:00 2001 From: Oli Lan Date: Wed, 21 Apr 2021 17:20:49 +0100 Subject: [PATCH] Call OnPrimaryClipChanged when classification status changes. To allow apps to know when text classification has been completed on clipboard clips, ClipboardService will now call any OnPrimaryClipChangedListeners when the classification status of the primary clip changes. This change is made as per API council suggestion. This CL also ensures that the classification status is set on any related profiles. Bug: 185177537 Test: atest ClipboardManagerListenerTest Test: atest ClipDescriptionTest Test: atest atest ManagedProfileCrossProfileTest#testCrossProfileCopyPaste Change-Id: I63c44a051d1e8029b6d56b9af5d1e506355a8466 --- .../android/content/ClipboardManager.java | 4 ++ .../server/clipboard/ClipboardService.java | 64 +++++++++++++++---- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java index 11adfa3cecc0d..d41cda1021033 100644 --- a/core/java/android/content/ClipboardManager.java +++ b/core/java/android/content/ClipboardManager.java @@ -100,6 +100,10 @@ public class ClipboardManager extends android.text.ClipboardManager { /** * Callback that is invoked by {@link android.content.ClipboardManager} when the primary * clip changes. + * + *

This is called when the result of {@link ClipDescription#getClassificationStatus()} + * changes, as well as when new clip data is set. So in cases where text classification is + * performed, this callback may be invoked multiple times for the same clip. */ void onPrimaryClipChanged(); } diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index e2aa07102ba3e..ab67b138fdbfc 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -606,6 +606,10 @@ public class ClipboardService extends SystemService { description.setTimestamp(System.currentTimeMillis()); } } + sendClipChangedBroadcast(clipboard); + } + + private void sendClipChangedBroadcast(PerUserClipboard clipboard) { final long ident = Binder.clearCallingIdentity(); final int n = clipboard.primaryClipListeners.beginBroadcast(); try { @@ -615,7 +619,7 @@ public class ClipboardService extends SystemService { clipboard.primaryClipListeners.getBroadcastCookie(i); if (clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, li.mPackageName, - li.mUid, UserHandle.getUserId(li.mUid))) { + li.mUid, UserHandle.getUserId(li.mUid))) { clipboard.primaryClipListeners.getBroadcastItem(i) .dispatchPrimaryClipChanged(); } @@ -632,7 +636,8 @@ public class ClipboardService extends SystemService { @GuardedBy("mLock") private void startClassificationLocked(@NonNull ClipData clip, @UserIdInt int userId) { - if (clip.getItemCount() == 0) { + CharSequence text = (clip.getItemCount() == 0) ? null : clip.getItemAt(0).getText(); + if (TextUtils.isEmpty(text) || text.length() > mMaxClassificationLength) { clip.getDescription().setClassificationStatus( ClipDescription.CLASSIFICATION_NOT_PERFORMED); return; @@ -650,20 +655,17 @@ public class ClipboardService extends SystemService { } finally { Binder.restoreCallingIdentity(ident); } - CharSequence text = clip.getItemAt(0).getText(); - if (TextUtils.isEmpty(text) || text.length() > mMaxClassificationLength - || text.length() > classifier.getMaxGenerateLinksTextLength()) { + if (text.length() > classifier.getMaxGenerateLinksTextLength()) { clip.getDescription().setClassificationStatus( ClipDescription.CLASSIFICATION_NOT_PERFORMED); return; } - getClipboardLocked(userId).mTextClassifier = classifier; - mWorkerHandler.post(() -> doClassification(text, clip, classifier)); + mWorkerHandler.post(() -> doClassification(text, clip, classifier, userId)); } @WorkerThread private void doClassification( - CharSequence text, ClipData clip, TextClassifier classifier) { + CharSequence text, ClipData clip, TextClassifier classifier, @UserIdInt int userId) { TextLinks.Request request = new TextLinks.Request.Builder(text).build(); TextLinks links = classifier.generateLinks(request); @@ -680,13 +682,53 @@ public class ClipboardService extends SystemService { } synchronized (mLock) { - clip.getDescription().setConfidenceScores(confidences); - if (!links.getLinks().isEmpty()) { - clip.getItemAt(0).setTextLinks(links); + PerUserClipboard clipboard = getClipboardLocked(userId); + if (clipboard.primaryClip == clip) { + applyClassificationAndSendBroadcastLocked( + clipboard, confidences, links, classifier); + + // Also apply to related profiles if needed + List related = getRelatedProfiles(userId); + if (related != null) { + int size = related.size(); + for (int i = 0; i < size; i++) { + int id = related.get(i).id; + if (id != userId) { + final boolean canCopyIntoProfile = !hasRestriction( + UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, id); + if (canCopyIntoProfile) { + PerUserClipboard relatedClipboard = getClipboardLocked(id); + if (hasTextLocked(relatedClipboard, text)) { + applyClassificationAndSendBroadcastLocked( + relatedClipboard, confidences, links, classifier); + } + } + } + } + } } } } + @GuardedBy("mLock") + private void applyClassificationAndSendBroadcastLocked( + PerUserClipboard clipboard, ArrayMap confidences, TextLinks links, + TextClassifier classifier) { + clipboard.mTextClassifier = classifier; + clipboard.primaryClip.getDescription().setConfidenceScores(confidences); + if (!links.getLinks().isEmpty()) { + clipboard.primaryClip.getItemAt(0).setTextLinks(links); + } + sendClipChangedBroadcast(clipboard); + } + + @GuardedBy("mLock") + private boolean hasTextLocked(PerUserClipboard clipboard, @NonNull CharSequence text) { + return clipboard.primaryClip != null + && clipboard.primaryClip.getItemCount() > 0 + && text.equals(clipboard.primaryClip.getItemAt(0).getText()); + } + private boolean isDeviceLocked(@UserIdInt int userId) { final long token = Binder.clearCallingIdentity(); try {