blob: 30c4e900f83cc748196b7863085b332fb9a3e2ac [file] [log] [blame]
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -08001/*
2 * Copyright (C) 2018 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.service.textclassifier;
18
19import android.Manifest;
Tony Mak9920dbb2019-01-23 19:49:30 +000020import android.annotation.MainThread;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080021import android.annotation.NonNull;
22import android.annotation.Nullable;
23import android.annotation.SystemApi;
24import android.app.Service;
25import android.content.ComponentName;
26import android.content.Context;
27import android.content.Intent;
28import android.content.pm.PackageManager;
Makoto Onuki700feef2018-02-15 10:59:41 -080029import android.content.pm.ResolveInfo;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080030import android.content.pm.ServiceInfo;
Tony Mak9920dbb2019-01-23 19:49:30 +000031import android.os.Bundle;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080032import android.os.CancellationSignal;
Tony Mak9920dbb2019-01-23 19:49:30 +000033import android.os.Handler;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080034import android.os.IBinder;
Tony Mak9920dbb2019-01-23 19:49:30 +000035import android.os.Looper;
36import android.os.Parcelable;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080037import android.os.RemoteException;
38import android.text.TextUtils;
39import android.util.Slog;
Tony Mak0be540b2018-11-09 16:58:35 +000040import android.view.textclassifier.ConversationActions;
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +000041import android.view.textclassifier.SelectionEvent;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080042import android.view.textclassifier.TextClassification;
Abodunrinwa Toki080c8542018-03-27 00:04:06 +010043import android.view.textclassifier.TextClassificationContext;
Abodunrinwa Tokie6d974a2018-03-06 18:18:30 +000044import android.view.textclassifier.TextClassificationManager;
Abodunrinwa Toki080c8542018-03-27 00:04:06 +010045import android.view.textclassifier.TextClassificationSessionId;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080046import android.view.textclassifier.TextClassifier;
Abodunrinwa Toki37ccedc2018-12-11 00:35:11 +000047import android.view.textclassifier.TextClassifierEvent;
Tony Mak0be540b2018-11-09 16:58:35 +000048import android.view.textclassifier.TextLanguage;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080049import android.view.textclassifier.TextLinks;
50import android.view.textclassifier.TextSelection;
51
Abodunrinwa Toki080c8542018-03-27 00:04:06 +010052import com.android.internal.util.Preconditions;
53
Tony Mak9920dbb2019-01-23 19:49:30 +000054import java.lang.ref.WeakReference;
55import java.util.concurrent.ExecutorService;
56import java.util.concurrent.Executors;
57
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080058/**
59 * Abstract base class for the TextClassifier service.
60 *
61 * <p>A TextClassifier service provides text classification related features for the system.
62 * The system's default TextClassifierService is configured in
63 * {@code config_defaultTextClassifierService}. If this config has no value, a
64 * {@link android.view.textclassifier.TextClassifierImpl} is loaded in the calling app's process.
65 *
66 * <p>See: {@link TextClassifier}.
Abodunrinwa Tokie6d974a2018-03-06 18:18:30 +000067 * See: {@link TextClassificationManager}.
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080068 *
69 * <p>Include the following in the manifest:
70 *
71 * <pre>
72 * {@literal
73 * <service android:name=".YourTextClassifierService"
74 * android:permission="android.permission.BIND_TEXTCLASSIFIER_SERVICE">
75 * <intent-filter>
76 * <action android:name="android.service.textclassifier.TextClassifierService" />
77 * </intent-filter>
78 * </service>}</pre>
79 *
Tony Mak9920dbb2019-01-23 19:49:30 +000080 * <p>From {@link android.os.Build.VERSION_CODES#Q} onward, all callbacks are called on the main
81 * thread. Prior to Q, there is no guarantee on what thread the callback will happen. You should
82 * make sure the callbacks are executed in your desired thread by using a executor, a handler or
83 * something else along the line.
84 *
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080085 * @see TextClassifier
86 * @hide
87 */
88@SystemApi
89public abstract class TextClassifierService extends Service {
90
91 private static final String LOG_TAG = "TextClassifierService";
92
93 /**
94 * The {@link Intent} that must be declared as handled by the service.
95 * To be supported, the service must also require the
96 * {@link android.Manifest.permission#BIND_TEXTCLASSIFIER_SERVICE} permission so
97 * that other applications can not abuse it.
98 */
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -080099 public static final String SERVICE_INTERFACE =
100 "android.service.textclassifier.TextClassifierService";
101
Tony Mak9920dbb2019-01-23 19:49:30 +0000102 /** @hide **/
103 private static final String KEY_RESULT = "key_result";
104
105 private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper(), null, true);
106 private final ExecutorService mSingleThreadExecutor = Executors.newSingleThreadExecutor();
107
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800108 private final ITextClassifierService.Stub mBinder = new ITextClassifierService.Stub() {
109
110 // TODO(b/72533911): Implement cancellation signal
111 @NonNull private final CancellationSignal mCancellationSignal = new CancellationSignal();
112
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800113 @Override
114 public void onSuggestSelection(
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100115 TextClassificationSessionId sessionId,
Tony Mak9920dbb2019-01-23 19:49:30 +0000116 TextSelection.Request request, ITextClassifierCallback callback) {
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100117 Preconditions.checkNotNull(request);
118 Preconditions.checkNotNull(callback);
Tony Mak9920dbb2019-01-23 19:49:30 +0000119 mMainThreadHandler.post(() -> TextClassifierService.this.onSuggestSelection(
120 sessionId, request, mCancellationSignal, new ProxyCallback<>(callback)));
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800121
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800122 }
123
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800124 @Override
125 public void onClassifyText(
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100126 TextClassificationSessionId sessionId,
Tony Mak9920dbb2019-01-23 19:49:30 +0000127 TextClassification.Request request, ITextClassifierCallback callback) {
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100128 Preconditions.checkNotNull(request);
129 Preconditions.checkNotNull(callback);
Tony Mak9920dbb2019-01-23 19:49:30 +0000130 mMainThreadHandler.post(() -> TextClassifierService.this.onClassifyText(
131 sessionId, request, mCancellationSignal, new ProxyCallback<>(callback)));
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800132 }
133
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800134 @Override
135 public void onGenerateLinks(
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100136 TextClassificationSessionId sessionId,
Tony Mak9920dbb2019-01-23 19:49:30 +0000137 TextLinks.Request request, ITextClassifierCallback callback) {
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100138 Preconditions.checkNotNull(request);
139 Preconditions.checkNotNull(callback);
Tony Mak9920dbb2019-01-23 19:49:30 +0000140 mMainThreadHandler.post(() -> TextClassifierService.this.onGenerateLinks(
141 sessionId, request, mCancellationSignal, new ProxyCallback<>(callback)));
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800142 }
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000143
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000144 @Override
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100145 public void onSelectionEvent(
146 TextClassificationSessionId sessionId,
Tony Mak0be540b2018-11-09 16:58:35 +0000147 SelectionEvent event) {
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100148 Preconditions.checkNotNull(event);
Tony Mak9920dbb2019-01-23 19:49:30 +0000149 mMainThreadHandler.post(
150 () -> TextClassifierService.this.onSelectionEvent(sessionId, event));
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100151 }
152
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100153 @Override
Abodunrinwa Toki37ccedc2018-12-11 00:35:11 +0000154 public void onTextClassifierEvent(
155 TextClassificationSessionId sessionId,
156 TextClassifierEvent event) {
157 Preconditions.checkNotNull(event);
Tony Mak9920dbb2019-01-23 19:49:30 +0000158 mMainThreadHandler.post(
159 () -> TextClassifierService.this.onTextClassifierEvent(sessionId, event));
Abodunrinwa Toki37ccedc2018-12-11 00:35:11 +0000160 }
161
Abodunrinwa Toki37ccedc2018-12-11 00:35:11 +0000162 @Override
Tony Mak0be540b2018-11-09 16:58:35 +0000163 public void onDetectLanguage(
164 TextClassificationSessionId sessionId,
165 TextLanguage.Request request,
Tony Mak9920dbb2019-01-23 19:49:30 +0000166 ITextClassifierCallback callback) {
Tony Mak0be540b2018-11-09 16:58:35 +0000167 Preconditions.checkNotNull(request);
168 Preconditions.checkNotNull(callback);
Tony Mak9920dbb2019-01-23 19:49:30 +0000169 mMainThreadHandler.post(() -> TextClassifierService.this.onDetectLanguage(
170 sessionId, request, mCancellationSignal, new ProxyCallback<>(callback)));
Tony Mak0be540b2018-11-09 16:58:35 +0000171 }
172
Tony Mak0be540b2018-11-09 16:58:35 +0000173 @Override
174 public void onSuggestConversationActions(
175 TextClassificationSessionId sessionId,
176 ConversationActions.Request request,
Tony Mak9920dbb2019-01-23 19:49:30 +0000177 ITextClassifierCallback callback) {
Tony Mak0be540b2018-11-09 16:58:35 +0000178 Preconditions.checkNotNull(request);
179 Preconditions.checkNotNull(callback);
Tony Mak9920dbb2019-01-23 19:49:30 +0000180 mMainThreadHandler.post(() -> TextClassifierService.this.onSuggestConversationActions(
181 sessionId, request, mCancellationSignal, new ProxyCallback<>(callback)));
Tony Mak0be540b2018-11-09 16:58:35 +0000182 }
183
Tony Mak0be540b2018-11-09 16:58:35 +0000184 @Override
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100185 public void onCreateTextClassificationSession(
Tony Mak0be540b2018-11-09 16:58:35 +0000186 TextClassificationContext context, TextClassificationSessionId sessionId) {
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100187 Preconditions.checkNotNull(context);
188 Preconditions.checkNotNull(sessionId);
Tony Mak9920dbb2019-01-23 19:49:30 +0000189 mMainThreadHandler.post(
190 () -> TextClassifierService.this.onCreateTextClassificationSession(
191 context, sessionId));
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100192 }
193
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100194 @Override
Tony Mak0be540b2018-11-09 16:58:35 +0000195 public void onDestroyTextClassificationSession(TextClassificationSessionId sessionId) {
Tony Mak9920dbb2019-01-23 19:49:30 +0000196 mMainThreadHandler.post(
197 () -> TextClassifierService.this.onDestroyTextClassificationSession(sessionId));
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000198 }
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800199 };
200
201 @Nullable
202 @Override
203 public final IBinder onBind(Intent intent) {
204 if (SERVICE_INTERFACE.equals(intent.getAction())) {
205 return mBinder;
206 }
207 return null;
208 }
209
210 /**
211 * Returns suggested text selection start and end indices, recognized entity types, and their
212 * associated confidence scores. The entity types are ordered from highest to lowest scoring.
213 *
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100214 * @param sessionId the session id
215 * @param request the text selection request
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800216 * @param cancellationSignal object to watch for canceling the current operation
217 * @param callback the callback to return the result to
218 */
Tony Mak9920dbb2019-01-23 19:49:30 +0000219 @MainThread
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800220 public abstract void onSuggestSelection(
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100221 @Nullable TextClassificationSessionId sessionId,
222 @NonNull TextSelection.Request request,
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800223 @NonNull CancellationSignal cancellationSignal,
224 @NonNull Callback<TextSelection> callback);
225
226 /**
227 * Classifies the specified text and returns a {@link TextClassification} object that can be
228 * used to generate a widget for handling the classified text.
229 *
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100230 * @param sessionId the session id
231 * @param request the text classification request
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800232 * @param cancellationSignal object to watch for canceling the current operation
233 * @param callback the callback to return the result to
234 */
Tony Mak9920dbb2019-01-23 19:49:30 +0000235 @MainThread
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800236 public abstract void onClassifyText(
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100237 @Nullable TextClassificationSessionId sessionId,
238 @NonNull TextClassification.Request request,
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800239 @NonNull CancellationSignal cancellationSignal,
240 @NonNull Callback<TextClassification> callback);
241
242 /**
243 * Generates and returns a {@link TextLinks} that may be applied to the text to annotate it with
244 * links information.
245 *
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100246 * @param sessionId the session id
247 * @param request the text classification request
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800248 * @param cancellationSignal object to watch for canceling the current operation
249 * @param callback the callback to return the result to
250 */
Tony Mak9920dbb2019-01-23 19:49:30 +0000251 @MainThread
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800252 public abstract void onGenerateLinks(
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100253 @Nullable TextClassificationSessionId sessionId,
254 @NonNull TextLinks.Request request,
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800255 @NonNull CancellationSignal cancellationSignal,
256 @NonNull Callback<TextLinks> callback);
257
258 /**
Tony Mak0be540b2018-11-09 16:58:35 +0000259 * Detects and returns the language of the give text.
260 *
261 * @param sessionId the session id
262 * @param request the language detection request
263 * @param cancellationSignal object to watch for canceling the current operation
264 * @param callback the callback to return the result to
265 */
Tony Mak9920dbb2019-01-23 19:49:30 +0000266 @MainThread
Tony Mak0be540b2018-11-09 16:58:35 +0000267 public void onDetectLanguage(
268 @Nullable TextClassificationSessionId sessionId,
269 @NonNull TextLanguage.Request request,
270 @NonNull CancellationSignal cancellationSignal,
271 @NonNull Callback<TextLanguage> callback) {
Tony Mak9920dbb2019-01-23 19:49:30 +0000272 mSingleThreadExecutor.submit(() ->
273 callback.onSuccess(getLocalTextClassifier().detectLanguage(request)));
Tony Mak0be540b2018-11-09 16:58:35 +0000274 }
275
276 /**
277 * Suggests and returns a list of actions according to the given conversation.
278 *
279 * @param sessionId the session id
280 * @param request the conversation actions request
281 * @param cancellationSignal object to watch for canceling the current operation
282 * @param callback the callback to return the result to
283 */
Tony Mak9920dbb2019-01-23 19:49:30 +0000284 @MainThread
Tony Mak0be540b2018-11-09 16:58:35 +0000285 public void onSuggestConversationActions(
286 @Nullable TextClassificationSessionId sessionId,
287 @NonNull ConversationActions.Request request,
288 @NonNull CancellationSignal cancellationSignal,
289 @NonNull Callback<ConversationActions> callback) {
Tony Mak9920dbb2019-01-23 19:49:30 +0000290 mSingleThreadExecutor.submit(() ->
291 callback.onSuccess(getLocalTextClassifier().suggestConversationActions(request)));
Tony Mak0be540b2018-11-09 16:58:35 +0000292 }
293
294 /**
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000295 * Writes the selection event.
296 * This is called when a selection event occurs. e.g. user changed selection; or smart selection
297 * happened.
298 *
299 * <p>The default implementation ignores the event.
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100300 *
301 * @param sessionId the session id
302 * @param event the selection event
Abodunrinwa Toki37ccedc2018-12-11 00:35:11 +0000303 * @deprecated
304 * Use {@link #onTextClassifierEvent(TextClassificationSessionId, TextClassifierEvent)}
305 * instead
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000306 */
Abodunrinwa Toki37ccedc2018-12-11 00:35:11 +0000307 @Deprecated
Tony Mak9920dbb2019-01-23 19:49:30 +0000308 @MainThread
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100309 public void onSelectionEvent(
310 @Nullable TextClassificationSessionId sessionId, @NonNull SelectionEvent event) {}
311
312 /**
Abodunrinwa Toki37ccedc2018-12-11 00:35:11 +0000313 * Writes the TextClassifier event.
314 * This is called when a TextClassifier event occurs. e.g. user changed selection,
315 * smart selection happened, or a link was clicked.
316 *
317 * <p>The default implementation ignores the event.
318 *
319 * @param sessionId the session id
320 * @param event the TextClassifier event
321 */
Tony Mak9920dbb2019-01-23 19:49:30 +0000322 @MainThread
Abodunrinwa Toki37ccedc2018-12-11 00:35:11 +0000323 public void onTextClassifierEvent(
324 @Nullable TextClassificationSessionId sessionId, @NonNull TextClassifierEvent event) {}
325
326 /**
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100327 * Creates a new text classification session for the specified context.
328 *
329 * @param context the text classification context
330 * @param sessionId the session's Id
331 */
Tony Mak9920dbb2019-01-23 19:49:30 +0000332 @MainThread
Jan Althaus39ccc7e2018-04-04 13:56:40 +0200333 public void onCreateTextClassificationSession(
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100334 @NonNull TextClassificationContext context,
Jan Althaus39ccc7e2018-04-04 13:56:40 +0200335 @NonNull TextClassificationSessionId sessionId) {}
Abodunrinwa Toki080c8542018-03-27 00:04:06 +0100336
337 /**
338 * Destroys the text classification session identified by the specified sessionId.
339 *
340 * @param sessionId the id of the session to destroy
341 */
Tony Mak9920dbb2019-01-23 19:49:30 +0000342 @MainThread
Jan Althaus39ccc7e2018-04-04 13:56:40 +0200343 public void onDestroyTextClassificationSession(
344 @NonNull TextClassificationSessionId sessionId) {}
Abodunrinwa Tokiad52f4b2018-02-06 23:32:41 +0000345
346 /**
Abodunrinwa Tokie6d974a2018-03-06 18:18:30 +0000347 * Returns a TextClassifier that runs in this service's process.
348 * If the local TextClassifier is disabled, this returns {@link TextClassifier#NO_OP}.
Abodunrinwa Toki324572e2019-02-12 19:01:01 +0000349 *
350 * @deprecated Use {@link #getDefaultTextClassifierImplementation(Context)} instead.
Abodunrinwa Tokie6d974a2018-03-06 18:18:30 +0000351 */
Abodunrinwa Toki324572e2019-02-12 19:01:01 +0000352 @Deprecated
Abodunrinwa Tokie6d974a2018-03-06 18:18:30 +0000353 public final TextClassifier getLocalTextClassifier() {
Abodunrinwa Toki324572e2019-02-12 19:01:01 +0000354 // Deprecated: In the future, we may not guarantee that this runs in the service's process.
355 return getDefaultTextClassifierImplementation(this);
356 }
357
358 /**
359 * Returns the platform's default TextClassifier implementation.
360 */
Abodunrinwa Toki9aed55e2019-04-10 20:30:31 +0100361 @NonNull
Abodunrinwa Toki324572e2019-02-12 19:01:01 +0000362 public static TextClassifier getDefaultTextClassifierImplementation(@NonNull Context context) {
363 final TextClassificationManager tcm =
364 context.getSystemService(TextClassificationManager.class);
Abodunrinwa Tokie6d974a2018-03-06 18:18:30 +0000365 if (tcm != null) {
366 return tcm.getTextClassifier(TextClassifier.LOCAL);
367 }
368 return TextClassifier.NO_OP;
369 }
370
Tony Mak9920dbb2019-01-23 19:49:30 +0000371 /** @hide **/
372 public static <T extends Parcelable> T getResponse(Bundle bundle) {
373 return bundle.getParcelable(KEY_RESULT);
374 }
375
Abodunrinwa Tokie6d974a2018-03-06 18:18:30 +0000376 /**
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800377 * Callbacks for TextClassifierService results.
378 *
379 * @param <T> the type of the result
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800380 */
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800381 public interface Callback<T> {
382 /**
383 * Returns the result.
384 */
385 void onSuccess(T result);
386
387 /**
388 * Signals a failure.
389 */
390 void onFailure(CharSequence error);
391 }
392
393 /**
394 * Returns the component name of the system default textclassifier service if it can be found
395 * on the system. Otherwise, returns null.
396 * @hide
397 */
398 @Nullable
399 public static ComponentName getServiceComponentName(Context context) {
Makoto Onuki700feef2018-02-15 10:59:41 -0800400 final String packageName = context.getPackageManager().getSystemTextClassifierPackageName();
401 if (TextUtils.isEmpty(packageName)) {
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800402 Slog.d(LOG_TAG, "No configured system TextClassifierService");
Makoto Onuki700feef2018-02-15 10:59:41 -0800403 return null;
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800404 }
Makoto Onuki700feef2018-02-15 10:59:41 -0800405
406 final Intent intent = new Intent(SERVICE_INTERFACE).setPackage(packageName);
407
408 final ResolveInfo ri = context.getPackageManager().resolveService(intent,
409 PackageManager.MATCH_SYSTEM_ONLY);
410
411 if ((ri == null) || (ri.serviceInfo == null)) {
Felipe Lemef8192132018-10-12 13:42:40 -0700412 Slog.w(LOG_TAG, String.format("Package or service not found in package %s for user %d",
413 packageName, context.getUserId()));
Makoto Onuki700feef2018-02-15 10:59:41 -0800414 return null;
415 }
416 final ServiceInfo si = ri.serviceInfo;
417
418 final String permission = si.permission;
419 if (Manifest.permission.BIND_TEXTCLASSIFIER_SERVICE.equals(permission)) {
420 return si.getComponentName();
421 }
422 Slog.w(LOG_TAG, String.format(
423 "Service %s should require %s permission. Found %s permission",
424 si.getComponentName(),
425 Manifest.permission.BIND_TEXTCLASSIFIER_SERVICE,
426 si.permission));
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800427 return null;
428 }
Tony Mak9920dbb2019-01-23 19:49:30 +0000429
430 /**
431 * Forwards the callback result to a wrapped binder callback.
432 */
433 private static final class ProxyCallback<T extends Parcelable> implements Callback<T> {
434 private WeakReference<ITextClassifierCallback> mTextClassifierCallback;
435
436 private ProxyCallback(ITextClassifierCallback textClassifierCallback) {
437 mTextClassifierCallback =
438 new WeakReference<>(Preconditions.checkNotNull(textClassifierCallback));
439 }
440
441 @Override
442 public void onSuccess(T result) {
443 ITextClassifierCallback callback = mTextClassifierCallback.get();
444 if (callback == null) {
445 return;
446 }
447 try {
448 Bundle bundle = new Bundle(1);
449 bundle.putParcelable(KEY_RESULT, result);
450 callback.onSuccess(bundle);
451 } catch (RemoteException e) {
452 Slog.d(LOG_TAG, "Error calling callback");
453 }
454 }
455
456 @Override
457 public void onFailure(CharSequence error) {
458 ITextClassifierCallback callback = mTextClassifierCallback.get();
459 if (callback == null) {
460 return;
461 }
462 try {
463 callback.onFailure();
464 } catch (RemoteException e) {
465 Slog.d(LOG_TAG, "Error calling callback");
466 }
467 }
468 }
Abodunrinwa Tokid32906c2018-01-18 04:34:44 -0800469}