Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2057c38a authored by Felipe Leme's avatar Felipe Leme
Browse files

New, minor ContentCapture APIs for virtual views management.

Test: atest CtsContentCaptureServiceTestCases:android.contentcaptureservice.cts.CustomViewActivityTest
Test: atest CtsContentCaptureServiceTestCases # sanity check
Test: atest FrameworksCoreTests:android.view.contentcapture.ContentCaptureSessionTest
Test: m update-api
Bug: 117944706

Change-Id: I08bed441c6cc15673296f392e333c78018b14f65
parent 93ffb98e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -52313,6 +52313,8 @@ package android.view.contentcapture {
    method public final android.view.contentcapture.ContentCaptureSession createContentCaptureSession(android.view.contentcapture.ContentCaptureContext);
    method public final void destroy();
    method public final android.view.contentcapture.ContentCaptureSessionId getContentCaptureSessionId();
    method public android.view.autofill.AutofillId newAutofillId(android.view.autofill.AutofillId, int);
    method public final android.view.ViewStructure newVirtualViewStructure(android.view.autofill.AutofillId, int);
    method public final void notifyViewAppeared(android.view.ViewStructure);
    method public final void notifyViewDisappeared(android.view.autofill.AutofillId);
    method public final void notifyViewTextChanged(android.view.autofill.AutofillId, java.lang.CharSequence, int);
+5 −5
Original line number Diff line number Diff line
@@ -165,7 +165,7 @@ public abstract class ContentCaptureService extends Service {
     */
    public final void setContentCaptureWhitelist(@Nullable List<String> packages,
            @Nullable List<ComponentName> activities) {
        //TODO(b/111276913): implement
        //TODO(b/122595322): implement
    }

    /**
@@ -176,7 +176,7 @@ public abstract class ContentCaptureService extends Service {
     */
    public final void setActivityContentCaptureEnabled(@NonNull ComponentName activity,
            boolean enabled) {
        //TODO(b/111276913): implement
        //TODO(b/122595322): implement
    }

    /**
@@ -187,7 +187,7 @@ public abstract class ContentCaptureService extends Service {
     */
    public final void setPackageContentCaptureEnabled(@NonNull String packageName,
            boolean enabled) {
        //TODO(b/111276913): implement
        //TODO(b/122595322): implement
    }

    /**
@@ -196,7 +196,7 @@ public abstract class ContentCaptureService extends Service {
     */
    @NonNull
    public final Set<ComponentName> getContentCaptureDisabledActivities() {
        //TODO(b/111276913): implement
        //TODO(b/122595322): implement
        return null;
    }

@@ -206,7 +206,7 @@ public abstract class ContentCaptureService extends Service {
     */
    @NonNull
    public final Set<String> getContentCaptureDisabledPackages() {
        //TODO(b/111276913): implement
        //TODO(b/122595322): implement
        return null;
    }

+13 −0
Original line number Diff line number Diff line
@@ -8199,6 +8199,19 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     * <p>The populated structure is then passed to the service through
     * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}.
     *
     * <p><b>Note: </b>views that manage a virtual structure under this view must populate just
     * the node representing this view and return right away, then asynchronously report (not
     * necessarily in the UI thread) when the children nodes appear, disappear or have their text
     * changed by calling
     * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)},
     * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and
     * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence, int)}
     * respectively. The structure for the a child must be created using
     * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, int)}, and the
     * {@code autofillId} for a child can be obtained either through
     * {@code childStructure.getAutofillId()} or
     * {@link ContentCaptureSession#newAutofillId(AutofillId, int)}.
     *
     * <p><b>Note: </b>the following methods of the {@code structure} will be ignored:
     * <ul>
     *   <li>{@link ViewStructure#setChildCount(int)}
+23 −5
Original line number Diff line number Diff line
@@ -46,8 +46,7 @@ public abstract class ContentCaptureSession implements AutoCloseable {

    /**
     * Used on {@link #notifyViewTextChanged(AutofillId, CharSequence, int)} to indicate that the
     *
     * thext change was caused by user input (for example, through IME).
     * text change was caused by user input (for example, through IME).
     */
    public static final int FLAG_USER_INPUT = 0x1;

@@ -294,6 +293,26 @@ public abstract class ContentCaptureSession implements AutoCloseable {
        return new ViewNode.ViewStructureImpl(view);
    }

    /**
     * Creates a new {@link AutofillId} for a virtual child, so it can be used to uniquely identify
     * the children in the session.
     *
     * @param parentId id of the virtual view parent (it can be obtained by calling
     * {@link ViewStructure#getAutofillId()} on the parent).
     * @param virtualChildId id of the virtual child, relative to the parent.
     *
     * @return if for the virtual child
     *
     * @throws IllegalArgumentException if the {@code parentId} is a virtual child id.
     */
    public @NonNull AutofillId newAutofillId(@NonNull AutofillId parentId, int virtualChildId) {
        Preconditions.checkNotNull(parentId);
        Preconditions.checkArgument(!parentId.isVirtual(), "virtual ids cannot have children");
        // TODO(b/121197119): we need to add the session id to the AutofillId to make them unique
        // per session
        return new AutofillId(parentId, virtualChildId);
    }

    /**
     * Creates a {@link ViewStructure} for a "virtual" view, so it can be passed to
     * {@link #notifyViewAppeared(ViewStructure)} by the view managing the virtual view hierarchy.
@@ -303,12 +322,11 @@ public abstract class ContentCaptureSession implements AutoCloseable {
     * @param virtualId id of the virtual child, relative to the parent.
     *
     * @return a new {@link ViewStructure} that can be used for Content Capture purposes.
     *
     * @hide
     */
    @NonNull
    public final ViewStructure newVirtualViewStructure(@NonNull AutofillId parentId,
            int virtualId) {
        // TODO(b/121197119): use the constructor that takes a session id / assert on unit test.
        return new ViewNode.ViewStructureImpl(parentId, virtualId);
    }

+68 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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 android.view.contentcapture;

import static com.google.common.truth.Truth.assertThat;

import static org.testng.Assert.assertThrows;

import android.view.autofill.AutofillId;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;

/**
 * Unit test for {@link ContentCaptureSessionTest}.
 *
 * <p>To run it:
 * {@code atest FrameworksCoreTests:android.view.contentcapture.ContentCaptureSessionTest}
 */
@RunWith(MockitoJUnitRunner.class)
public class ContentCaptureSessionTest {

    /**
     * Uses a spy as ContentCaptureSession is abstract but (so far) we're testing its concrete
     * methods.
     */
    @Spy
    private ContentCaptureSession mMockSession;

    @Test
    public void testNewAutofillId_invalid() {
        assertThrows(NullPointerException.class, () -> mMockSession.newAutofillId(null, 42));
        assertThrows(IllegalArgumentException.class,
                () -> mMockSession.newAutofillId(new AutofillId(42, 42), 42));
    }

    @Test
    public void testNewAutofillId_valid() {
        final AutofillId parentId = new AutofillId(42);
        final AutofillId childId = mMockSession.newAutofillId(parentId, 108);
        assertThat(childId.getViewId()).isEqualTo(42);
        assertThat(childId.getVirtualChildId()).isEqualTo(108);
        // TODO(b/121197119): assert session id
    }

    @Test
    public void testNotifyXXX_null() {
        assertThrows(NullPointerException.class, () -> mMockSession.notifyViewAppeared(null));
        assertThrows(NullPointerException.class, () -> mMockSession.notifyViewDisappeared(null));
        assertThrows(NullPointerException.class,
                () -> mMockSession.notifyViewTextChanged(null, "whatever", 0));
    }
}