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

Commit 88be5a6c authored by Abodunrinwa Toki's avatar Abodunrinwa Toki
Browse files

Implement Stateful TextClassifier APIs.

Outstanding work tbd in other CLs
- Introduce request objects with session Ids
- Implement character based indexing for Selection events.

This CL hides the old Logger API but still keeps running so that we can
check that the modifications to the new API does not break anything.
We will remove the old Logger once we're convinced this is stable.

Please refer to I3c9ceea0863099fc4f0a5ce5e823c648ee9c4521 for previous
reviews related to this CL.

Bug: 74461129
Test: bit FrameworksCoreTests:android.view.textclassifier.TextClassificationManagerTest
Test: bit CtsViewTestCases:android.view.textclassifier.cts.TextClassificationManagerTest
Test: bit CtsWidgetTestCases:android.widget.cts.TextViewTest
Test: bit FrameworksCoreTests:android.widget.TextViewActivityTest
Change-Id: Iea744f1fa5964b4399290c31863ebeffa99af8d3
parent 8eaee9ee
Loading
Loading
Loading
Loading
+45 −33
Original line number Diff line number Diff line
@@ -50307,38 +50307,13 @@ package android.view.inputmethod {
package android.view.textclassifier {
  public abstract class Logger {
    ctor public Logger(android.view.textclassifier.Logger.Config);
    method public java.text.BreakIterator getTokenIterator(java.util.Locale);
    method public boolean isSmartSelection(java.lang.String);
    method public final void logSelectionActionEvent(int, int, int);
    method public final void logSelectionActionEvent(int, int, int, android.view.textclassifier.TextClassification);
    method public final void logSelectionModifiedEvent(int, int);
    method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextClassification);
    method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextSelection);
    method public final void logSelectionStartedEvent(int, int);
    method public abstract void writeEvent(android.view.textclassifier.SelectionEvent);
    field public static final int OUT_OF_BOUNDS = 2147483647; // 0x7fffffff
    field public static final int OUT_OF_BOUNDS_NEGATIVE = -2147483648; // 0x80000000
    field public static final java.lang.String WIDGET_CUSTOM_EDITTEXT = "customedit";
    field public static final java.lang.String WIDGET_CUSTOM_TEXTVIEW = "customview";
    field public static final java.lang.String WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
    field public static final java.lang.String WIDGET_EDITTEXT = "edittext";
    field public static final java.lang.String WIDGET_EDIT_WEBVIEW = "edit-webview";
    field public static final java.lang.String WIDGET_TEXTVIEW = "textview";
    field public static final java.lang.String WIDGET_UNKNOWN = "unknown";
    field public static final java.lang.String WIDGET_UNSELECTABLE_TEXTVIEW = "nosel-textview";
    field public static final java.lang.String WIDGET_WEBVIEW = "webview";
  }
  public static final class Logger.Config {
    ctor public Logger.Config(android.content.Context, java.lang.String, java.lang.String);
    method public java.lang.String getPackageName();
    method public java.lang.String getWidgetType();
    method public java.lang.String getWidgetVersion();
  }
  public final class SelectionEvent implements android.os.Parcelable {
    method public static android.view.textclassifier.SelectionEvent createSelectionActionEvent(int, int, int);
    method public static android.view.textclassifier.SelectionEvent createSelectionActionEvent(int, int, int, android.view.textclassifier.TextClassification);
    method public static android.view.textclassifier.SelectionEvent createSelectionModifiedEvent(int, int);
    method public static android.view.textclassifier.SelectionEvent createSelectionModifiedEvent(int, int, android.view.textclassifier.TextClassification);
    method public static android.view.textclassifier.SelectionEvent createSelectionModifiedEvent(int, int, android.view.textclassifier.TextSelection);
    method public static android.view.textclassifier.SelectionEvent createSelectionStartedEvent(int, int);
    method public int describeContents();
    method public long getDurationSincePreviousEvent();
    method public long getDurationSinceSessionStart();
@@ -50349,13 +50324,14 @@ package android.view.textclassifier {
    method public int getEventType();
    method public int getInvocationMethod();
    method public java.lang.String getPackageName();
    method public java.lang.String getSessionId();
    method public android.view.textclassifier.TextClassificationSessionId getSessionId();
    method public java.lang.String getSignature();
    method public int getSmartEnd();
    method public int getSmartStart();
    method public int getStart();
    method public java.lang.String getWidgetType();
    method public java.lang.String getWidgetVersion();
    method public static boolean isTerminal(int);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final int ACTION_ABANDON = 107; // 0x6b
    field public static final int ACTION_COPY = 101; // 0x65
@@ -50376,6 +50352,7 @@ package android.view.textclassifier {
    field public static final int EVENT_SMART_SELECTION_SINGLE = 3; // 0x3
    field public static final int INVOCATION_LINK = 2; // 0x2
    field public static final int INVOCATION_MANUAL = 1; // 0x1
    field public static final int INVOCATION_UNKNOWN = 0; // 0x0
  }
  public final class TextClassification implements android.os.Parcelable {
@@ -50423,19 +50400,45 @@ package android.view.textclassifier {
    field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassification.Options> CREATOR;
  }
  public final class TextClassificationContext {
    method public java.lang.String getPackageName();
    method public java.lang.String getWidgetType();
    method public java.lang.String getWidgetVersion();
  }
  public static final class TextClassificationContext.Builder {
    ctor public TextClassificationContext.Builder(java.lang.String, java.lang.String);
    method public android.view.textclassifier.TextClassificationContext build();
    method public android.view.textclassifier.TextClassificationContext.Builder setWidgetVersion(java.lang.String);
  }
  public final class TextClassificationManager {
    method public android.view.textclassifier.TextClassifier createTextClassificationSession(android.view.textclassifier.TextClassificationContext);
    method public android.view.textclassifier.TextClassifier getTextClassifier();
    method public void setTextClassificationSessionFactory(android.view.textclassifier.TextClassificationSessionFactory);
    method public void setTextClassifier(android.view.textclassifier.TextClassifier);
  }
  public abstract interface TextClassificationSessionFactory {
    method public abstract android.view.textclassifier.TextClassifier createTextClassificationSession(android.view.textclassifier.TextClassificationContext);
  }
  public final class TextClassificationSessionId implements android.os.Parcelable {
    method public int describeContents();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassificationSessionId> CREATOR;
  }
  public abstract interface TextClassifier {
    method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.view.textclassifier.TextClassification.Options);
    method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int);
    method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
    method public default void destroy();
    method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options);
    method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence);
    method public default android.view.textclassifier.Logger getLogger(android.view.textclassifier.Logger.Config);
    method public default int getMaxGenerateLinksTextLength();
    method public default boolean isDestroyed();
    method public default void onSelectionEvent(android.view.textclassifier.SelectionEvent);
    method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
    method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
    method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
@@ -50451,6 +50454,15 @@ package android.view.textclassifier {
    field public static final java.lang.String TYPE_PHONE = "phone";
    field public static final java.lang.String TYPE_UNKNOWN = "";
    field public static final java.lang.String TYPE_URL = "url";
    field public static final java.lang.String WIDGET_TYPE_CUSTOM_EDITTEXT = "customedit";
    field public static final java.lang.String WIDGET_TYPE_CUSTOM_TEXTVIEW = "customview";
    field public static final java.lang.String WIDGET_TYPE_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
    field public static final java.lang.String WIDGET_TYPE_EDITTEXT = "edittext";
    field public static final java.lang.String WIDGET_TYPE_EDIT_WEBVIEW = "edit-webview";
    field public static final java.lang.String WIDGET_TYPE_TEXTVIEW = "textview";
    field public static final java.lang.String WIDGET_TYPE_UNKNOWN = "unknown";
    field public static final java.lang.String WIDGET_TYPE_UNSELECTABLE_TEXTVIEW = "nosel-textview";
    field public static final java.lang.String WIDGET_TYPE_WEBVIEW = "webview";
  }
  public static final class TextClassifier.EntityConfig implements android.os.Parcelable {
+1 −1
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ import java.util.StringJoiner;
public final class DefaultLogger extends Logger {

    private static final String LOG_TAG = "DefaultLogger";
    private static final String CLASSIFIER_ID = "androidtc";
    static final String CLASSIFIER_ID = "androidtc";

    private static final int START_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_START;
    private static final int PREV_EVENT_DELTA = MetricsEvent.FIELD_SELECTION_SINCE_PREVIOUS;
+10 −38
Original line number Diff line number Diff line
@@ -18,56 +18,25 @@ package android.view.textclassifier;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
import android.content.Context;
import android.util.Log;

import com.android.internal.util.Preconditions;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.text.BreakIterator;
import java.util.Locale;
import java.util.Objects;
import java.util.UUID;

/**
 * A helper for logging TextClassifier related events.
 * @hide
 */
public abstract class Logger {

    /**
     * Use this to specify an indeterminate positive index.
     */
    public static final int OUT_OF_BOUNDS = Integer.MAX_VALUE;

    /**
     * Use this to specify an indeterminate negative index.
     */
    public static final int OUT_OF_BOUNDS_NEGATIVE = Integer.MIN_VALUE;

    private static final String LOG_TAG = "Logger";
    /* package */ static final boolean DEBUG_LOG_ENABLED = true;

    private static final String NO_SIGNATURE = "";

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @StringDef({WIDGET_TEXTVIEW, WIDGET_WEBVIEW, WIDGET_EDITTEXT,
            WIDGET_EDIT_WEBVIEW, WIDGET_CUSTOM_TEXTVIEW, WIDGET_CUSTOM_EDITTEXT,
            WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW, WIDGET_UNKNOWN})
    public @interface WidgetType {}

    public static final String WIDGET_TEXTVIEW = "textview";
    public static final String WIDGET_EDITTEXT = "edittext";
    public static final String WIDGET_UNSELECTABLE_TEXTVIEW = "nosel-textview";
    public static final String WIDGET_WEBVIEW = "webview";
    public static final String WIDGET_EDIT_WEBVIEW = "edit-webview";
    public static final String WIDGET_CUSTOM_TEXTVIEW = "customview";
    public static final String WIDGET_CUSTOM_EDITTEXT = "customedit";
    public static final String WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
    public static final String WIDGET_UNKNOWN = "unknown";

    private @SelectionEvent.InvocationMethod int mInvocationMethod;
    private SelectionEvent mPrevEvent;
    private SelectionEvent mSmartEvent;
@@ -108,7 +77,6 @@ public abstract class Logger {
        return false;
    }


    /**
     * Returns a token iterator for tokenizing text for logging purposes.
     */
@@ -299,6 +267,9 @@ public abstract class Logger {
                    // Selection did not change. Ignore event.
                    return;
                }
                break;
            default:
                // do nothing.
        }

        event.setEventTime(now);
@@ -325,9 +296,9 @@ public abstract class Logger {
        }
    }

    private String startNewSession() {
    private TextClassificationSessionId startNewSession() {
        endSession();
        return UUID.randomUUID().toString();
        return new TextClassificationSessionId();
    }

    private void endSession() {
@@ -372,12 +343,12 @@ public abstract class Logger {
        /**
         * @param context Context of the widget the logger logs for
         * @param widgetType a name for the widget being logged for. e.g.
         *      {@link #WIDGET_TEXTVIEW}
         *      {@link TextClassifier#WIDGET_TYPE_TEXTVIEW}
         * @param widgetVersion a string version info for the widget the logger logs for
         */
        public Config(
                @NonNull Context context,
                @WidgetType String widgetType,
                @TextClassifier.WidgetType String widgetType,
                @Nullable String widgetVersion) {
            mPackageName = Preconditions.checkNotNull(context).getPackageName();
            mWidgetType = widgetType;
@@ -392,7 +363,8 @@ public abstract class Logger {
        }

        /**
         * Returns the name for the widget being logged for. e.g. {@link #WIDGET_TEXTVIEW}.
         * Returns the name for the widget being logged for. e.g.
         * {@link TextClassifier#WIDGET_TYPE_TEXTVIEW}.
         */
        public String getWidgetType() {
            return mWidgetType;
+226 −23

File changed.

Preview size limit exceeded, changes collapsed.

+123 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.textclassifier;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.view.textclassifier.TextClassifier.WidgetType;

import com.android.internal.util.Preconditions;

import java.util.Locale;

/**
 * A representation of the context in which text classification would be performed.
 * @see TextClassificationManager#createTextClassificationSession(TextClassificationContext)
 */
public final class TextClassificationContext {

    private final String mPackageName;
    private final String mWidgetType;
    @Nullable private final String mWidgetVersion;

    private TextClassificationContext(
            String packageName,
            String widgetType,
            String widgetVersion) {
        mPackageName = Preconditions.checkNotNull(packageName);
        mWidgetType = Preconditions.checkNotNull(widgetType);
        mWidgetVersion = widgetVersion;
    }

    /**
     * Returns the package name for the calling package.
     */
    @NonNull
    public String getPackageName() {
        return mPackageName;
    }

    /**
     * Returns the widget type for this classification context.
     */
    @NonNull
    @WidgetType
    public String getWidgetType() {
        return mWidgetType;
    }

    /**
     * Returns a custom version string for the widget type.
     *
     * @see #getWidgetType()
     */
    @Nullable
    public String getWidgetVersion() {
        return mWidgetVersion;
    }

    @Override
    public String toString() {
        return String.format(Locale.US, "TextClassificationContext{"
                + "packageName=%s, widgetType=%s, widgetVersion=%s}",
                mPackageName, mWidgetType, mWidgetVersion);
    }

    /**
     * A builder for building a TextClassification context.
     */
    public static final class Builder {

        private final String mPackageName;
        private final String mWidgetType;

        @Nullable private String mWidgetVersion;

        /**
         * Initializes a new builder for text classification context objects.
         *
         * @param packageName the name of the calling package
         * @param widgetType the type of widget e.g. {@link TextClassifier#WIDGET_TYPE_TEXTVIEW}
         *
         * @return this builder
         */
        public Builder(@NonNull String packageName, @NonNull @WidgetType String widgetType) {
            mPackageName = Preconditions.checkNotNull(packageName);
            mWidgetType = Preconditions.checkNotNull(widgetType);
        }

        /**
         * Sets an optional custom version string for the widget type.
         *
         * @return this builder
         */
        public Builder setWidgetVersion(@Nullable String widgetVersion) {
            mWidgetVersion = widgetVersion;
            return this;
        }

        /**
         * Builds the text classification context object.
         *
         * @return the built TextClassificationContext object
         */
        @NonNull
        public TextClassificationContext build() {
            return new TextClassificationContext(mPackageName, mWidgetType, mWidgetVersion);
        }
    }
}
Loading