Merge "Notify TextClassifier an app is reading the clipboard" into sc-dev
This commit is contained in:
@@ -86,7 +86,8 @@ public abstract class TextClassifierEvent implements Parcelable {
|
||||
TYPE_ACTIONS_SHOWN, TYPE_LINK_CLICKED, TYPE_OVERTYPE, TYPE_COPY_ACTION,
|
||||
TYPE_PASTE_ACTION, TYPE_CUT_ACTION, TYPE_SHARE_ACTION, TYPE_SMART_ACTION,
|
||||
TYPE_SELECTION_DRAG, TYPE_SELECTION_DESTROYED, TYPE_OTHER_ACTION, TYPE_SELECT_ALL,
|
||||
TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY, TYPE_ACTIONS_GENERATED, TYPE_LINKS_GENERATED})
|
||||
TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY, TYPE_ACTIONS_GENERATED, TYPE_LINKS_GENERATED,
|
||||
TYPE_READ_CLIPBOARD})
|
||||
public @interface Type {
|
||||
// For custom event types, use range 1,000,000+.
|
||||
}
|
||||
@@ -135,6 +136,13 @@ public abstract class TextClassifierEvent implements Parcelable {
|
||||
public static final int TYPE_ACTIONS_GENERATED = 20;
|
||||
/** Some text links were generated.*/
|
||||
public static final int TYPE_LINKS_GENERATED = 21;
|
||||
/**
|
||||
* Read a clipboard.
|
||||
* TODO: Make this public.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final int TYPE_READ_CLIPBOARD = 22;
|
||||
|
||||
@Category
|
||||
private final int mEventCategory;
|
||||
|
||||
@@ -45,6 +45,7 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
@@ -67,6 +68,7 @@ import android.view.autofill.AutofillManagerInternal;
|
||||
import android.view.textclassifier.TextClassificationContext;
|
||||
import android.view.textclassifier.TextClassificationManager;
|
||||
import android.view.textclassifier.TextClassifier;
|
||||
import android.view.textclassifier.TextClassifierEvent;
|
||||
import android.view.textclassifier.TextLinks;
|
||||
import android.widget.Toast;
|
||||
|
||||
@@ -211,9 +213,18 @@ public class ClipboardService extends SystemService {
|
||||
/** Uids that have already triggered a toast notification for {@link #primaryClip} */
|
||||
final SparseBooleanArray mNotifiedUids = new SparseBooleanArray();
|
||||
|
||||
/**
|
||||
* Uids that have already triggered a notification to text classifier for
|
||||
* {@link #primaryClip}.
|
||||
*/
|
||||
final SparseBooleanArray mNotifiedTextClassifierUids = new SparseBooleanArray();
|
||||
|
||||
final HashSet<String> activePermissionOwners
|
||||
= new HashSet<String>();
|
||||
|
||||
/** The text classifier session that is used to annotate the text in the primary clip. */
|
||||
TextClassifier mTextClassifier;
|
||||
|
||||
PerUserClipboard(int userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
@@ -371,6 +382,7 @@ public class ClipboardService extends SystemService {
|
||||
addActiveOwnerLocked(intendingUid, pkg);
|
||||
PerUserClipboard clipboard = getClipboardLocked(intendingUserId);
|
||||
showAccessNotificationLocked(pkg, intendingUid, intendingUserId, clipboard);
|
||||
notifyTextClassifierLocked(clipboard, pkg, intendingUid);
|
||||
return clipboard.primaryClip;
|
||||
}
|
||||
}
|
||||
@@ -580,6 +592,7 @@ public class ClipboardService extends SystemService {
|
||||
}
|
||||
clipboard.primaryClip = clip;
|
||||
clipboard.mNotifiedUids.clear();
|
||||
clipboard.mNotifiedTextClassifierUids.clear();
|
||||
if (clip != null) {
|
||||
clipboard.primaryClipUid = uid;
|
||||
clipboard.mPrimaryClipPackage = sourcePackage;
|
||||
@@ -619,6 +632,11 @@ public class ClipboardService extends SystemService {
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void startClassificationLocked(@NonNull ClipData clip, @UserIdInt int userId) {
|
||||
if (clip.getItemCount() == 0) {
|
||||
clip.getDescription().setClassificationStatus(
|
||||
ClipDescription.CLASSIFICATION_NOT_PERFORMED);
|
||||
return;
|
||||
}
|
||||
TextClassifier classifier;
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
@@ -627,17 +645,11 @@ public class ClipboardService extends SystemService {
|
||||
new TextClassificationContext.Builder(
|
||||
getContext().getPackageName(),
|
||||
TextClassifier.WIDGET_TYPE_CLIPBOARD
|
||||
).build()
|
||||
);
|
||||
).build()
|
||||
);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
|
||||
if (clip.getItemCount() == 0) {
|
||||
clip.getDescription().setClassificationStatus(
|
||||
ClipDescription.CLASSIFICATION_NOT_PERFORMED);
|
||||
return;
|
||||
}
|
||||
CharSequence text = clip.getItemAt(0).getText();
|
||||
if (TextUtils.isEmpty(text) || text.length() > mMaxClassificationLength
|
||||
|| text.length() > classifier.getMaxGenerateLinksTextLength()) {
|
||||
@@ -645,7 +657,7 @@ public class ClipboardService extends SystemService {
|
||||
ClipDescription.CLASSIFICATION_NOT_PERFORMED);
|
||||
return;
|
||||
}
|
||||
|
||||
getClipboardLocked(userId).mTextClassifier = classifier;
|
||||
mWorkerHandler.post(() -> doClassification(text, clip, classifier));
|
||||
}
|
||||
|
||||
@@ -653,12 +665,7 @@ public class ClipboardService extends SystemService {
|
||||
private void doClassification(
|
||||
CharSequence text, ClipData clip, TextClassifier classifier) {
|
||||
TextLinks.Request request = new TextLinks.Request.Builder(text).build();
|
||||
TextLinks links;
|
||||
try {
|
||||
links = classifier.generateLinks(request);
|
||||
} finally {
|
||||
classifier.destroy();
|
||||
}
|
||||
TextLinks links = classifier.generateLinks(request);
|
||||
|
||||
// Find the highest confidence for each entity in the text.
|
||||
ArrayMap<String, Float> confidences = new ArrayMap<>();
|
||||
@@ -979,6 +986,48 @@ public class ClipboardService extends SystemService {
|
||||
&& item.getIntent() == null;
|
||||
}
|
||||
|
||||
/** Potentially notifies the text classifier that an app is accessing a text clip. */
|
||||
@GuardedBy("mLock")
|
||||
private void notifyTextClassifierLocked(
|
||||
PerUserClipboard clipboard, String callingPackage, int callingUid) {
|
||||
if (clipboard.primaryClip == null) {
|
||||
return;
|
||||
}
|
||||
ClipData.Item item = clipboard.primaryClip.getItemAt(0);
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
if (!isText(clipboard.primaryClip)) {
|
||||
return;
|
||||
}
|
||||
TextClassifier textClassifier = clipboard.mTextClassifier;
|
||||
// Don't notify text classifier if we haven't used it to annotate the text in the clip.
|
||||
if (textClassifier == null) {
|
||||
return;
|
||||
}
|
||||
// Don't notify text classifier if the app reading the clipboard does not have the focus.
|
||||
if (!mWm.isUidFocused(callingUid)) {
|
||||
return;
|
||||
}
|
||||
// Don't notify text classifier again if already notified for this uid and clip.
|
||||
if (clipboard.mNotifiedTextClassifierUids.get(callingUid)) {
|
||||
return;
|
||||
}
|
||||
clipboard.mNotifiedTextClassifierUids.put(callingUid, true);
|
||||
Binder.withCleanCallingIdentity(() -> {
|
||||
TextClassifierEvent.TextLinkifyEvent pasteEvent =
|
||||
new TextClassifierEvent.TextLinkifyEvent.Builder(
|
||||
TextClassifierEvent.TYPE_READ_CLIPBOARD)
|
||||
.setEventContext(new TextClassificationContext.Builder(
|
||||
callingPackage, TextClassifier.WIDGET_TYPE_CLIPBOARD)
|
||||
.build())
|
||||
.setExtras(
|
||||
Bundle.forPair("source_package", clipboard.mPrimaryClipPackage))
|
||||
.build();
|
||||
textClassifier.onTextClassifierEvent(pasteEvent);
|
||||
});
|
||||
}
|
||||
|
||||
private TextClassificationManager createTextClassificationManagerAsUser(@UserIdInt int userId) {
|
||||
Context context = getContext().createContextAsUser(UserHandle.of(userId), /* flags= */ 0);
|
||||
return context.getSystemService(TextClassificationManager.class);
|
||||
|
||||
Reference in New Issue
Block a user