Merge "Refresh TCM settings when they change" into pi-dev
am: 3fa564030f
Change-Id: Ia8c3f5844dc908f2fb7671182bcc683850cf69d0
This commit is contained in:
@@ -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;
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,14 +78,13 @@ public final class TextClassificationManager {
|
||||
@NonNull
|
||||
public TextClassifier getTextClassifier() {
|
||||
synchronized (mLock) {
|
||||
if (mTextClassifier == null) {
|
||||
if (isSystemTextClassifierEnabled()) {
|
||||
mTextClassifier = getSystemTextClassifier();
|
||||
} else {
|
||||
mTextClassifier = getLocalTextClassifier();
|
||||
}
|
||||
if (mCustomTextClassifier != null) {
|
||||
return mCustomTextClassifier;
|
||||
} else if (isSystemTextClassifierEnabled()) {
|
||||
return getSystemTextClassifier();
|
||||
} else {
|
||||
return getLocalTextClassifier();
|
||||
}
|
||||
return mTextClassifier;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +95,7 @@ public final class TextClassificationManager {
|
||||
*/
|
||||
public void setTextClassifier(@Nullable TextClassifier textClassifier) {
|
||||
synchronized (mLock) {
|
||||
mTextClassifier = textClassifier;
|
||||
mCustomTextClassifier = textClassifier;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,9 +116,15 @@ public final class TextClassificationManager {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public TextClassificationConstants getSettings() {
|
||||
return mSettings;
|
||||
private TextClassificationConstants getSettings() {
|
||||
synchronized (mLock) {
|
||||
if (mSettings == null) {
|
||||
mSettings = TextClassificationConstants.loadFromString(Settings.Global.getString(
|
||||
mContext.getApplicationContext().getContentResolver(),
|
||||
Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
|
||||
}
|
||||
return mSettings;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
@@ -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 {
|
||||
@@ -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),
|
||||
@@ -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);
|
||||
@@ -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();
|
||||
}
|
||||
@@ -906,7 +908,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. **/
|
||||
@@ -942,8 +943,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
|
||||
@@ -982,7 +981,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);
|
||||
@@ -1010,6 +1009,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
|
||||
|
||||
Reference in New Issue
Block a user