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

Commit 92c6decb authored by Jan Althaus's avatar Jan Althaus
Browse files

Logging for linkify selections

Bug: 67629726, 70246800
Test: Manually validated, ran CTS tests, and framework tests
Change-Id: Icd41f1e171767bc466f47c87a6ab611185745fd4
parent fd673f32
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -50292,7 +50292,7 @@ package android.view.textclassifier.logging {
    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);
    method public final void logSelectionStartedEvent(int, int);
    method public abstract void writeEvent(android.view.textclassifier.logging.SelectionEvent);
    field public static final int OUT_OF_BOUNDS = 2147483647; // 0x7fffffff
    field public static final int OUT_OF_BOUNDS_NEGATIVE = -2147483648; // 0x80000000
@@ -50322,6 +50322,7 @@ package android.view.textclassifier.logging {
    method public int getEventIndex();
    method public long getEventTime();
    method public int getEventType();
    method public int getInvocationMethod();
    method public java.lang.String getPackageName();
    method public java.lang.String getSessionId();
    method public java.lang.String getSignature();
@@ -50346,6 +50347,8 @@ package android.view.textclassifier.logging {
    field public static final int EVENT_SELECTION_STARTED = 1; // 0x1
    field public static final int EVENT_SMART_SELECTION_MULTI = 4; // 0x4
    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
  }
}
+27 −3
Original line number Diff line number Diff line
@@ -79,7 +79,7 @@ public final class DefaultLogger extends Logger {
        Preconditions.checkNotNull(event);
        final LogMaker log = new LogMaker(MetricsEvent.TEXT_SELECTION_SESSION)
                .setType(getLogType(event))
                .setSubtype(MetricsEvent.TEXT_SELECTION_INVOCATION_MANUAL)
                .setSubtype(getLogSubType(event))
                .setPackageName(event.getPackageName())
                .addTaggedData(START_EVENT_DELTA, event.getDurationSinceSessionStart())
                .addTaggedData(PREV_EVENT_DELTA, event.getDurationSincePreviousEvent())
@@ -136,6 +136,17 @@ public final class DefaultLogger extends Logger {
        }
    }

    private static int getLogSubType(SelectionEvent event) {
        switch (event.getInvocationMethod()) {
            case SelectionEvent.INVOCATION_MANUAL:
                return MetricsEvent.TEXT_SELECTION_INVOCATION_MANUAL;
            case SelectionEvent.INVOCATION_LINK:
                return MetricsEvent.TEXT_SELECTION_INVOCATION_LINK;
            default:
                return MetricsEvent.TEXT_SELECTION_INVOCATION_UNKNOWN;
        }
    }

    private static String getLogTypeString(int logType) {
        switch (logType) {
            case MetricsEvent.ACTION_TEXT_SELECTION_OVERTYPE:
@@ -175,6 +186,17 @@ public final class DefaultLogger extends Logger {
        }
    }

    private static String getLogSubTypeString(int logSubType) {
        switch (logSubType) {
            case MetricsEvent.TEXT_SELECTION_INVOCATION_MANUAL:
                return "MANUAL";
            case MetricsEvent.TEXT_SELECTION_INVOCATION_LINK:
                return "LINK";
            default:
                return UNKNOWN;
        }
    }

    private static void debugLog(LogMaker log) {
        if (!DEBUG_LOG_ENABLED) return;

@@ -192,6 +214,7 @@ public final class DefaultLogger extends Logger {
        final String model = Objects.toString(log.getTaggedData(MODEL_NAME), UNKNOWN);
        final String entity = Objects.toString(log.getTaggedData(ENTITY_TYPE), UNKNOWN);
        final String type = getLogTypeString(log.getType());
        final String subType = getLogSubTypeString(log.getSubtype());
        final int smartStart = Integer.parseInt(
                Objects.toString(log.getTaggedData(SMART_START), ZERO));
        final int smartEnd = Integer.parseInt(
@@ -201,8 +224,9 @@ public final class DefaultLogger extends Logger {
        final int eventEnd = Integer.parseInt(
                Objects.toString(log.getTaggedData(EVENT_END), ZERO));

        Log.d(LOG_TAG, String.format("%2d: %s/%s, range=%d,%d - smart_range=%d,%d (%s/%s)",
                index, type, entity, eventStart, eventEnd, smartStart, smartEnd, widget, model));
        Log.d(LOG_TAG, String.format("%2d: %s/%s/%s, range=%d,%d - smart_range=%d,%d (%s/%s)",
                index, type, subType, entity, eventStart, eventEnd, smartStart, smartEnd, widget,
                model));
    }

    /**
+14 −7
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ public abstract class Logger {
    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;
    private SelectionEvent mStartEvent;
@@ -124,16 +125,19 @@ public abstract class Logger {
    /**
     * Logs a "selection started" event.
     *
     * @param invocationMethod  the way the selection was triggered
     * @param start  the token index of the selected token
     */
    public final void logSelectionStartedEvent(int start) {
    public final void logSelectionStartedEvent(
            @SelectionEvent.InvocationMethod int invocationMethod, int start) {
        if (mConfig == null) {
            return;
        }

        mInvocationMethod = invocationMethod;
        logEvent(new SelectionEvent(
                start, start + 1, SelectionEvent.EVENT_SELECTION_STARTED,
                TextClassifier.TYPE_UNKNOWN, NO_SIGNATURE, mConfig));
                TextClassifier.TYPE_UNKNOWN, mInvocationMethod, NO_SIGNATURE, mConfig));
    }

    /**
@@ -152,7 +156,7 @@ public abstract class Logger {

        logEvent(new SelectionEvent(
                start, end, SelectionEvent.EVENT_SELECTION_MODIFIED,
                TextClassifier.TYPE_UNKNOWN, NO_SIGNATURE, mConfig));
                TextClassifier.TYPE_UNKNOWN, mInvocationMethod, NO_SIGNATURE, mConfig));
    }

    /**
@@ -179,7 +183,7 @@ public abstract class Logger {
        final String signature = classification.getSignature();
        logEvent(new SelectionEvent(
                start, end, SelectionEvent.EVENT_SELECTION_MODIFIED,
                entityType, signature, mConfig));
                entityType, mInvocationMethod, signature, mConfig));
    }

    /**
@@ -213,7 +217,8 @@ public abstract class Logger {
                ? selection.getEntity(0)
                : TextClassifier.TYPE_UNKNOWN;
        final String signature = selection.getSignature();
        logEvent(new SelectionEvent(start, end, eventType, entityType, signature, mConfig));
        logEvent(new SelectionEvent(start, end, eventType, entityType, mInvocationMethod, signature,
                mConfig));
    }

    /**
@@ -234,7 +239,8 @@ public abstract class Logger {
        }

        logEvent(new SelectionEvent(
                start, end, actionType, TextClassifier.TYPE_UNKNOWN, NO_SIGNATURE, mConfig));
                start, end, actionType, TextClassifier.TYPE_UNKNOWN, mInvocationMethod,
                NO_SIGNATURE, mConfig));
    }

    /**
@@ -265,7 +271,8 @@ public abstract class Logger {
                ? classification.getEntity(0)
                : TextClassifier.TYPE_UNKNOWN;
        final String signature = classification.getSignature();
        logEvent(new SelectionEvent(start, end, actionType, entityType, signature, mConfig));
        logEvent(new SelectionEvent(start, end, actionType, entityType, mInvocationMethod,
                signature, mConfig));
    }

    private void logEvent(@NonNull SelectionEvent event) {
+20 −1
Original line number Diff line number Diff line
@@ -98,6 +98,16 @@ public final class SelectionEvent {
    /** Something else other than User or the default TextClassifier triggered a selection. */
    public static final int EVENT_AUTO_SELECTION = 5;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef({INVOCATION_MANUAL, INVOCATION_LINK})
    public @interface InvocationMethod {}

    /** Selection was invoked by the user long pressing, double tapping, or dragging to select. */
    public static final int INVOCATION_MANUAL = 1;
    /** Selection was invoked by the user tapping on a link. */
    public static final int INVOCATION_LINK = 2;

    private final int mAbsoluteStart;
    private final int mAbsoluteEnd;
    private final @EventType int mEventType;
@@ -105,6 +115,7 @@ public final class SelectionEvent {
    @Nullable private final String mWidgetVersion;
    private final String mPackageName;
    private final String mWidgetType;
    private final @InvocationMethod int mInvocationMethod;

    // These fields should only be set by creator of a SelectionEvent.
    private String mSignature;
@@ -121,7 +132,7 @@ public final class SelectionEvent {
    SelectionEvent(
            int start, int end,
            @EventType int eventType, @EntityType String entityType,
            String signature, Logger.Config config) {
            @InvocationMethod int invocationMethod, String signature, Logger.Config config) {
        Preconditions.checkArgument(end >= start, "end cannot be less than start");
        mAbsoluteStart = start;
        mAbsoluteEnd = end;
@@ -132,6 +143,7 @@ public final class SelectionEvent {
        mWidgetVersion = config.getWidgetVersion();
        mPackageName = Preconditions.checkNotNull(config.getPackageName());
        mWidgetType = Preconditions.checkNotNull(config.getWidgetType());
        mInvocationMethod = invocationMethod;
    }

    int getAbsoluteStart() {
@@ -179,6 +191,13 @@ public final class SelectionEvent {
        return mWidgetVersion;
    }

    /**
     * Returns the way the selection mode was invoked.
     */
    public @InvocationMethod int getInvocationMethod() {
        return mInvocationMethod;
    }

    /**
     * Returns the signature of the text classifier result associated with this event.
     */
+15 −6
Original line number Diff line number Diff line
@@ -111,7 +111,8 @@ public final class SelectionActionModeHelper {
        mSelectionTracker.onOriginalSelection(
                getText(mTextView),
                mTextView.getSelectionStart(),
                mTextView.getSelectionEnd());
                mTextView.getSelectionEnd(),
                false /*isLink*/);
        cancelAsyncTask();
        if (skipTextClassification()) {
            startSelectionActionMode(null);
@@ -134,7 +135,11 @@ public final class SelectionActionModeHelper {
     * Starts Link ActionMode.
     */
    public void startLinkActionModeAsync(TextLinks.TextLink textLink) {
        //TODO: tracking/logging
        mSelectionTracker.onOriginalSelection(
                getText(mTextView),
                mTextView.getSelectionStart(),
                mTextView.getSelectionEnd(),
                true /*isLink*/);
        cancelAsyncTask();
        if (skipTextClassification()) {
            startLinkActionMode(null);
@@ -483,7 +488,8 @@ public final class SelectionActionModeHelper {
        /**
         * Called when the original selection happens, before smart selection is triggered.
         */
        public void onOriginalSelection(CharSequence text, int selectionStart, int selectionEnd) {
        public void onOriginalSelection(
                CharSequence text, int selectionStart, int selectionEnd, boolean isLink) {
            // If we abandoned a selection and created a new one very shortly after, we may still
            // have a pending request to log ABANDON, which we flush here.
            mDelayedLogAbandon.flush();
@@ -492,7 +498,8 @@ public final class SelectionActionModeHelper {
            mOriginalEnd = mSelectionEnd = selectionEnd;
            mAllowReset = false;
            maybeInvalidateLogger();
            mLogger.logSelectionStarted(text, selectionStart);
            mLogger.logSelectionStarted(text, selectionStart,
                    isLink ? SelectionEvent.INVOCATION_LINK : SelectionEvent.INVOCATION_MANUAL);
        }

        /**
@@ -675,7 +682,9 @@ public final class SelectionActionModeHelper {
            return Logger.WIDGET_UNSELECTABLE_TEXTVIEW;
        }

        public void logSelectionStarted(CharSequence text, int index) {
        public void logSelectionStarted(
                CharSequence text, int index,
                @SelectionEvent.InvocationMethod int invocationMethod) {
            try {
                Preconditions.checkNotNull(text);
                Preconditions.checkArgumentInRange(index, 0, text.length(), "index");
@@ -684,7 +693,7 @@ public final class SelectionActionModeHelper {
                }
                mTokenIterator.setText(mText);
                mStartIndex = index;
                mLogger.logSelectionStartedEvent(0);
                mLogger.logSelectionStartedEvent(invocationMethod, 0);
            } catch (Exception e) {
                // Avoid crashes due to logging.
                Log.d(LOG_TAG, e.getMessage());