Loading core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -54796,6 +54796,7 @@ package android.view.contentcapture { method public final void notifyViewDisappeared(@NonNull android.view.autofill.AutofillId); method public final void notifyViewInsetsChanged(@NonNull android.graphics.Insets); method public final void notifyViewTextChanged(@NonNull android.view.autofill.AutofillId, @Nullable CharSequence); method public final void notifyViewsAppeared(@NonNull java.util.List<android.view.ViewStructure>); method public final void notifyViewsDisappeared(@NonNull android.view.autofill.AutofillId, @NonNull long[]); method public final void setContentCaptureContext(@Nullable android.view.contentcapture.ContentCaptureContext); } core/java/android/view/contentcapture/ContentCaptureSession.java +53 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package android.view.contentcapture; import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE; import static android.view.contentcapture.ContentCaptureHelper.sDebug; import static android.view.contentcapture.ContentCaptureHelper.sVerbose; import static android.view.contentcapture.ContentCaptureManager.NO_SESSION_ID; Loading @@ -23,6 +24,9 @@ import android.annotation.CallSuper; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.graphics.Insets; import android.util.DebugUtils; import android.util.Log; Loading @@ -41,6 +45,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.security.SecureRandom; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** Loading Loading @@ -171,6 +176,10 @@ public abstract class ContentCaptureSession implements AutoCloseable { /** @hide */ public static final int FLUSH_REASON_SESSION_CONNECTED = 7; @ChangeId @EnabledSince(targetSdkVersion = UPSIDE_DOWN_CAKE) static final long NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS = 258825825L; /** @hide */ @IntDef(prefix = { "FLUSH_REASON_" }, value = { FLUSH_REASON_FULL, Loading Loading @@ -229,7 +238,7 @@ public abstract class ContentCaptureSession implements AutoCloseable { mId = id; } // Used by ChildCOntentCaptureSession // Used by ChildContentCaptureSession ContentCaptureSession(@NonNull ContentCaptureContext initialContext) { this(); mClientContext = Objects.requireNonNull(initialContext); Loading Loading @@ -362,6 +371,9 @@ public abstract class ContentCaptureSession implements AutoCloseable { * automatically by the Android System for views that return {@code true} on * {@link View#onProvideContentCaptureStructure(ViewStructure, int)}. * * <p>Consider use {@link #notifyViewsAppeared} which has a better performance when notifying * a list of nodes has appeared. * * @param node node that has been added. */ public final void notifyViewAppeared(@NonNull ViewStructure node) { Loading @@ -383,6 +395,9 @@ public abstract class ContentCaptureSession implements AutoCloseable { * <p>Typically called "manually" by views that handle their own virtual view hierarchy, or * automatically by the Android System for standard views. * * <p>Consider use {@link #notifyViewsDisappeared} which has a better performance when notifying * a list of nodes has disappeared. * * @param id id of the node that has been removed. */ public final void notifyViewDisappeared(@NonNull AutofillId id) { Loading @@ -394,12 +409,43 @@ public abstract class ContentCaptureSession implements AutoCloseable { abstract void internalNotifyViewDisappeared(@NonNull AutofillId id); /** * Notifies the Content Capture Service that a list of nodes has appeared in the view structure. * * <p>Typically called manually by views that handle their own virtual view hierarchy. * * @param appearedNodes nodes that have appeared. Each element represents a view node that has * been added to the view structure. The order of the elements is important, which should be * preserved as the attached order of when the node is attached to the virtual view hierarchy. */ public final void notifyViewsAppeared(@NonNull List<ViewStructure> appearedNodes) { Preconditions.checkCollectionElementsNotNull(appearedNodes, "appearedNodes"); if (!isContentCaptureEnabled()) return; for (int i = 0; i < appearedNodes.size(); i++) { ViewStructure v = appearedNodes.get(i); if (!(v instanceof ViewNode.ViewStructureImpl)) { throw new IllegalArgumentException("Invalid class: " + v.getClass()); } } internalNotifyViewTreeEvent(/* started= */ true); for (int i = 0; i < appearedNodes.size(); i++) { ViewStructure v = appearedNodes.get(i); internalNotifyViewAppeared((ViewStructureImpl) v); } internalNotifyViewTreeEvent(/* started= */ false); } /** * Notifies the Content Capture Service that many nodes has been removed from a virtual view * structure. * * <p>Should only be called by views that handle their own virtual view hierarchy. * * <p>After UPSIDE_DOWN_CAKE, this method wraps the virtual children with a pair of view tree * appearing and view tree appeared events. * * @param hostId id of the non-virtual view hosting the virtual view hierarchy (it can be * obtained by calling {@link ViewStructure#getAutofillId()}). * @param virtualIds ids of the virtual children. Loading @@ -413,11 +459,17 @@ public abstract class ContentCaptureSession implements AutoCloseable { Preconditions.checkArgument(!ArrayUtils.isEmpty(virtualIds), "virtual ids cannot be empty"); if (!isContentCaptureEnabled()) return; if (CompatChanges.isChangeEnabled(NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS)) { internalNotifyViewTreeEvent(/* started= */ true); } // TODO(b/123036895): use a internalNotifyViewsDisappeared that optimizes how the event is // parcelized for (long id : virtualIds) { internalNotifyViewDisappeared(new AutofillId(hostId, id, mId)); } if (CompatChanges.isChangeEnabled(NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS)) { internalNotifyViewTreeEvent(/* started= */ false); } } /** Loading core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java +38 −4 Original line number Diff line number Diff line Loading @@ -20,13 +20,19 @@ import static com.google.common.truth.Truth.assertThat; import static org.testng.Assert.assertThrows; import android.compat.testing.PlatformCompatChangeRule; import android.graphics.Insets; import android.view.View; import android.view.ViewStructure; import android.view.autofill.AutofillId; import android.view.contentcapture.ViewNode.ViewStructureImpl; import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; Loading @@ -39,6 +45,8 @@ import org.mockito.junit.MockitoJUnitRunner; */ @RunWith(MockitoJUnitRunner.class) public class ContentCaptureSessionTest { @Rule public TestRule compatChangeRule = new PlatformCompatChangeRule(); private ContentCaptureSession mSession1 = new MyContentCaptureSession(111); Loading @@ -47,6 +55,7 @@ public class ContentCaptureSessionTest { @Mock private View mMockView; @DisableCompatChanges({ContentCaptureSession.NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS}) @Test public void testNewAutofillId_invalid() { assertThrows(NullPointerException.class, () -> mSession1.newAutofillId(null, 42L)); Loading Loading @@ -78,6 +87,8 @@ public class ContentCaptureSessionTest { public void testNotifyXXX_null() { assertThrows(NullPointerException.class, () -> mSession1.notifyViewAppeared(null)); assertThrows(NullPointerException.class, () -> mSession1.notifyViewDisappeared(null)); assertThrows(NullPointerException.class, () -> mSession1.notifyViewsAppeared(null)); assertThrows(NullPointerException.class, () -> mSession1.notifyViewTextChanged(null, "whatever")); } Loading Loading @@ -115,8 +126,29 @@ public class ContentCaptureSessionTest { () -> mSession1.notifyViewsDisappeared(new AutofillId(42, 108), new long[] {666})); } @Test public void testNotifyViewsDisappeared_noSendTreeEventBeforeU() { MyContentCaptureSession session = new MyContentCaptureSession(121); session.notifyViewsDisappeared(new AutofillId(42), new long[] {42}); assertThat(session.mInternalNotifyViewTreeEventStartedCount).isEqualTo(0); assertThat(session.mInternalNotifyViewTreeEventFinishedCount).isEqualTo(0); } @EnableCompatChanges({ContentCaptureSession.NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS}) @Test public void testNotifyViewsDisappeared_sendTreeEventSinceU() { MyContentCaptureSession session = new MyContentCaptureSession(122); session.notifyViewsDisappeared(new AutofillId(42), new long[] {42}); assertThat(session.mInternalNotifyViewTreeEventStartedCount).isEqualTo(1); assertThat(session.mInternalNotifyViewTreeEventFinishedCount).isEqualTo(1); } // Cannot use @Spy because we need to pass the session id on constructor private class MyContentCaptureSession extends ContentCaptureSession { int mInternalNotifyViewTreeEventStartedCount = 0; int mInternalNotifyViewTreeEventFinishedCount = 0; private MyContentCaptureSession(int id) { super(id); Loading Loading @@ -148,9 +180,7 @@ public class ContentCaptureSessionTest { } @Override void internalNotifyViewDisappeared(AutofillId id) { throw new UnsupportedOperationException("should not have been called"); } void internalNotifyViewDisappeared(AutofillId id) {} @Override void internalNotifyViewTextChanged(AutofillId id, CharSequence text) { Loading @@ -159,7 +189,11 @@ public class ContentCaptureSessionTest { @Override public void internalNotifyViewTreeEvent(boolean started) { throw new UnsupportedOperationException("should not have been called"); if (started) { mInternalNotifyViewTreeEventStartedCount += 1; } else { mInternalNotifyViewTreeEventFinishedCount += 1; } } @Override Loading Loading
core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -54796,6 +54796,7 @@ package android.view.contentcapture { method public final void notifyViewDisappeared(@NonNull android.view.autofill.AutofillId); method public final void notifyViewInsetsChanged(@NonNull android.graphics.Insets); method public final void notifyViewTextChanged(@NonNull android.view.autofill.AutofillId, @Nullable CharSequence); method public final void notifyViewsAppeared(@NonNull java.util.List<android.view.ViewStructure>); method public final void notifyViewsDisappeared(@NonNull android.view.autofill.AutofillId, @NonNull long[]); method public final void setContentCaptureContext(@Nullable android.view.contentcapture.ContentCaptureContext); }
core/java/android/view/contentcapture/ContentCaptureSession.java +53 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,7 @@ */ package android.view.contentcapture; import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE; import static android.view.contentcapture.ContentCaptureHelper.sDebug; import static android.view.contentcapture.ContentCaptureHelper.sVerbose; import static android.view.contentcapture.ContentCaptureManager.NO_SESSION_ID; Loading @@ -23,6 +24,9 @@ import android.annotation.CallSuper; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.graphics.Insets; import android.util.DebugUtils; import android.util.Log; Loading @@ -41,6 +45,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.security.SecureRandom; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** Loading Loading @@ -171,6 +176,10 @@ public abstract class ContentCaptureSession implements AutoCloseable { /** @hide */ public static final int FLUSH_REASON_SESSION_CONNECTED = 7; @ChangeId @EnabledSince(targetSdkVersion = UPSIDE_DOWN_CAKE) static final long NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS = 258825825L; /** @hide */ @IntDef(prefix = { "FLUSH_REASON_" }, value = { FLUSH_REASON_FULL, Loading Loading @@ -229,7 +238,7 @@ public abstract class ContentCaptureSession implements AutoCloseable { mId = id; } // Used by ChildCOntentCaptureSession // Used by ChildContentCaptureSession ContentCaptureSession(@NonNull ContentCaptureContext initialContext) { this(); mClientContext = Objects.requireNonNull(initialContext); Loading Loading @@ -362,6 +371,9 @@ public abstract class ContentCaptureSession implements AutoCloseable { * automatically by the Android System for views that return {@code true} on * {@link View#onProvideContentCaptureStructure(ViewStructure, int)}. * * <p>Consider use {@link #notifyViewsAppeared} which has a better performance when notifying * a list of nodes has appeared. * * @param node node that has been added. */ public final void notifyViewAppeared(@NonNull ViewStructure node) { Loading @@ -383,6 +395,9 @@ public abstract class ContentCaptureSession implements AutoCloseable { * <p>Typically called "manually" by views that handle their own virtual view hierarchy, or * automatically by the Android System for standard views. * * <p>Consider use {@link #notifyViewsDisappeared} which has a better performance when notifying * a list of nodes has disappeared. * * @param id id of the node that has been removed. */ public final void notifyViewDisappeared(@NonNull AutofillId id) { Loading @@ -394,12 +409,43 @@ public abstract class ContentCaptureSession implements AutoCloseable { abstract void internalNotifyViewDisappeared(@NonNull AutofillId id); /** * Notifies the Content Capture Service that a list of nodes has appeared in the view structure. * * <p>Typically called manually by views that handle their own virtual view hierarchy. * * @param appearedNodes nodes that have appeared. Each element represents a view node that has * been added to the view structure. The order of the elements is important, which should be * preserved as the attached order of when the node is attached to the virtual view hierarchy. */ public final void notifyViewsAppeared(@NonNull List<ViewStructure> appearedNodes) { Preconditions.checkCollectionElementsNotNull(appearedNodes, "appearedNodes"); if (!isContentCaptureEnabled()) return; for (int i = 0; i < appearedNodes.size(); i++) { ViewStructure v = appearedNodes.get(i); if (!(v instanceof ViewNode.ViewStructureImpl)) { throw new IllegalArgumentException("Invalid class: " + v.getClass()); } } internalNotifyViewTreeEvent(/* started= */ true); for (int i = 0; i < appearedNodes.size(); i++) { ViewStructure v = appearedNodes.get(i); internalNotifyViewAppeared((ViewStructureImpl) v); } internalNotifyViewTreeEvent(/* started= */ false); } /** * Notifies the Content Capture Service that many nodes has been removed from a virtual view * structure. * * <p>Should only be called by views that handle their own virtual view hierarchy. * * <p>After UPSIDE_DOWN_CAKE, this method wraps the virtual children with a pair of view tree * appearing and view tree appeared events. * * @param hostId id of the non-virtual view hosting the virtual view hierarchy (it can be * obtained by calling {@link ViewStructure#getAutofillId()}). * @param virtualIds ids of the virtual children. Loading @@ -413,11 +459,17 @@ public abstract class ContentCaptureSession implements AutoCloseable { Preconditions.checkArgument(!ArrayUtils.isEmpty(virtualIds), "virtual ids cannot be empty"); if (!isContentCaptureEnabled()) return; if (CompatChanges.isChangeEnabled(NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS)) { internalNotifyViewTreeEvent(/* started= */ true); } // TODO(b/123036895): use a internalNotifyViewsDisappeared that optimizes how the event is // parcelized for (long id : virtualIds) { internalNotifyViewDisappeared(new AutofillId(hostId, id, mId)); } if (CompatChanges.isChangeEnabled(NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS)) { internalNotifyViewTreeEvent(/* started= */ false); } } /** Loading
core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java +38 −4 Original line number Diff line number Diff line Loading @@ -20,13 +20,19 @@ import static com.google.common.truth.Truth.assertThat; import static org.testng.Assert.assertThrows; import android.compat.testing.PlatformCompatChangeRule; import android.graphics.Insets; import android.view.View; import android.view.ViewStructure; import android.view.autofill.AutofillId; import android.view.contentcapture.ViewNode.ViewStructureImpl; import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; Loading @@ -39,6 +45,8 @@ import org.mockito.junit.MockitoJUnitRunner; */ @RunWith(MockitoJUnitRunner.class) public class ContentCaptureSessionTest { @Rule public TestRule compatChangeRule = new PlatformCompatChangeRule(); private ContentCaptureSession mSession1 = new MyContentCaptureSession(111); Loading @@ -47,6 +55,7 @@ public class ContentCaptureSessionTest { @Mock private View mMockView; @DisableCompatChanges({ContentCaptureSession.NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS}) @Test public void testNewAutofillId_invalid() { assertThrows(NullPointerException.class, () -> mSession1.newAutofillId(null, 42L)); Loading Loading @@ -78,6 +87,8 @@ public class ContentCaptureSessionTest { public void testNotifyXXX_null() { assertThrows(NullPointerException.class, () -> mSession1.notifyViewAppeared(null)); assertThrows(NullPointerException.class, () -> mSession1.notifyViewDisappeared(null)); assertThrows(NullPointerException.class, () -> mSession1.notifyViewsAppeared(null)); assertThrows(NullPointerException.class, () -> mSession1.notifyViewTextChanged(null, "whatever")); } Loading Loading @@ -115,8 +126,29 @@ public class ContentCaptureSessionTest { () -> mSession1.notifyViewsDisappeared(new AutofillId(42, 108), new long[] {666})); } @Test public void testNotifyViewsDisappeared_noSendTreeEventBeforeU() { MyContentCaptureSession session = new MyContentCaptureSession(121); session.notifyViewsDisappeared(new AutofillId(42), new long[] {42}); assertThat(session.mInternalNotifyViewTreeEventStartedCount).isEqualTo(0); assertThat(session.mInternalNotifyViewTreeEventFinishedCount).isEqualTo(0); } @EnableCompatChanges({ContentCaptureSession.NOTIFY_NODES_DISAPPEAR_NOW_SENDS_TREE_EVENTS}) @Test public void testNotifyViewsDisappeared_sendTreeEventSinceU() { MyContentCaptureSession session = new MyContentCaptureSession(122); session.notifyViewsDisappeared(new AutofillId(42), new long[] {42}); assertThat(session.mInternalNotifyViewTreeEventStartedCount).isEqualTo(1); assertThat(session.mInternalNotifyViewTreeEventFinishedCount).isEqualTo(1); } // Cannot use @Spy because we need to pass the session id on constructor private class MyContentCaptureSession extends ContentCaptureSession { int mInternalNotifyViewTreeEventStartedCount = 0; int mInternalNotifyViewTreeEventFinishedCount = 0; private MyContentCaptureSession(int id) { super(id); Loading Loading @@ -148,9 +180,7 @@ public class ContentCaptureSessionTest { } @Override void internalNotifyViewDisappeared(AutofillId id) { throw new UnsupportedOperationException("should not have been called"); } void internalNotifyViewDisappeared(AutofillId id) {} @Override void internalNotifyViewTextChanged(AutofillId id, CharSequence text) { Loading @@ -159,7 +189,11 @@ public class ContentCaptureSessionTest { @Override public void internalNotifyViewTreeEvent(boolean started) { throw new UnsupportedOperationException("should not have been called"); if (started) { mInternalNotifyViewTreeEventStartedCount += 1; } else { mInternalNotifyViewTreeEventFinishedCount += 1; } } @Override Loading