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

Commit 0e6b43ed authored by Abodunrinwa Toki's avatar Abodunrinwa Toki
Browse files

Flags to enable/disable smart selection in EditText

1. smart_selection_enabled_for_edit_text
   Disables smart selection for editable text.
2. smart_selection_dark_launch
   Dark launch TextClassifierImpl.suggestSelection(...)
   In this mode we run the method, but never change the user's
   selection to measure the quality of the results based on what
   the user actually wanted.

Bug: 65959640
Test: Manually tested flags turn on/off feature with 'adb shell
settings put global' and GServices override.
Test: bit FrameworksCoreTests:android.provider.SettingsBackupTest
Change-Id: Iacc561c8ee004b0123de66ad1ee06b1f56b4e4b4
parent 24f51900
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -9574,6 +9574,22 @@ public final class Settings {
         */
        public static final String DEVICE_POLICY_CONSTANTS = "device_policy_constants";

        /**
         * TextClassifier specific settings.
         * This is encoded as a key=value list, separated by commas. Ex:
         *
         * <pre>
         * smart_selection_dark_launch              (boolean)
         * smart_selection_enabled_for_edit_text    (boolean)
         * </pre>
         *
         * <p>
         * Type: string
         * @hide
         * see also android.view.textclassifier.TextClassifierConstants
         */
        public static final String TEXT_CLASSIFIER_CONSTANTS = "text_classifier_constants";

        /**
         * Get the key that retrieves a bluetooth headset's priority.
         * @hide
+8 −0
Original line number Diff line number Diff line
@@ -152,4 +152,12 @@ public interface TextClassifier {
     */
    @WorkerThread
    default void logEvent(String source, String event) {}

    /**
     * Returns this TextClassifier's settings.
     * @hide
     */
    default TextClassifierConstants getSettings() {
        return TextClassifierConstants.DEFAULT;
    }
}
+90 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.Nullable;
import android.util.KeyValueListParser;
import android.util.Slog;

/**
 * TextClassifier specific settings.
 * This is encoded as a key=value list, separated by commas. Ex:
 *
 * <pre>
 * smart_selection_dark_launch              (boolean)
 * smart_selection_enabled_for_edit_text    (boolean)
 * </pre>
 *
 * <p>
 * Type: string
 * see also android.provider.Settings.Global.TEXT_CLASSIFIER_CONSTANTS
 *
 * Example of setting the values for testing.
 * adb shell settings put global text_classifier_constants smart_selection_dark_launch=true,smart_selection_enabled_for_edit_text=true
 * @hide
 */
public final class TextClassifierConstants {

    private static final String LOG_TAG = "TextClassifierConstants";

    private static final String SMART_SELECTION_DARK_LAUNCH =
            "smart_selection_dark_launch";
    private static final String SMART_SELECTION_ENABLED_FOR_EDIT_TEXT =
            "smart_selection_enabled_for_edit_text";

    private static final boolean SMART_SELECTION_DARK_LAUNCH_DEFAULT = false;
    private static final boolean SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT = true;

    /** Default settings. */
    static final TextClassifierConstants DEFAULT = new TextClassifierConstants();

    private final boolean mDarkLaunch;
    private final boolean mSuggestSelectionEnabledForEditableText;

    private TextClassifierConstants() {
        mDarkLaunch = SMART_SELECTION_DARK_LAUNCH_DEFAULT;
        mSuggestSelectionEnabledForEditableText = SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT;
    }

    private TextClassifierConstants(@Nullable String settings) {
        final KeyValueListParser parser = new KeyValueListParser(',');
        try {
            parser.setString(settings);
        } catch (IllegalArgumentException e) {
            // Failed to parse the settings string, log this and move on with defaults.
            Slog.e(LOG_TAG, "Bad TextClassifier settings: " + settings);
        }
        mDarkLaunch = parser.getBoolean(
                SMART_SELECTION_DARK_LAUNCH,
                SMART_SELECTION_DARK_LAUNCH_DEFAULT);
        mSuggestSelectionEnabledForEditableText = parser.getBoolean(
                SMART_SELECTION_ENABLED_FOR_EDIT_TEXT,
                SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT);
    }

    static TextClassifierConstants loadFromString(String settings) {
        return new TextClassifierConstants(settings);
    }

    public boolean isDarkLaunch() {
        return mDarkLaunch;
    }

    public boolean isSuggestSelectionEnabledForEditableText() {
        return mSuggestSelectionEnabledForEditableText;
    }
}
+13 −1
Original line number Diff line number Diff line
@@ -24,12 +24,12 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.icu.text.BreakIterator;
import android.net.Uri;
import android.os.LocaleList;
import android.os.ParcelFileDescriptor;
import android.provider.Browser;
import android.provider.ContactsContract;
import android.provider.Settings;
import android.text.Spannable;
import android.text.TextUtils;
import android.text.method.WordIterator;
@@ -47,6 +47,7 @@ import com.android.internal.util.Preconditions;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -91,6 +92,8 @@ final class TextClassifierImpl implements TextClassifier {
    @GuardedBy("mSmartSelectionLock") // Do not access outside this lock.
    private SmartSelection mSmartSelection;

    private TextClassifierConstants mSettings;

    TextClassifierImpl(Context context) {
        mContext = Preconditions.checkNotNull(context);
    }
@@ -189,6 +192,15 @@ final class TextClassifierImpl implements TextClassifier {
        }
    }

    @Override
    public TextClassifierConstants getSettings() {
        if (mSettings == null) {
            mSettings = TextClassifierConstants.loadFromString(Settings.Global.getString(
                    mContext.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
        }
        return mSettings;
    }

    private SmartSelection getSmartSelection(LocaleList localeList) throws FileNotFoundException {
        synchronized (mSmartSelectionLock) {
            localeList = localeList == null ? LocaleList.getEmptyLocaleList() : localeList;
+20 −10
Original line number Diff line number Diff line
@@ -95,11 +95,15 @@ public final class SelectionActionModeHelper {
    }

    public void startActionModeAsync(boolean adjustSelection) {
        // Check if the smart selection should run for editable text.
        adjustSelection &= !mTextView.isTextEditable()
                || mTextView.getTextClassifier().getSettings()
                        .isSuggestSelectionEnabledForEditableText();

        mSelectionTracker.onOriginalSelection(
                getText(mTextView),
                mTextView.getSelectionStart(),
                mTextView.getSelectionEnd(),
                mTextView.isTextEditable());
                mTextView.getSelectionEnd());
        cancelAsyncTask();
        if (skipTextClassification()) {
            startActionMode(null);
@@ -196,7 +200,10 @@ public final class SelectionActionModeHelper {
    private void startActionMode(@Nullable SelectionResult result) {
        final CharSequence text = getText(mTextView);
        if (result != null && text instanceof Spannable) {
            // Do not change the selection if TextClassifier should be dark launched.
            if (!mTextView.getTextClassifier().getSettings().isDarkLaunch()) {
                Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
            }
            mTextClassification = result.mClassification;
        } else {
            mTextClassification = null;
@@ -377,7 +384,7 @@ public final class SelectionActionModeHelper {
    }

    private void resetTextClassificationHelper() {
        mTextClassificationHelper.reset(
        mTextClassificationHelper.init(
                mTextView.getTextClassifier(),
                getText(mTextView),
                mTextView.getSelectionStart(), mTextView.getSelectionEnd(),
@@ -415,8 +422,7 @@ public final class SelectionActionModeHelper {
        /**
         * Called when the original selection happens, before smart selection is triggered.
         */
        public void onOriginalSelection(
                CharSequence text, int selectionStart, int selectionEnd, boolean editableText) {
        public void onOriginalSelection(CharSequence text, int selectionStart, int selectionEnd) {
            // 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();
@@ -812,11 +818,11 @@ public final class SelectionActionModeHelper {

        TextClassificationHelper(TextClassifier textClassifier,
                CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
            reset(textClassifier, text, selectionStart, selectionEnd, locales);
            init(textClassifier, text, selectionStart, selectionEnd, locales);
        }

        @UiThread
        public void reset(TextClassifier textClassifier,
        public void init(TextClassifier textClassifier,
                CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
            mTextClassifier = Preconditions.checkNotNull(textClassifier);
            mText = Preconditions.checkNotNull(text).toString();
@@ -839,8 +845,12 @@ public final class SelectionActionModeHelper {
            trimText();
            final TextSelection selection = mTextClassifier.suggestSelection(
                    mTrimmedText, mRelativeStart, mRelativeEnd, mLocales);
            // Do not classify new selection boundaries if TextClassifier should be dark launched.
            if (!mTextClassifier.getSettings().isDarkLaunch()) {
                mSelectionStart = Math.max(0, selection.getSelectionStartIndex() + mTrimStart);
            mSelectionEnd = Math.min(mText.length(), selection.getSelectionEndIndex() + mTrimStart);
                mSelectionEnd = Math.min(
                        mText.length(), selection.getSelectionEndIndex() + mTrimStart);
            }
            return performClassification(selection);
        }

Loading