diff options
| author | Felipe Leme <felipeal@google.com> | 2019-02-11 17:50:17 -0800 |
|---|---|---|
| committer | Felipe Leme <felipeal@google.com> | 2019-02-12 11:31:06 -0800 |
| commit | 4eecbe6e3c098347a2c5aa81ae5d8ecad0b79786 (patch) | |
| tree | 1bada50a78d21b7697995df0ca7e13bfdbdd56cf /core/java/android | |
| parent | 7c2f57169ca06505f1a43a62feaba07cecd89e26 (diff) | |
Add new ContentCapture APIs to let apps change the ContentCaptureContext.
Test: atest CtsContentCaptureServiceTestCases:android.contentcaptureservice.cts.LoginActivityTest#testSimpleLifecycle_changeContextOnCreate \
CtsContentCaptureServiceTestCases:android.contentcaptureservice.cts.LoginActivityTest#testSimpleLifecycle_changeContextAfterCreate
Test: atest FrameworksCoreTests:android.view.contentcapture.ContentCaptureEventTest
Bug: 124266664
Change-Id: I0348e81e1b2bac01363cf615d2ab32e5bab8aee1
Diffstat (limited to 'core/java/android')
6 files changed, 93 insertions, 38 deletions
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index c98f09e13d97..d2f98599e9a6 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -339,7 +339,7 @@ public abstract class ContentCaptureService extends Service { } switch (event.getType()) { case ContentCaptureEvent.TYPE_SESSION_STARTED: - final ContentCaptureContext clientContext = event.getClientContext(); + final ContentCaptureContext clientContext = event.getContentCaptureContext(); clientContext.setParentSessionId(event.getParentSessionId()); mSessionUids.put(sessionIdString, uid); onCreateContentCaptureSession(clientContext, sessionId); @@ -383,8 +383,8 @@ public abstract class ContentCaptureService extends Service { } final Integer rightUid = mSessionUids.get(sessionId); if (rightUid == null) { - if (DEBUG) { - Log.d(TAG, "handleIsRightCallerFor(" + event + "): no session for " + sessionId + if (VERBOSE) { + Log.v(TAG, "handleIsRightCallerFor(" + event + "): no session for " + sessionId + ": " + mSessionUids); } // Just ignore, as the session could have been finished already diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 83df33e9742e..469bdbf89d6a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -9366,7 +9366,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * Gets the session used to notify Content Capture events. * * @return session explicitly set by {@link #setContentCaptureSession(ContentCaptureSession)}, - * inherited by ancestore, default session or {@code null} if content capture is disabled for + * inherited by ancestors, default session or {@code null} if content capture is disabled for * this view. */ @Nullable diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java index acb81e086461..13e8a6584218 100644 --- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java @@ -20,10 +20,6 @@ import android.annotation.Nullable; import android.view.autofill.AutofillId; import android.view.contentcapture.ViewNode.ViewStructureImpl; -import com.android.internal.util.Preconditions; - -import java.io.PrintWriter; - /** * A session that is explicitly created by the app (and hence is a descendant of * {@link MainContentCaptureSession}). @@ -35,21 +31,11 @@ final class ChildContentCaptureSession extends ContentCaptureSession { @NonNull private final ContentCaptureSession mParent; - /** - * {@link ContentCaptureContext} set by client, or {@code null} when it's the - * {@link ContentCaptureManager#getMainContentCaptureSession() default session} for the - * context. - * - * @hide - */ - @NonNull - private final ContentCaptureContext mClientContext; - /** @hide */ protected ChildContentCaptureSession(@NonNull ContentCaptureSession parent, @NonNull ContentCaptureContext clientContext) { + super(clientContext); mParent = parent; - mClientContext = Preconditions.checkNotNull(clientContext); } @Override @@ -73,6 +59,11 @@ final class ChildContentCaptureSession extends ContentCaptureSession { } @Override + public void updateContentCaptureContext(@Nullable ContentCaptureContext context) { + getMainCaptureSession().notifyContextUpdated(mId, context); + } + + @Override void onDestroy() { getMainCaptureSession().notifyChildSessionFinished(mParent.mId, mId); } @@ -101,13 +92,4 @@ final class ChildContentCaptureSession extends ContentCaptureSession { boolean isContentCaptureEnabled() { return getMainCaptureSession().isContentCaptureEnabled(); } - - @Override - void dump(String prefix, PrintWriter pw) { - if (mClientContext != null) { - // NOTE: we don't dump clientContent because it could have PII - pw.print(prefix); pw.println("hasClientContext"); - } - super.dump(prefix, pw); - } } diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java index 22254cd94059..9cdbefac3d1d 100644 --- a/core/java/android/view/contentcapture/ContentCaptureEvent.java +++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java @@ -91,13 +91,22 @@ public final class ContentCaptureEvent implements Parcelable { */ public static final int TYPE_INITIAL_VIEW_TREE_APPEARED = 5; + /** + * Called after a call to + * {@link ContentCaptureSession#setContentCaptureContext(ContentCaptureContext)}. + * + * <p>The passed context is available through {@link #getContentCaptureContext()}. + */ + public static final int TYPE_CONTEXT_UPDATED = 6; + /** @hide */ @IntDef(prefix = { "TYPE_" }, value = { TYPE_VIEW_APPEARED, TYPE_VIEW_DISAPPEARED, TYPE_VIEW_TEXT_CHANGED, TYPE_INITIAL_VIEW_TREE_APPEARING, - TYPE_INITIAL_VIEW_TREE_APPEARED + TYPE_INITIAL_VIEW_TREE_APPEARED, + TYPE_CONTEXT_UPDATED }) @Retention(RetentionPolicy.SOURCE) public @interface EventType{} @@ -193,12 +202,13 @@ public final class ContentCaptureEvent implements Parcelable { } /** - * Used by {@link #TYPE_SESSION_STARTED}. + * Gets the {@link ContentCaptureContext} set calls to + * {@link ContentCaptureSession#setContentCaptureContext(ContentCaptureContext)}. * - * @hide + * <p>Only set on {@link #TYPE_CONTEXT_UPDATED} events. */ @Nullable - public ContentCaptureContext getClientContext() { + public ContentCaptureContext getContentCaptureContext() { return mClientContext; } @@ -220,8 +230,8 @@ public final class ContentCaptureEvent implements Parcelable { * Gets the type of the event. * * @return one of {@link #TYPE_VIEW_APPEARED}, {@link #TYPE_VIEW_DISAPPEARED}, - * {@link #TYPE_VIEW_TEXT_CHANGED}, {@link #TYPE_INITIAL_VIEW_TREE_APPEARING}, or - * {@link #TYPE_INITIAL_VIEW_TREE_APPEARED}. + * {@link #TYPE_VIEW_TEXT_CHANGED}, {@link #TYPE_INITIAL_VIEW_TREE_APPEARING}, + * {@link #TYPE_INITIAL_VIEW_TREE_APPEARED}, or {@link #TYPE_CONTEXT_UPDATED}. */ public @EventType int getType() { return mType; @@ -299,6 +309,10 @@ public final class ContentCaptureEvent implements Parcelable { if (mText != null) { pw.print(", text="); pw.println(getSanitizedString(mText)); } + if (mClientContext != null) { + pw.print(", context="); mClientContext.dump(pw); pw.println(); + + } } @Override @@ -325,6 +339,9 @@ public final class ContentCaptureEvent implements Parcelable { if (mText != null) { string.append(", text=").append(getSanitizedString(mText)); } + if (mClientContext != null) { + string.append(", context=").append(mClientContext); + } return string.append(']').toString(); } @@ -345,7 +362,7 @@ public final class ContentCaptureEvent implements Parcelable { if (mType == TYPE_SESSION_STARTED || mType == TYPE_SESSION_FINISHED) { parcel.writeString(mParentSessionId); } - if (mType == TYPE_SESSION_STARTED) { + if (mType == TYPE_SESSION_STARTED || mType == TYPE_CONTEXT_UPDATED) { parcel.writeParcelable(mClientContext, flags); } } @@ -375,7 +392,7 @@ public final class ContentCaptureEvent implements Parcelable { if (type == TYPE_SESSION_STARTED || type == TYPE_SESSION_FINISHED) { event.setParentSessionId(parcel.readString()); } - if (type == TYPE_SESSION_STARTED) { + if (type == TYPE_SESSION_STARTED || type == TYPE_CONTEXT_UPDATED) { event.setClientContext(parcel.readParcelable(null)); } return event; @@ -404,6 +421,8 @@ public final class ContentCaptureEvent implements Parcelable { return "INITIAL_VIEW_HIERARCHY_STARTED"; case TYPE_INITIAL_VIEW_TREE_APPEARED: return "INITIAL_VIEW_HIERARCHY_FINISHED"; + case TYPE_CONTEXT_UPDATED: + return "CONTEXT_UPDATED"; default: return "UKNOWN_TYPE: " + type; } diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index e028961692f9..b8d3fa6f4404 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -166,6 +166,14 @@ public abstract class ContentCaptureSession implements AutoCloseable { private ContentCaptureSessionId mContentCaptureSessionId; /** + * {@link ContentCaptureContext} set by client, or {@code null} when it's the + * {@link ContentCaptureManager#getMainContentCaptureSession() default session} for the + * context. + */ + @Nullable + private ContentCaptureContext mClientContext; + + /** * List of children session. */ @Nullable @@ -183,6 +191,12 @@ public abstract class ContentCaptureSession implements AutoCloseable { mId = Preconditions.checkNotNull(id); } + // Used by ChildCOntentCaptureSession + ContentCaptureSession(@NonNull ContentCaptureContext initialContext) { + this(); + mClientContext = Preconditions.checkNotNull(initialContext); + } + /** @hide */ @NonNull abstract MainContentCaptureSession getMainCaptureSession(); @@ -240,6 +254,30 @@ public abstract class ContentCaptureSession implements AutoCloseable { abstract void flush(@FlushReason int reason); /** + * Sets the {@link ContentCaptureContext} associated with the session. + * + * <p>Typically used to change the context associated with the default session from an activity. + */ + public final void setContentCaptureContext(@Nullable ContentCaptureContext context) { + mClientContext = context; + updateContentCaptureContext(context); + } + + abstract void updateContentCaptureContext(@Nullable ContentCaptureContext context); + + /** + * Gets the {@link ContentCaptureContext} associated with the session. + * + * @return context set on constructor or by + * {@link #setContentCaptureContext(ContentCaptureContext)}, or {@code null} if never + * explicitly set. + */ + @Nullable + public final ContentCaptureContext getContentCaptureContext() { + return mClientContext; + } + + /** * Destroys this session, flushing out all pending notifications to the service. * * <p>Once destroyed, any new notification will be dropped. @@ -424,6 +462,9 @@ public abstract class ContentCaptureSession implements AutoCloseable { @CallSuper void dump(@NonNull String prefix, @NonNull PrintWriter pw) { pw.print(prefix); pw.print("id: "); pw.println(mId); + if (mClientContext != null) { + pw.print(prefix); mClientContext.dump(pw); pw.println(); + } synchronized (mLock) { pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed); if (mChildren != null && !mChildren.isEmpty()) { diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index 810c967ce2c8..d949f45ba5e6 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -15,6 +15,7 @@ */ package android.view.contentcapture; +import static android.view.contentcapture.ContentCaptureEvent.TYPE_CONTEXT_UPDATED; import static android.view.contentcapture.ContentCaptureEvent.TYPE_INITIAL_VIEW_TREE_APPEARED; import static android.view.contentcapture.ContentCaptureEvent.TYPE_INITIAL_VIEW_TREE_APPEARING; import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_FINISHED; @@ -269,11 +270,12 @@ public final class MainContentCaptureSession extends ContentCaptureSession { private void sendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) { final int eventType = event.getType(); if (VERBOSE) Log.v(TAG, "handleSendEvent(" + getDebugState() + "): " + event); - if (!hasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED) { + if (!hasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED + && eventType != ContentCaptureEvent.TYPE_CONTEXT_UPDATED) { // TODO(b/120494182): comment when this could happen (dialogs?) Log.v(TAG, "handleSendEvent(" + getDebugState() + ", " + ContentCaptureEvent.getTypeAsString(eventType) - + "): session not started yet"); + + "): dropping because session not started yet"); return; } if (mDisabled.get()) { @@ -476,6 +478,11 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } } + @Override + public void updateContentCaptureContext(@Nullable ContentCaptureContext context) { + notifyContextUpdated(mId, context); + } + /** * Resets the buffer and return a {@link ParceledListSlice} with the previous events. */ @@ -613,6 +620,12 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } } + void notifyContextUpdated(@NonNull String sessionId, + @Nullable ContentCaptureContext context) { + sendEvent(new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED) + .setClientContext(context)); + } + @Override void dump(@NonNull String prefix, @NonNull PrintWriter pw) { pw.print(prefix); pw.print("mContext: "); pw.println(mContext); |
