TextClassificationManager.java revision 88be5a6cee59868eaee6f7b52fd8b2e6f6f28429
1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.view.textclassifier; 18 19import android.annotation.NonNull; 20import android.annotation.Nullable; 21import android.annotation.SystemService; 22import android.content.Context; 23import android.os.ServiceManager; 24import android.provider.Settings; 25import android.service.textclassifier.TextClassifierService; 26import android.view.textclassifier.TextClassifier.TextClassifierType; 27 28import com.android.internal.annotations.GuardedBy; 29import com.android.internal.util.Preconditions; 30 31/** 32 * Interface to the text classification service. 33 */ 34@SystemService(Context.TEXT_CLASSIFICATION_SERVICE) 35public final class TextClassificationManager { 36 37 private static final String LOG_TAG = "TextClassificationManager"; 38 39 private final Object mLock = new Object(); 40 private final TextClassificationSessionFactory mDefaultSessionFactory = 41 classificationContext -> new TextClassificationSession( 42 classificationContext, getTextClassifier()); 43 44 private final Context mContext; 45 private final TextClassificationConstants mSettings; 46 47 @GuardedBy("mLock") 48 private TextClassifier mTextClassifier; 49 @GuardedBy("mLock") 50 private TextClassifier mLocalTextClassifier; 51 @GuardedBy("mLock") 52 private TextClassifier mSystemTextClassifier; 53 @GuardedBy("mLock") 54 private TextClassificationSessionFactory mSessionFactory; 55 56 /** @hide */ 57 public TextClassificationManager(Context context) { 58 mContext = Preconditions.checkNotNull(context); 59 mSettings = TextClassificationConstants.loadFromString(Settings.Global.getString( 60 context.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS)); 61 mSessionFactory = mDefaultSessionFactory; 62 } 63 64 /** 65 * Returns the text classifier that was set via {@link #setTextClassifier(TextClassifier)}. 66 * If this is null, this method returns a default text classifier (i.e. either the system text 67 * classifier if one exists, or a local text classifier running in this app.) 68 * 69 * @see #setTextClassifier(TextClassifier) 70 */ 71 @NonNull 72 public TextClassifier getTextClassifier() { 73 synchronized (mLock) { 74 if (mTextClassifier == null) { 75 if (isSystemTextClassifierEnabled()) { 76 mTextClassifier = getSystemTextClassifier(); 77 } else { 78 mTextClassifier = getLocalTextClassifier(); 79 } 80 } 81 return mTextClassifier; 82 } 83 } 84 85 /** 86 * Sets the text classifier. 87 * Set to null to use the system default text classifier. 88 * Set to {@link TextClassifier#NO_OP} to disable text classifier features. 89 */ 90 public void setTextClassifier(@Nullable TextClassifier textClassifier) { 91 synchronized (mLock) { 92 mTextClassifier = textClassifier; 93 } 94 } 95 96 /** 97 * Returns a specific type of text classifier. 98 * If the specified text classifier cannot be found, this returns {@link TextClassifier#NO_OP}. 99 * 100 * @see TextClassifier#LOCAL 101 * @see TextClassifier#SYSTEM 102 * @hide 103 */ 104 public TextClassifier getTextClassifier(@TextClassifierType int type) { 105 switch (type) { 106 case TextClassifier.LOCAL: 107 return getLocalTextClassifier(); 108 default: 109 return getSystemTextClassifier(); 110 } 111 } 112 113 /** @hide */ 114 public TextClassificationConstants getSettings() { 115 return mSettings; 116 } 117 118 /** 119 * Call this method to start a text classification session with the given context. 120 * A session is created with a context helping the classifier better understand 121 * what the user needs and consists of queries and feedback events. The queries 122 * are directly related to providing useful functionality to the user and the events 123 * are a feedback loop back to the classifier helping it learn and better serve 124 * future queries. 125 * 126 * <p> All interactions with the returned classifier are considered part of a single 127 * session and are logically grouped. For example, when a text widget is focused 128 * all user interactions around text editing (selection, editing, etc) can be 129 * grouped together to allow the classifier get better. 130 * 131 * @param classificationContext The context in which classification would occur 132 * 133 * @return An instance to perform classification in the given context 134 */ 135 @NonNull 136 public TextClassifier createTextClassificationSession( 137 @NonNull TextClassificationContext classificationContext) { 138 Preconditions.checkNotNull(classificationContext); 139 final TextClassifier textClassifier = 140 mSessionFactory.createTextClassificationSession(classificationContext); 141 Preconditions.checkNotNull(textClassifier, "Session Factory should never return null"); 142 return textClassifier; 143 } 144 145 /** 146 * @see #createTextClassificationSession(TextClassificationContext, TextClassifier) 147 * @hide 148 */ 149 public TextClassifier createTextClassificationSession( 150 TextClassificationContext classificationContext, TextClassifier textClassifier) { 151 Preconditions.checkNotNull(classificationContext); 152 Preconditions.checkNotNull(textClassifier); 153 return new TextClassificationSession(classificationContext, textClassifier); 154 } 155 156 /** 157 * Sets a TextClassificationSessionFactory to be used to create session-aware TextClassifiers. 158 * 159 * @param factory the textClassification session factory. If this is null, the default factory 160 * will be used. 161 */ 162 public void setTextClassificationSessionFactory( 163 @Nullable TextClassificationSessionFactory factory) { 164 synchronized (mLock) { 165 if (factory != null) { 166 mSessionFactory = factory; 167 } else { 168 mSessionFactory = mDefaultSessionFactory; 169 } 170 } 171 } 172 173 private TextClassifier getSystemTextClassifier() { 174 synchronized (mLock) { 175 if (mSystemTextClassifier == null && isSystemTextClassifierEnabled()) { 176 try { 177 mSystemTextClassifier = new SystemTextClassifier(mContext, mSettings); 178 Log.d(LOG_TAG, "Initialized SystemTextClassifier"); 179 } catch (ServiceManager.ServiceNotFoundException e) { 180 Log.e(LOG_TAG, "Could not initialize SystemTextClassifier", e); 181 } 182 } 183 } 184 if (mSystemTextClassifier != null) { 185 return mSystemTextClassifier; 186 } 187 return TextClassifier.NO_OP; 188 } 189 190 private TextClassifier getLocalTextClassifier() { 191 synchronized (mLock) { 192 if (mLocalTextClassifier == null) { 193 if (mSettings.isLocalTextClassifierEnabled()) { 194 mLocalTextClassifier = new TextClassifierImpl(mContext, mSettings); 195 } else { 196 Log.d(LOG_TAG, "Local TextClassifier disabled"); 197 mLocalTextClassifier = TextClassifierImpl.NO_OP; 198 } 199 } 200 return mLocalTextClassifier; 201 } 202 } 203 204 private boolean isSystemTextClassifierEnabled() { 205 return mSettings.isSystemTextClassifierEnabled() 206 && TextClassifierService.getServiceComponentName(mContext) != null; 207 } 208 209 /** @hide */ 210 public static TextClassificationConstants getSettings(Context context) { 211 Preconditions.checkNotNull(context); 212 final TextClassificationManager tcm = 213 context.getSystemService(TextClassificationManager.class); 214 if (tcm != null) { 215 return tcm.mSettings; 216 } else { 217 return TextClassificationConstants.loadFromString(Settings.Global.getString( 218 context.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS)); 219 } 220 } 221} 222