blob: 818ebd998f50676420a4c5fbe7e13ca47aebea20 [file] [log] [blame]
Sailesh Nepal1bef3392016-01-24 18:21:53 -08001/*
2 * Copyright (C) 2016 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.telecom;
18
Tyler Gunnc30ce782019-01-16 10:42:14 -080019import android.annotation.IntDef;
Tyler Gunnd081f042018-12-04 12:56:45 -080020import android.annotation.NonNull;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080021import android.annotation.SdkConstant;
22import android.app.Service;
tonyzhu9e1d4f82018-10-22 15:11:31 +080023import android.content.ComponentName;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080024import android.content.Intent;
Tyler Gunn94f8f112018-12-17 09:56:11 -080025import android.net.Uri;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080026import android.os.Handler;
27import android.os.IBinder;
28import android.os.Looper;
29import android.os.Message;
30import android.os.RemoteException;
31
32import com.android.internal.os.SomeArgs;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080033import com.android.internal.telecom.ICallScreeningAdapter;
Tyler Gunn3cd820f2018-11-30 14:21:18 -080034import com.android.internal.telecom.ICallScreeningService;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080035
Tyler Gunnc30ce782019-01-16 10:42:14 -080036import java.lang.annotation.Retention;
37import java.lang.annotation.RetentionPolicy;
38
Sailesh Nepal1bef3392016-01-24 18:21:53 -080039/**
40 * This service can be implemented by the default dialer (see
Tyler Gunn94f8f112018-12-17 09:56:11 -080041 * {@link TelecomManager#getDefaultDialerPackage()}) or a third party app to allow or disallow
42 * incoming calls before they are shown to a user. This service can also provide
43 * {@link CallIdentification} information for calls.
Sailesh Nepal1bef3392016-01-24 18:21:53 -080044 * <p>
45 * Below is an example manifest registration for a {@code CallScreeningService}.
46 * <pre>
47 * {@code
48 * <service android:name="your.package.YourCallScreeningServiceImplementation"
49 * android:permission="android.permission.BIND_SCREENING_SERVICE">
50 * <intent-filter>
51 * <action android:name="android.telecom.CallScreeningService"/>
52 * </intent-filter>
53 * </service>
54 * }
55 * </pre>
Tyler Gunnd081f042018-12-04 12:56:45 -080056 * <p>
57 * A CallScreeningService performs two functions:
58 * <ol>
59 * <li>Call blocking/screening - the service can choose which calls will ring on the user's
60 * device, and which will be silently sent to voicemail.</li>
61 * <li>Call identification - the service can optionally provide {@link CallIdentification}
62 * information about a {@link Call.Details call} which will be shown to the user in the
63 * Dialer app.</li>
64 * </ol>
Tyler Gunn94f8f112018-12-17 09:56:11 -080065 * <p>
66 * <h2>Becoming the {@link CallScreeningService}</h2>
67 * Telecom will bind to a single app chosen by the user which implements the
68 * {@link CallScreeningService} API when there are new incoming and outgoing calls.
69 * <p>
70 * The code snippet below illustrates how your app can request that it fills the call screening
71 * role.
72 * <pre>
73 * {@code
74 * private static final int REQUEST_ID = 1;
75 *
76 * public void requestRole() {
77 * RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
78 * Intent intent = roleManager.createRequestRoleIntent("android.app.role.CALL_SCREENING_APP");
79 * startActivityForResult(intent, REQUEST_ID);
80 * }
81 *
82 * &#64;Override
83 * public void onActivityResult(int requestCode, int resultCode, Intent data) {
84 * if (requestCode == REQUEST_ID) {
85 * if (resultCode == android.app.Activity.RESULT_OK) {
86 * // Your app is now the call screening app
87 * } else {
88 * // Your app is not the call screening app
89 * }
90 * }
91 * }
92 * </pre>
Sailesh Nepal1bef3392016-01-24 18:21:53 -080093 */
94public abstract class CallScreeningService extends Service {
Tyler Gunnc30ce782019-01-16 10:42:14 -080095
96 /** @hide */
97 @Retention(RetentionPolicy.SOURCE)
98 @IntDef(
99 prefix = { "CALL_DURATION_" },
100 value = {CALL_DURATION_VERY_SHORT, CALL_DURATION_SHORT, CALL_DURATION_MEDIUM,
101 CALL_DURATION_LONG})
102 public @interface CallDuration {}
103
104 /**
105 * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
106 * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
107 * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}). The
108 * {@link CallScreeningService} can use this as a signal for training nuisance detection
109 * algorithms. The call duration is reported in coarse grained buckets to minimize exposure of
110 * identifying call log information to the {@link CallScreeningService}.
111 * <p>
112 * Indicates the call was < 3 seconds in duration.
113 */
114 public static final int CALL_DURATION_VERY_SHORT = 1;
115
116 /**
117 * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
118 * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
119 * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}). The
120 * {@link CallScreeningService} can use this as a signal for training nuisance detection
121 * algorithms. The call duration is reported in coarse grained buckets to minimize exposure of
122 * identifying call log information to the {@link CallScreeningService}.
123 * <p>
124 * Indicates the call was greater than 3 seconds, but less than 60 seconds in duration.
125 */
126 public static final int CALL_DURATION_SHORT = 2;
127
128 /**
129 * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
130 * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
131 * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}). The
132 * {@link CallScreeningService} can use this as a signal for training nuisance detection
133 * algorithms. The call duration is reported in coarse grained buckets to minimize exposure of
134 * identifying call log information to the {@link CallScreeningService}.
135 * <p>
136 * Indicates the call was greater than 60 seconds, but less than 120 seconds in duration.
137 */
138 public static final int CALL_DURATION_MEDIUM = 3;
139
140 /**
141 * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
142 * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
143 * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}). The
144 * {@link CallScreeningService} can use this as a signal for training nuisance detection
145 * algorithms. The call duration is reported in coarse grained buckets to minimize exposure of
146 * identifying call log information to the {@link CallScreeningService}.
147 * <p>
148 * Indicates the call was greater than 120 seconds.
149 */
150 public static final int CALL_DURATION_LONG = 4;
151
152 /**
153 * Telecom sends this intent to the {@link CallScreeningService} which the user has chosen to
154 * fill the call screening role when the user indicates through the default dialer whether a
155 * call is a nuisance call or not (see
156 * {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}).
157 * <p>
158 * The following extra values are provided for the call:
159 * <ol>
160 * <li>{@link #EXTRA_CALL_HANDLE} - the handle of the call.</li>
161 * <li>{@link #EXTRA_IS_NUISANCE} - {@code true} if the user reported the call as a nuisance
162 * call, {@code false} otherwise.</li>
163 * <li>{@link #EXTRA_CALL_TYPE} - reports the type of call (incoming, rejected, missed,
164 * blocked).</li>
165 * <li>{@link #EXTRA_CALL_DURATION} - the duration of the call (see
166 * {@link #EXTRA_CALL_DURATION} for valid values).</li>
167 * </ol>
168 * <p>
169 * {@link CallScreeningService} implementations which want to track whether the user reports
170 * calls are nuisance calls should use declare a broadcast receiver in their manifest for this
171 * intent.
172 * <p>
173 * Note: Only {@link CallScreeningService} implementations which have provided
174 * {@link CallIdentification} information for calls at some point will receive this intent.
175 */
176 public static final String ACTION_NUISANCE_CALL_STATUS_CHANGED =
177 "android.telecom.action.NUISANCE_CALL_STATUS_CHANGED";
178
179 /**
180 * Extra used to provide the handle of the call for
181 * {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED}. The call handle is reported as a
182 * {@link Uri}.
183 */
184 public static final String EXTRA_CALL_HANDLE = "android.telecom.extra.CALL_HANDLE";
185
186 /**
187 * Boolean extra used to indicate whether the user reported a call as a nuisance call.
188 * When {@code true}, the user reported that a call was a nuisance call, {@code false}
189 * otherwise. Sent with {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED}.
190 */
191 public static final String EXTRA_IS_NUISANCE = "android.telecom.extra.IS_NUISANCE";
192
193 /**
194 * Integer extra used with {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED} to report the type of
195 * call. Valid values are:
196 * <UL>
197 * <li>{@link android.provider.CallLog.Calls#MISSED_TYPE}</li>
198 * <li>{@link android.provider.CallLog.Calls#INCOMING_TYPE}</li>
199 * <li>{@link android.provider.CallLog.Calls#BLOCKED_TYPE}</li>
200 * <li>{@link android.provider.CallLog.Calls#REJECTED_TYPE}</li>
201 * </UL>
202 */
203 public static final String EXTRA_CALL_TYPE = "android.telecom.extra.CALL_TYPE";
204
205 /**
206 * Integer extra used to with {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED} to report how long
207 * the call lasted. Valid values are:
208 * <UL>
209 * <LI>{@link #CALL_DURATION_VERY_SHORT}</LI>
210 * <LI>{@link #CALL_DURATION_SHORT}</LI>
211 * <LI>{@link #CALL_DURATION_MEDIUM}</LI>
212 * <LI>{@link #CALL_DURATION_LONG}</LI>
213 * </UL>
214 */
215 public static final String EXTRA_CALL_DURATION = "android.telecom.extra.CALL_DURATION";
216
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800217 /**
218 * The {@link Intent} that must be declared as handled by the service.
219 */
220 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
221 public static final String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
222
223 private static final int MSG_SCREEN_CALL = 1;
224
225 private final Handler mHandler = new Handler(Looper.getMainLooper()) {
226 @Override
227 public void handleMessage(Message msg) {
228 switch (msg.what) {
229 case MSG_SCREEN_CALL:
230 SomeArgs args = (SomeArgs) msg.obj;
231 try {
232 mCallScreeningAdapter = (ICallScreeningAdapter) args.arg1;
233 onScreenCall(
234 Call.Details.createFromParcelableCall((ParcelableCall) args.arg2));
235 } finally {
236 args.recycle();
237 }
238 break;
239 }
240 }
241 };
242
243 private final class CallScreeningBinder extends ICallScreeningService.Stub {
244 @Override
245 public void screenCall(ICallScreeningAdapter adapter, ParcelableCall call) {
246 Log.v(this, "screenCall");
247 SomeArgs args = SomeArgs.obtain();
248 args.arg1 = adapter;
249 args.arg2 = call;
250 mHandler.obtainMessage(MSG_SCREEN_CALL, args).sendToTarget();
251 }
252 }
253
254 private ICallScreeningAdapter mCallScreeningAdapter;
255
256 /*
257 * Information about how to respond to an incoming call.
258 */
Sailesh Nepalf4460712016-01-27 16:45:51 -0800259 public static class CallResponse {
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800260 private final boolean mShouldDisallowCall;
261 private final boolean mShouldRejectCall;
262 private final boolean mShouldSkipCallLog;
263 private final boolean mShouldSkipNotification;
264
265 private CallResponse(
266 boolean shouldDisallowCall,
267 boolean shouldRejectCall,
268 boolean shouldSkipCallLog,
269 boolean shouldSkipNotification) {
270 if (!shouldDisallowCall
271 && (shouldRejectCall || shouldSkipCallLog || shouldSkipNotification)) {
272 throw new IllegalStateException("Invalid response state for allowed call.");
273 }
274
275 mShouldDisallowCall = shouldDisallowCall;
276 mShouldRejectCall = shouldRejectCall;
277 mShouldSkipCallLog = shouldSkipCallLog;
278 mShouldSkipNotification = shouldSkipNotification;
279 }
280
281 /*
282 * @return Whether the incoming call should be blocked.
283 */
284 public boolean getDisallowCall() {
285 return mShouldDisallowCall;
286 }
287
288 /*
289 * @return Whether the incoming call should be disconnected as if the user had manually
290 * rejected it.
291 */
292 public boolean getRejectCall() {
293 return mShouldRejectCall;
294 }
295
296 /*
297 * @return Whether the incoming call should not be displayed in the call log.
298 */
299 public boolean getSkipCallLog() {
300 return mShouldSkipCallLog;
301 }
302
303 /*
304 * @return Whether a missed call notification should not be shown for the incoming call.
305 */
306 public boolean getSkipNotification() {
307 return mShouldSkipNotification;
308 }
309
Sailesh Nepalf4460712016-01-27 16:45:51 -0800310 public static class Builder {
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800311 private boolean mShouldDisallowCall;
312 private boolean mShouldRejectCall;
313 private boolean mShouldSkipCallLog;
314 private boolean mShouldSkipNotification;
315
Tyler Gunn3cd820f2018-11-30 14:21:18 -0800316 /**
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800317 * Sets whether the incoming call should be blocked.
318 */
319 public Builder setDisallowCall(boolean shouldDisallowCall) {
320 mShouldDisallowCall = shouldDisallowCall;
321 return this;
322 }
323
Tyler Gunn3cd820f2018-11-30 14:21:18 -0800324 /**
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800325 * Sets whether the incoming call should be disconnected as if the user had manually
326 * rejected it. This property should only be set to true if the call is disallowed.
327 */
328 public Builder setRejectCall(boolean shouldRejectCall) {
329 mShouldRejectCall = shouldRejectCall;
330 return this;
331 }
332
Tyler Gunn3cd820f2018-11-30 14:21:18 -0800333 /**
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800334 * Sets whether the incoming call should not be displayed in the call log. This property
335 * should only be set to true if the call is disallowed.
Tyler Gunn3cd820f2018-11-30 14:21:18 -0800336 * <p>
337 * Note: Calls will still be logged with type
338 * {@link android.provider.CallLog.Calls#BLOCKED_TYPE}, regardless of how this property
339 * is set.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800340 */
341 public Builder setSkipCallLog(boolean shouldSkipCallLog) {
342 mShouldSkipCallLog = shouldSkipCallLog;
343 return this;
344 }
345
Tyler Gunn3cd820f2018-11-30 14:21:18 -0800346 /**
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800347 * Sets whether a missed call notification should not be shown for the incoming call.
348 * This property should only be set to true if the call is disallowed.
349 */
350 public Builder setSkipNotification(boolean shouldSkipNotification) {
351 mShouldSkipNotification = shouldSkipNotification;
352 return this;
353 }
354
355 public CallResponse build() {
356 return new CallResponse(
357 mShouldDisallowCall,
358 mShouldRejectCall,
359 mShouldSkipCallLog,
360 mShouldSkipNotification);
361 }
362 }
363 }
364
365 public CallScreeningService() {
366 }
367
368 @Override
369 public IBinder onBind(Intent intent) {
370 Log.v(this, "onBind");
371 return new CallScreeningBinder();
372 }
373
374 @Override
375 public boolean onUnbind(Intent intent) {
376 Log.v(this, "onUnbind");
377 return false;
378 }
379
380 /**
Tyler Gunn94f8f112018-12-17 09:56:11 -0800381 * Called when a new incoming or outgoing call is added which is not in the user's contact list.
382 * <p>
383 * A {@link CallScreeningService} must indicate whether an incoming call is allowed or not by
384 * calling
385 * {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}.
386 * Your app can tell if a call is an incoming call by checking to see if
387 * {@link Call.Details#getCallDirection()} is {@link Call.Details#DIRECTION_INCOMING}.
388 * <p>
389 * For incoming or outgoing calls, the {@link CallScreeningService} can call
390 * {@link #provideCallIdentification(Call.Details, CallIdentification)} in order to provide
391 * {@link CallIdentification} for the call.
Tyler Gunn3cd820f2018-11-30 14:21:18 -0800392 * <p>
393 * Note: The {@link Call.Details} instance provided to a call screening service will only have
394 * the following properties set. The rest of the {@link Call.Details} properties will be set to
395 * their default value or {@code null}.
396 * <ul>
Tyler Gunn94f8f112018-12-17 09:56:11 -0800397 * <li>{@link Call.Details#getCallDirection()}</li>
Tyler Gunn3cd820f2018-11-30 14:21:18 -0800398 * <li>{@link Call.Details#getConnectTimeMillis()}</li>
399 * <li>{@link Call.Details#getCreationTimeMillis()}</li>
400 * <li>{@link Call.Details#getHandle()}</li>
401 * <li>{@link Call.Details#getHandlePresentation()}</li>
402 * </ul>
Tyler Gunn94f8f112018-12-17 09:56:11 -0800403 * <p>
404 * Only calls where the {@link Call.Details#getHandle() handle} {@link Uri#getScheme() scheme}
405 * is {@link PhoneAccount#SCHEME_TEL} are passed for call
406 * screening. Further, only calls which are not in the user's contacts are passed for
407 * screening. For outgoing calls, no post-dial digits are passed.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800408 *
Tyler Gunn94f8f112018-12-17 09:56:11 -0800409 * @param callDetails Information about a new call, see {@link Call.Details}.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800410 */
Tyler Gunnd081f042018-12-04 12:56:45 -0800411 public abstract void onScreenCall(@NonNull Call.Details callDetails);
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800412
413 /**
Tyler Gunn94f8f112018-12-17 09:56:11 -0800414 * Responds to the given incoming call, either allowing it or disallowing it.
Tyler Gunnd081f042018-12-04 12:56:45 -0800415 * <p>
416 * The {@link CallScreeningService} calls this method to inform the system whether the call
417 * should be silently blocked or not.
Tyler Gunn94f8f112018-12-17 09:56:11 -0800418 * <p>
419 * Calls to this method are ignored unless the {@link Call.Details#getCallDirection()} is
420 * {@link Call.Details#DIRECTION_INCOMING}.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800421 *
422 * @param callDetails The call to allow.
Tyler Gunnd081f042018-12-04 12:56:45 -0800423 * <p>
424 * Must be the same {@link Call.Details call} which was provided to the
425 * {@link CallScreeningService} via {@link #onScreenCall(Call.Details)}.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800426 * @param response The {@link CallScreeningService.CallResponse} which contains information
427 * about how to respond to a call.
428 */
Tyler Gunnd081f042018-12-04 12:56:45 -0800429 public final void respondToCall(@NonNull Call.Details callDetails,
430 @NonNull CallResponse response) {
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800431 try {
432 if (response.getDisallowCall()) {
433 mCallScreeningAdapter.disallowCall(
434 callDetails.getTelecomCallId(),
435 response.getRejectCall(),
436 !response.getSkipCallLog(),
tonyzhu9e1d4f82018-10-22 15:11:31 +0800437 !response.getSkipNotification(),
438 new ComponentName(getPackageName(), getClass().getName()));
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800439 } else {
440 mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
441 }
442 } catch (RemoteException e) {
443 }
444 }
Tyler Gunnd081f042018-12-04 12:56:45 -0800445
446 /**
447 * Provide {@link CallIdentification} information about a {@link Call.Details call}.
448 * <p>
449 * The {@link CallScreeningService} calls this method to provide information it has identified
450 * about a {@link Call.Details call}. This information will potentially be shown to the user
451 * in the {@link InCallService dialer} app. It will be logged to the
452 * {@link android.provider.CallLog}.
453 * <p>
454 * A {@link CallScreeningService} should only call this method for calls for which it is able to
455 * provide some {@link CallIdentification} for. {@link CallIdentification} instances with no
456 * fields set will be ignored by the system.
457 *
458 * @param callDetails The call to provide information for.
459 * <p>
460 * Must be the same {@link Call.Details call} which was provided to the
461 * {@link CallScreeningService} via {@link #onScreenCall(Call.Details)}.
462 * @param identification An instance of {@link CallIdentification} with information about the
463 * {@link Call.Details call}.
464 */
465 public final void provideCallIdentification(@NonNull Call.Details callDetails,
466 @NonNull CallIdentification identification) {
467 try {
468 mCallScreeningAdapter.provideCallIdentification(callDetails.getTelecomCallId(),
469 identification);
470 } catch (RemoteException e) {
471 }
472 }
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800473}