blob: 1737861ee716bd17c8ae9fa1fac859d31924b9d7 [file] [log] [blame]
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +00001/*
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
Abodunrinwa Toki88be5a62018-03-23 04:01:28 +000019import android.annotation.NonNull;
Abodunrinwa Tokidf61b032017-03-29 22:41:57 +010020import android.annotation.Nullable;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060021import android.annotation.SystemService;
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000022import android.content.Context;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080023import android.os.ServiceManager;
Abodunrinwa Tokidb8fc312018-02-26 21:37:51 +000024import android.provider.Settings;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080025import android.service.textclassifier.TextClassifierService;
Abodunrinwa Tokic7073a42018-02-28 23:02:13 +000026import android.view.textclassifier.TextClassifier.TextClassifierType;
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000027
Abodunrinwa Tokic7073a42018-02-28 23:02:13 +000028import com.android.internal.annotations.GuardedBy;
Abodunrinwa Toki43e03502017-01-13 13:46:33 -080029import com.android.internal.util.Preconditions;
30
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000031/**
32 * Interface to the text classification service.
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000033 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060034@SystemService(Context.TEXT_CLASSIFICATION_SERVICE)
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000035public final class TextClassificationManager {
36
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080037 private static final String LOG_TAG = "TextClassificationManager";
38
39 private final Object mLock = new Object();
Abodunrinwa Toki88be5a62018-03-23 04:01:28 +000040 private final TextClassificationSessionFactory mDefaultSessionFactory =
41 classificationContext -> new TextClassificationSession(
42 classificationContext, getTextClassifier());
Abodunrinwa Tokib89cf022017-02-06 19:53:22 +000043
Abodunrinwa Toki43e03502017-01-13 13:46:33 -080044 private final Context mContext;
Abodunrinwa Tokidb8fc312018-02-26 21:37:51 +000045 private final TextClassificationConstants mSettings;
Abodunrinwa Tokic7073a42018-02-28 23:02:13 +000046
47 @GuardedBy("mLock")
Abodunrinwa Tokidf61b032017-03-29 22:41:57 +010048 private TextClassifier mTextClassifier;
Abodunrinwa Tokic7073a42018-02-28 23:02:13 +000049 @GuardedBy("mLock")
50 private TextClassifier mLocalTextClassifier;
51 @GuardedBy("mLock")
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080052 private TextClassifier mSystemTextClassifier;
Abodunrinwa Toki88be5a62018-03-23 04:01:28 +000053 @GuardedBy("mLock")
54 private TextClassificationSessionFactory mSessionFactory;
Abodunrinwa Toki43e03502017-01-13 13:46:33 -080055
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000056 /** @hide */
Abodunrinwa Toki43e03502017-01-13 13:46:33 -080057 public TextClassificationManager(Context context) {
58 mContext = Preconditions.checkNotNull(context);
Abodunrinwa Tokidb8fc312018-02-26 21:37:51 +000059 mSettings = TextClassificationConstants.loadFromString(Settings.Global.getString(
60 context.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
Abodunrinwa Toki88be5a62018-03-23 04:01:28 +000061 mSessionFactory = mDefaultSessionFactory;
Abodunrinwa Toki43e03502017-01-13 13:46:33 -080062 }
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000063
Abodunrinwa Tokidf61b032017-03-29 22:41:57 +010064 /**
Abodunrinwa Tokic7073a42018-02-28 23:02:13 +000065 * 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)
Abodunrinwa Tokidf61b032017-03-29 22:41:57 +010070 */
Abodunrinwa Toki88be5a62018-03-23 04:01:28 +000071 @NonNull
Abodunrinwa Tokidf61b032017-03-29 22:41:57 +010072 public TextClassifier getTextClassifier() {
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080073 synchronized (mLock) {
Abodunrinwa Tokidf61b032017-03-29 22:41:57 +010074 if (mTextClassifier == null) {
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080075 if (isSystemTextClassifierEnabled()) {
Abodunrinwa Tokic7073a42018-02-28 23:02:13 +000076 mTextClassifier = getSystemTextClassifier();
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080077 } else {
Abodunrinwa Tokic7073a42018-02-28 23:02:13 +000078 mTextClassifier = getLocalTextClassifier();
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080079 }
Abodunrinwa Toki43e03502017-01-13 13:46:33 -080080 }
Abodunrinwa Tokidf61b032017-03-29 22:41:57 +010081 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) {
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080091 synchronized (mLock) {
Abodunrinwa Tokidf61b032017-03-29 22:41:57 +010092 mTextClassifier = textClassifier;
Abodunrinwa Toki43e03502017-01-13 13:46:33 -080093 }
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +000094 }
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080095
Abodunrinwa Tokic7073a42018-02-28 23:02:13 +000096 /**
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 */
Abodunrinwa Tokic7073a42018-02-28 23:02:13 +0000104 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
Abodunrinwa Toki88be5a62018-03-23 04:01:28 +0000118 /**
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
Abodunrinwa Tokic7073a42018-02-28 23:02:13 +0000173 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()) {
Abodunrinwa Toki253827f2018-04-24 19:19:48 +0100194 mLocalTextClassifier =
195 new TextClassifierImpl(mContext, mSettings, TextClassifier.NO_OP);
Abodunrinwa Tokic7073a42018-02-28 23:02:13 +0000196 } else {
197 Log.d(LOG_TAG, "Local TextClassifier disabled");
Abodunrinwa Toki253827f2018-04-24 19:19:48 +0100198 mLocalTextClassifier = TextClassifier.NO_OP;
Abodunrinwa Tokic7073a42018-02-28 23:02:13 +0000199 }
200 }
201 return mLocalTextClassifier;
202 }
203 }
204
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800205 private boolean isSystemTextClassifierEnabled() {
Abodunrinwa Tokic7073a42018-02-28 23:02:13 +0000206 return mSettings.isSystemTextClassifierEnabled()
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800207 && TextClassifierService.getServiceComponentName(mContext) != null;
208 }
Abodunrinwa Tokidb8fc312018-02-26 21:37:51 +0000209
210 /** @hide */
211 public static TextClassificationConstants getSettings(Context context) {
212 Preconditions.checkNotNull(context);
213 final TextClassificationManager tcm =
214 context.getSystemService(TextClassificationManager.class);
215 if (tcm != null) {
216 return tcm.mSettings;
217 } else {
218 return TextClassificationConstants.loadFromString(Settings.Global.getString(
219 context.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
220 }
221 }
Abodunrinwa Tokif001fef2017-01-04 23:51:42 +0000222}