Loading core/java/android/view/textclassifier/TextClassificationManager.java +77 −21 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; import android.content.Context; import android.database.ContentObserver; import android.os.ServiceManager; import android.provider.Settings; import android.service.textclassifier.TextClassifierService; Loading @@ -28,6 +29,8 @@ import android.view.textclassifier.TextClassifier.TextClassifierType; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import java.lang.ref.WeakReference; /** * Interface to the text classification service. */ Loading @@ -42,23 +45,27 @@ public final class TextClassificationManager { classificationContext, getTextClassifier()); private final Context mContext; private final TextClassificationConstants mSettings; private final SettingsObserver mSettingsObserver; @GuardedBy("mLock") private TextClassifier mTextClassifier; @Nullable private TextClassifier mCustomTextClassifier; @GuardedBy("mLock") @Nullable private TextClassifier mLocalTextClassifier; @GuardedBy("mLock") @Nullable private TextClassifier mSystemTextClassifier; @GuardedBy("mLock") private TextClassificationSessionFactory mSessionFactory; @GuardedBy("mLock") private TextClassificationConstants mSettings; /** @hide */ public TextClassificationManager(Context context) { mContext = Preconditions.checkNotNull(context); mSettings = TextClassificationConstants.loadFromString(Settings.Global.getString( context.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS)); mSessionFactory = mDefaultSessionFactory; mSettingsObserver = new SettingsObserver(this); } /** Loading @@ -71,14 +78,13 @@ public final class TextClassificationManager { @NonNull public TextClassifier getTextClassifier() { synchronized (mLock) { if (mTextClassifier == null) { if (isSystemTextClassifierEnabled()) { mTextClassifier = getSystemTextClassifier(); if (mCustomTextClassifier != null) { return mCustomTextClassifier; } else if (isSystemTextClassifierEnabled()) { return getSystemTextClassifier(); } else { mTextClassifier = getLocalTextClassifier(); } return getLocalTextClassifier(); } return mTextClassifier; } } Loading @@ -89,7 +95,7 @@ public final class TextClassificationManager { */ public void setTextClassifier(@Nullable TextClassifier textClassifier) { synchronized (mLock) { mTextClassifier = textClassifier; mCustomTextClassifier = textClassifier; } } Loading @@ -110,10 +116,16 @@ public final class TextClassificationManager { } } /** @hide */ public TextClassificationConstants getSettings() { private TextClassificationConstants getSettings() { synchronized (mLock) { if (mSettings == null) { mSettings = TextClassificationConstants.loadFromString(Settings.Global.getString( mContext.getApplicationContext().getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS)); } return mSettings; } } /** * Call this method to start a text classification session with the given context. Loading Loading @@ -170,11 +182,24 @@ public final class TextClassificationManager { } } @Override protected void finalize() throws Throwable { try { // Note that fields could be null if the constructor threw. if (mContext != null && mSettingsObserver != null) { mContext.getApplicationContext().getContentResolver() .unregisterContentObserver(mSettingsObserver); } } finally { super.finalize(); } } private TextClassifier getSystemTextClassifier() { synchronized (mLock) { if (mSystemTextClassifier == null && isSystemTextClassifierEnabled()) { try { mSystemTextClassifier = new SystemTextClassifier(mContext, mSettings); mSystemTextClassifier = new SystemTextClassifier(mContext, getSettings()); Log.d(LOG_TAG, "Initialized SystemTextClassifier"); } catch (ServiceManager.ServiceNotFoundException e) { Log.e(LOG_TAG, "Could not initialize SystemTextClassifier", e); Loading @@ -190,9 +215,9 @@ public final class TextClassificationManager { private TextClassifier getLocalTextClassifier() { synchronized (mLock) { if (mLocalTextClassifier == null) { if (mSettings.isLocalTextClassifierEnabled()) { if (getSettings().isLocalTextClassifierEnabled()) { mLocalTextClassifier = new TextClassifierImpl(mContext, mSettings, TextClassifier.NO_OP); new TextClassifierImpl(mContext, getSettings(), TextClassifier.NO_OP); } else { Log.d(LOG_TAG, "Local TextClassifier disabled"); mLocalTextClassifier = TextClassifier.NO_OP; Loading @@ -203,20 +228,51 @@ public final class TextClassificationManager { } private boolean isSystemTextClassifierEnabled() { return mSettings.isSystemTextClassifierEnabled() return getSettings().isSystemTextClassifierEnabled() && TextClassifierService.getServiceComponentName(mContext) != null; } private void invalidate() { synchronized (mLock) { mSettings = null; mLocalTextClassifier = null; mSystemTextClassifier = null; } } /** @hide */ public static TextClassificationConstants getSettings(Context context) { Preconditions.checkNotNull(context); final TextClassificationManager tcm = context.getSystemService(TextClassificationManager.class); if (tcm != null) { return tcm.mSettings; return tcm.getSettings(); } else { return TextClassificationConstants.loadFromString(Settings.Global.getString( context.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS)); context.getApplicationContext().getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS)); } } private static final class SettingsObserver extends ContentObserver { private final WeakReference<TextClassificationManager> mTcm; SettingsObserver(TextClassificationManager tcm) { super(null); mTcm = new WeakReference<>(tcm); tcm.mContext.getApplicationContext().getContentResolver().registerContentObserver( Settings.Global.getUriFor(Settings.Global.TEXT_CLASSIFIER_CONSTANTS), false /* notifyForDescendants */, this); } @Override public void onChange(boolean selfChange) { final TextClassificationManager tcm = mTcm.get(); if (tcm != null) { tcm.invalidate(); } } } } core/java/android/widget/SelectionActionModeHelper.java +12 −9 Original line number Diff line number Diff line Loading @@ -70,7 +70,6 @@ public final class SelectionActionModeHelper { private final Editor mEditor; private final TextView mTextView; private final TextClassificationHelper mTextClassificationHelper; private final TextClassificationConstants mTextClassificationSettings; @Nullable private TextClassification mTextClassification; private AsyncTask mTextClassificationAsyncTask; Loading @@ -84,7 +83,6 @@ public final class SelectionActionModeHelper { SelectionActionModeHelper(@NonNull Editor editor) { mEditor = Preconditions.checkNotNull(editor); mTextView = mEditor.getTextView(); mTextClassificationSettings = TextClassificationManager.getSettings(mTextView.getContext()); mTextClassificationHelper = new TextClassificationHelper( mTextView.getContext(), mTextView::getTextClassifier, Loading @@ -92,7 +90,7 @@ public final class SelectionActionModeHelper { 0, 1, mTextView.getTextLocales()); mSelectionTracker = new SelectionTracker(mTextView); if (mTextClassificationSettings.isSmartSelectionAnimationEnabled()) { if (getTextClassificationSettings().isSmartSelectionAnimationEnabled()) { mSmartSelectSprite = new SmartSelectSprite(mTextView.getContext(), editor.getTextView().mHighlightColor, mTextView::invalidate); } else { Loading @@ -105,7 +103,7 @@ public final class SelectionActionModeHelper { */ public void startSelectionActionModeAsync(boolean adjustSelection) { // Check if the smart selection should run for editable text. adjustSelection &= mTextClassificationSettings.isSmartSelectionEnabled(); adjustSelection &= getTextClassificationSettings().isSmartSelectionEnabled(); mSelectionTracker.onOriginalSelection( getText(mTextView), Loading Loading @@ -212,6 +210,10 @@ public final class SelectionActionModeHelper { return mSmartSelectSprite != null && mSmartSelectSprite.isAnimationActive(); } private TextClassificationConstants getTextClassificationSettings() { return TextClassificationManager.getSettings(mTextView.getContext()); } private void cancelAsyncTask() { if (mTextClassificationAsyncTask != null) { mTextClassificationAsyncTask.cancel(true); Loading Loading @@ -245,7 +247,7 @@ public final class SelectionActionModeHelper { if (result != null && text instanceof Spannable && (mTextView.isTextSelectable() || mTextView.isTextEditable())) { // Do not change the selection if TextClassifier should be dark launched. if (!mTextClassificationSettings.isModelDarkLaunchEnabled()) { if (!getTextClassificationSettings().isModelDarkLaunchEnabled()) { Selection.setSelection((Spannable) text, result.mStart, result.mEnd); mTextView.invalidate(); } Loading Loading @@ -911,7 +913,6 @@ public final class SelectionActionModeHelper { private static final int TRIM_DELTA = 120; // characters private final Context mContext; private final boolean mDarkLaunchEnabled; private Supplier<TextClassifier> mTextClassifier; /** The original TextView text. **/ Loading Loading @@ -947,8 +948,6 @@ public final class SelectionActionModeHelper { CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) { init(textClassifier, text, selectionStart, selectionEnd, locales); mContext = Preconditions.checkNotNull(context); mDarkLaunchEnabled = TextClassificationManager.getSettings(mContext) .isModelDarkLaunchEnabled(); } @UiThread Loading Loading @@ -987,7 +986,7 @@ public final class SelectionActionModeHelper { mTrimmedText, mRelativeStart, mRelativeEnd, mDefaultLocales); } // Do not classify new selection boundaries if TextClassifier should be dark launched. if (!mDarkLaunchEnabled) { if (!isDarkLaunchEnabled()) { mSelectionStart = Math.max(0, selection.getSelectionStartIndex() + mTrimStart); mSelectionEnd = Math.min( mText.length(), selection.getSelectionEndIndex() + mTrimStart); Loading Loading @@ -1015,6 +1014,10 @@ public final class SelectionActionModeHelper { } } private boolean isDarkLaunchEnabled() { return TextClassificationManager.getSettings(mContext).isModelDarkLaunchEnabled(); } private SelectionResult performClassification(@Nullable TextSelection selection) { if (!Objects.equals(mText, mLastClassificationText) || mSelectionStart != mLastClassificationSelectionStart Loading Loading
core/java/android/view/textclassifier/TextClassificationManager.java +77 −21 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; import android.content.Context; import android.database.ContentObserver; import android.os.ServiceManager; import android.provider.Settings; import android.service.textclassifier.TextClassifierService; Loading @@ -28,6 +29,8 @@ import android.view.textclassifier.TextClassifier.TextClassifierType; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import java.lang.ref.WeakReference; /** * Interface to the text classification service. */ Loading @@ -42,23 +45,27 @@ public final class TextClassificationManager { classificationContext, getTextClassifier()); private final Context mContext; private final TextClassificationConstants mSettings; private final SettingsObserver mSettingsObserver; @GuardedBy("mLock") private TextClassifier mTextClassifier; @Nullable private TextClassifier mCustomTextClassifier; @GuardedBy("mLock") @Nullable private TextClassifier mLocalTextClassifier; @GuardedBy("mLock") @Nullable private TextClassifier mSystemTextClassifier; @GuardedBy("mLock") private TextClassificationSessionFactory mSessionFactory; @GuardedBy("mLock") private TextClassificationConstants mSettings; /** @hide */ public TextClassificationManager(Context context) { mContext = Preconditions.checkNotNull(context); mSettings = TextClassificationConstants.loadFromString(Settings.Global.getString( context.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS)); mSessionFactory = mDefaultSessionFactory; mSettingsObserver = new SettingsObserver(this); } /** Loading @@ -71,14 +78,13 @@ public final class TextClassificationManager { @NonNull public TextClassifier getTextClassifier() { synchronized (mLock) { if (mTextClassifier == null) { if (isSystemTextClassifierEnabled()) { mTextClassifier = getSystemTextClassifier(); if (mCustomTextClassifier != null) { return mCustomTextClassifier; } else if (isSystemTextClassifierEnabled()) { return getSystemTextClassifier(); } else { mTextClassifier = getLocalTextClassifier(); } return getLocalTextClassifier(); } return mTextClassifier; } } Loading @@ -89,7 +95,7 @@ public final class TextClassificationManager { */ public void setTextClassifier(@Nullable TextClassifier textClassifier) { synchronized (mLock) { mTextClassifier = textClassifier; mCustomTextClassifier = textClassifier; } } Loading @@ -110,10 +116,16 @@ public final class TextClassificationManager { } } /** @hide */ public TextClassificationConstants getSettings() { private TextClassificationConstants getSettings() { synchronized (mLock) { if (mSettings == null) { mSettings = TextClassificationConstants.loadFromString(Settings.Global.getString( mContext.getApplicationContext().getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS)); } return mSettings; } } /** * Call this method to start a text classification session with the given context. Loading Loading @@ -170,11 +182,24 @@ public final class TextClassificationManager { } } @Override protected void finalize() throws Throwable { try { // Note that fields could be null if the constructor threw. if (mContext != null && mSettingsObserver != null) { mContext.getApplicationContext().getContentResolver() .unregisterContentObserver(mSettingsObserver); } } finally { super.finalize(); } } private TextClassifier getSystemTextClassifier() { synchronized (mLock) { if (mSystemTextClassifier == null && isSystemTextClassifierEnabled()) { try { mSystemTextClassifier = new SystemTextClassifier(mContext, mSettings); mSystemTextClassifier = new SystemTextClassifier(mContext, getSettings()); Log.d(LOG_TAG, "Initialized SystemTextClassifier"); } catch (ServiceManager.ServiceNotFoundException e) { Log.e(LOG_TAG, "Could not initialize SystemTextClassifier", e); Loading @@ -190,9 +215,9 @@ public final class TextClassificationManager { private TextClassifier getLocalTextClassifier() { synchronized (mLock) { if (mLocalTextClassifier == null) { if (mSettings.isLocalTextClassifierEnabled()) { if (getSettings().isLocalTextClassifierEnabled()) { mLocalTextClassifier = new TextClassifierImpl(mContext, mSettings, TextClassifier.NO_OP); new TextClassifierImpl(mContext, getSettings(), TextClassifier.NO_OP); } else { Log.d(LOG_TAG, "Local TextClassifier disabled"); mLocalTextClassifier = TextClassifier.NO_OP; Loading @@ -203,20 +228,51 @@ public final class TextClassificationManager { } private boolean isSystemTextClassifierEnabled() { return mSettings.isSystemTextClassifierEnabled() return getSettings().isSystemTextClassifierEnabled() && TextClassifierService.getServiceComponentName(mContext) != null; } private void invalidate() { synchronized (mLock) { mSettings = null; mLocalTextClassifier = null; mSystemTextClassifier = null; } } /** @hide */ public static TextClassificationConstants getSettings(Context context) { Preconditions.checkNotNull(context); final TextClassificationManager tcm = context.getSystemService(TextClassificationManager.class); if (tcm != null) { return tcm.mSettings; return tcm.getSettings(); } else { return TextClassificationConstants.loadFromString(Settings.Global.getString( context.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS)); context.getApplicationContext().getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS)); } } private static final class SettingsObserver extends ContentObserver { private final WeakReference<TextClassificationManager> mTcm; SettingsObserver(TextClassificationManager tcm) { super(null); mTcm = new WeakReference<>(tcm); tcm.mContext.getApplicationContext().getContentResolver().registerContentObserver( Settings.Global.getUriFor(Settings.Global.TEXT_CLASSIFIER_CONSTANTS), false /* notifyForDescendants */, this); } @Override public void onChange(boolean selfChange) { final TextClassificationManager tcm = mTcm.get(); if (tcm != null) { tcm.invalidate(); } } } }
core/java/android/widget/SelectionActionModeHelper.java +12 −9 Original line number Diff line number Diff line Loading @@ -70,7 +70,6 @@ public final class SelectionActionModeHelper { private final Editor mEditor; private final TextView mTextView; private final TextClassificationHelper mTextClassificationHelper; private final TextClassificationConstants mTextClassificationSettings; @Nullable private TextClassification mTextClassification; private AsyncTask mTextClassificationAsyncTask; Loading @@ -84,7 +83,6 @@ public final class SelectionActionModeHelper { SelectionActionModeHelper(@NonNull Editor editor) { mEditor = Preconditions.checkNotNull(editor); mTextView = mEditor.getTextView(); mTextClassificationSettings = TextClassificationManager.getSettings(mTextView.getContext()); mTextClassificationHelper = new TextClassificationHelper( mTextView.getContext(), mTextView::getTextClassifier, Loading @@ -92,7 +90,7 @@ public final class SelectionActionModeHelper { 0, 1, mTextView.getTextLocales()); mSelectionTracker = new SelectionTracker(mTextView); if (mTextClassificationSettings.isSmartSelectionAnimationEnabled()) { if (getTextClassificationSettings().isSmartSelectionAnimationEnabled()) { mSmartSelectSprite = new SmartSelectSprite(mTextView.getContext(), editor.getTextView().mHighlightColor, mTextView::invalidate); } else { Loading @@ -105,7 +103,7 @@ public final class SelectionActionModeHelper { */ public void startSelectionActionModeAsync(boolean adjustSelection) { // Check if the smart selection should run for editable text. adjustSelection &= mTextClassificationSettings.isSmartSelectionEnabled(); adjustSelection &= getTextClassificationSettings().isSmartSelectionEnabled(); mSelectionTracker.onOriginalSelection( getText(mTextView), Loading Loading @@ -212,6 +210,10 @@ public final class SelectionActionModeHelper { return mSmartSelectSprite != null && mSmartSelectSprite.isAnimationActive(); } private TextClassificationConstants getTextClassificationSettings() { return TextClassificationManager.getSettings(mTextView.getContext()); } private void cancelAsyncTask() { if (mTextClassificationAsyncTask != null) { mTextClassificationAsyncTask.cancel(true); Loading Loading @@ -245,7 +247,7 @@ public final class SelectionActionModeHelper { if (result != null && text instanceof Spannable && (mTextView.isTextSelectable() || mTextView.isTextEditable())) { // Do not change the selection if TextClassifier should be dark launched. if (!mTextClassificationSettings.isModelDarkLaunchEnabled()) { if (!getTextClassificationSettings().isModelDarkLaunchEnabled()) { Selection.setSelection((Spannable) text, result.mStart, result.mEnd); mTextView.invalidate(); } Loading Loading @@ -911,7 +913,6 @@ public final class SelectionActionModeHelper { private static final int TRIM_DELTA = 120; // characters private final Context mContext; private final boolean mDarkLaunchEnabled; private Supplier<TextClassifier> mTextClassifier; /** The original TextView text. **/ Loading Loading @@ -947,8 +948,6 @@ public final class SelectionActionModeHelper { CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) { init(textClassifier, text, selectionStart, selectionEnd, locales); mContext = Preconditions.checkNotNull(context); mDarkLaunchEnabled = TextClassificationManager.getSettings(mContext) .isModelDarkLaunchEnabled(); } @UiThread Loading Loading @@ -987,7 +986,7 @@ public final class SelectionActionModeHelper { mTrimmedText, mRelativeStart, mRelativeEnd, mDefaultLocales); } // Do not classify new selection boundaries if TextClassifier should be dark launched. if (!mDarkLaunchEnabled) { if (!isDarkLaunchEnabled()) { mSelectionStart = Math.max(0, selection.getSelectionStartIndex() + mTrimStart); mSelectionEnd = Math.min( mText.length(), selection.getSelectionEndIndex() + mTrimStart); Loading Loading @@ -1015,6 +1014,10 @@ public final class SelectionActionModeHelper { } } private boolean isDarkLaunchEnabled() { return TextClassificationManager.getSettings(mContext).isModelDarkLaunchEnabled(); } private SelectionResult performClassification(@Nullable TextSelection selection) { if (!Objects.equals(mText, mLastClassificationText) || mSelectionStart != mLastClassificationSelectionStart Loading