blob: d1d16ff8b64135a9d0689b9c329487845bb542d0 [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
Hall Liuff4a1252020-01-01 16:27:14 -080019import android.Manifest;
Hall Liud4c62b92021-02-05 18:33:05 -080020import android.annotation.IntDef;
Tyler Gunn7e45b722018-12-04 12:56:45 -080021import android.annotation.NonNull;
Hall Liuff4a1252020-01-01 16:27:14 -080022import android.annotation.RequiresPermission;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080023import android.annotation.SdkConstant;
Hall Liu6dfa2492019-10-01 17:20:39 -070024import android.annotation.SystemApi;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080025import android.app.Service;
tonyzhu9e1d4f82018-10-22 15:11:31 +080026import android.content.ComponentName;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080027import android.content.Intent;
Tyler Gunn460b7d42020-05-15 10:19:32 -070028import android.content.pm.ServiceInfo;
Tyler Gunn9e76fd19b2018-12-17 09:56:11 -080029import android.net.Uri;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080030import android.os.Handler;
31import android.os.IBinder;
32import android.os.Looper;
33import android.os.Message;
Hall Liu5efe9972021-02-04 13:09:45 -080034import android.os.Parcel;
35import android.os.Parcelable;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080036import android.os.RemoteException;
37
38import com.android.internal.os.SomeArgs;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080039import com.android.internal.telecom.ICallScreeningAdapter;
Tyler Gunne0caec72018-11-30 14:21:18 -080040import com.android.internal.telecom.ICallScreeningService;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080041
Hall Liud4c62b92021-02-05 18:33:05 -080042import java.lang.annotation.Retention;
43import java.lang.annotation.RetentionPolicy;
Hall Liu5efe9972021-02-04 13:09:45 -080044import java.util.Objects;
45
Sailesh Nepal1bef3392016-01-24 18:21:53 -080046/**
47 * This service can be implemented by the default dialer (see
Tyler Gunn9e76fd19b2018-12-17 09:56:11 -080048 * {@link TelecomManager#getDefaultDialerPackage()}) or a third party app to allow or disallow
Tyler Gunna842e7622019-03-29 11:32:08 -070049 * incoming calls before they are shown to a user. A {@link CallScreeningService} can also see
50 * outgoing calls for the purpose of providing caller ID services for those calls.
Sailesh Nepal1bef3392016-01-24 18:21:53 -080051 * <p>
52 * Below is an example manifest registration for a {@code CallScreeningService}.
53 * <pre>
54 * {@code
55 * <service android:name="your.package.YourCallScreeningServiceImplementation"
56 * android:permission="android.permission.BIND_SCREENING_SERVICE">
57 * <intent-filter>
58 * <action android:name="android.telecom.CallScreeningService"/>
59 * </intent-filter>
60 * </service>
61 * }
62 * </pre>
Tyler Gunn7e45b722018-12-04 12:56:45 -080063 * <p>
64 * A CallScreeningService performs two functions:
65 * <ol>
66 * <li>Call blocking/screening - the service can choose which calls will ring on the user's
67 * device, and which will be silently sent to voicemail.</li>
Tyler Gunna842e7622019-03-29 11:32:08 -070068 * <li>Call identification - services which provide call identification functionality can
69 * display a user-interface of their choosing which contains identifying information for a call.
70 * </li>
Tyler Gunn7e45b722018-12-04 12:56:45 -080071 * </ol>
Tyler Gunn9e76fd19b2018-12-17 09:56:11 -080072 * <p>
Tyler Gunn467acc42020-10-07 15:42:06 -070073 * <h2>Becoming the CallScreeningService</h2>
Tyler Gunn9e76fd19b2018-12-17 09:56:11 -080074 * Telecom will bind to a single app chosen by the user which implements the
75 * {@link CallScreeningService} API when there are new incoming and outgoing calls.
76 * <p>
77 * The code snippet below illustrates how your app can request that it fills the call screening
78 * role.
79 * <pre>
80 * {@code
81 * private static final int REQUEST_ID = 1;
82 *
83 * public void requestRole() {
84 * RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
Grace Jia2d21e952019-09-20 14:57:00 -070085 * Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_SCREENING);
Tyler Gunn9e76fd19b2018-12-17 09:56:11 -080086 * startActivityForResult(intent, REQUEST_ID);
87 * }
88 *
89 * &#64;Override
90 * public void onActivityResult(int requestCode, int resultCode, Intent data) {
91 * if (requestCode == REQUEST_ID) {
92 * if (resultCode == android.app.Activity.RESULT_OK) {
93 * // Your app is now the call screening app
94 * } else {
95 * // Your app is not the call screening app
96 * }
97 * }
98 * }
Tyler Gunn467acc42020-10-07 15:42:06 -070099 * }
Tyler Gunn9e76fd19b2018-12-17 09:56:11 -0800100 * </pre>
Tyler Gunn467acc42020-10-07 15:42:06 -0700101 *
102 * <h2>CallScreeningService Lifecycle</h2>
103 *
104 * The framework binds to the {@link CallScreeningService} implemented by the user-chosen app
105 * filling the {@link android.app.role.RoleManager#ROLE_CALL_SCREENING} role when incoming calls are
106 * received (prior to ringing) and when outgoing calls are placed. The platform calls the
107 * {@link #onScreenCall(Call.Details)} method to provide your service with details about the call.
108 * <p>
109 * For incoming calls, the {@link CallScreeningService} must call
110 * {@link #respondToCall(Call.Details, CallResponse)} within 5 seconds of being bound to indicate to
111 * the platform whether the call should be blocked or not. Your app must do this even if it is
112 * primarily performing caller ID operations and not screening calls. It is important to perform
113 * screening operations in a timely matter as the user's device will not begin ringing until the
114 * response is received (or the timeout is hit). A {@link CallScreeningService} may choose to
115 * perform local database lookups to help determine if a call should be screened or not; care should
116 * be taken to ensure the timeout is not repeatedly hit, causing delays in the incoming call flow.
117 * <p>
118 * If your app provides a caller ID experience, it should launch an activity to show the caller ID
119 * information from {@link #onScreenCall(Call.Details)}.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800120 */
121public abstract class CallScreeningService extends Service {
122 /**
123 * The {@link Intent} that must be declared as handled by the service.
124 */
125 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
126 public static final String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
127
128 private static final int MSG_SCREEN_CALL = 1;
129
130 private final Handler mHandler = new Handler(Looper.getMainLooper()) {
131 @Override
132 public void handleMessage(Message msg) {
133 switch (msg.what) {
134 case MSG_SCREEN_CALL:
135 SomeArgs args = (SomeArgs) msg.obj;
136 try {
137 mCallScreeningAdapter = (ICallScreeningAdapter) args.arg1;
Grace Jia90b38042019-11-06 14:12:33 -0800138 Call.Details callDetails = Call.Details
139 .createFromParcelableCall((ParcelableCall) args.arg2);
140 onScreenCall(callDetails);
141 if (callDetails.getCallDirection() == Call.Details.DIRECTION_OUTGOING) {
Hall Liu5efe9972021-02-04 13:09:45 -0800142 mCallScreeningAdapter.onScreeningResponse(
143 callDetails.getTelecomCallId(),
144 new ComponentName(getPackageName(), getClass().getName()),
145 null);
Grace Jia90b38042019-11-06 14:12:33 -0800146 }
147 } catch (RemoteException e) {
148 Log.w(this, "Exception when screening call: " + e);
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800149 } finally {
150 args.recycle();
151 }
152 break;
153 }
154 }
155 };
156
157 private final class CallScreeningBinder extends ICallScreeningService.Stub {
158 @Override
159 public void screenCall(ICallScreeningAdapter adapter, ParcelableCall call) {
160 Log.v(this, "screenCall");
161 SomeArgs args = SomeArgs.obtain();
162 args.arg1 = adapter;
163 args.arg2 = call;
164 mHandler.obtainMessage(MSG_SCREEN_CALL, args).sendToTarget();
165 }
166 }
167
168 private ICallScreeningAdapter mCallScreeningAdapter;
169
Hall Liu5efe9972021-02-04 13:09:45 -0800170 /**
171 * Parcelable version of {@link CallResponse} used to do IPC.
172 * @hide
173 */
174 public static class ParcelableCallResponse implements Parcelable {
175 private final boolean mShouldDisallowCall;
176 private final boolean mShouldRejectCall;
177 private final boolean mShouldSilenceCall;
178 private final boolean mShouldSkipCallLog;
179 private final boolean mShouldSkipNotification;
180 private final boolean mShouldScreenCallViaAudioProcessing;
181
Hall Liud4c62b92021-02-05 18:33:05 -0800182 private final int mCallComposerAttachmentsToShow;
183
Hall Liu5efe9972021-02-04 13:09:45 -0800184 private ParcelableCallResponse(
Hall Liud4c62b92021-02-05 18:33:05 -0800185 boolean shouldDisallowCall,
186 boolean shouldRejectCall,
187 boolean shouldSilenceCall,
188 boolean shouldSkipCallLog,
189 boolean shouldSkipNotification,
190 boolean shouldScreenCallViaAudioProcessing,
191 int callComposerAttachmentsToShow) {
Hall Liu5efe9972021-02-04 13:09:45 -0800192 mShouldDisallowCall = shouldDisallowCall;
193 mShouldRejectCall = shouldRejectCall;
194 mShouldSilenceCall = shouldSilenceCall;
195 mShouldSkipCallLog = shouldSkipCallLog;
196 mShouldSkipNotification = shouldSkipNotification;
197 mShouldScreenCallViaAudioProcessing = shouldScreenCallViaAudioProcessing;
Hall Liud4c62b92021-02-05 18:33:05 -0800198 mCallComposerAttachmentsToShow = callComposerAttachmentsToShow;
Hall Liu5efe9972021-02-04 13:09:45 -0800199 }
200
201 protected ParcelableCallResponse(Parcel in) {
202 mShouldDisallowCall = in.readBoolean();
203 mShouldRejectCall = in.readBoolean();
204 mShouldSilenceCall = in.readBoolean();
205 mShouldSkipCallLog = in.readBoolean();
206 mShouldSkipNotification = in.readBoolean();
207 mShouldScreenCallViaAudioProcessing = in.readBoolean();
Hall Liud4c62b92021-02-05 18:33:05 -0800208 mCallComposerAttachmentsToShow = in.readInt();
Hall Liu5efe9972021-02-04 13:09:45 -0800209 }
210
211 public CallResponse toCallResponse() {
212 return new CallResponse.Builder()
213 .setDisallowCall(mShouldDisallowCall)
214 .setRejectCall(mShouldRejectCall)
215 .setSilenceCall(mShouldSilenceCall)
216 .setSkipCallLog(mShouldSkipCallLog)
217 .setSkipNotification(mShouldSkipNotification)
218 .setShouldScreenCallViaAudioProcessing(mShouldScreenCallViaAudioProcessing)
Hall Liud4c62b92021-02-05 18:33:05 -0800219 .setCallComposerAttachmentsToShow(mCallComposerAttachmentsToShow)
Hall Liu5efe9972021-02-04 13:09:45 -0800220 .build();
221 }
222
223 public boolean shouldDisallowCall() {
224 return mShouldDisallowCall;
225 }
226
227 public boolean shouldRejectCall() {
228 return mShouldRejectCall;
229 }
230
231 public boolean shouldSilenceCall() {
232 return mShouldSilenceCall;
233 }
234
235 public boolean shouldSkipCallLog() {
236 return mShouldSkipCallLog;
237 }
238
239 public boolean shouldSkipNotification() {
240 return mShouldSkipNotification;
241 }
242
243 public boolean shouldScreenCallViaAudioProcessing() {
244 return mShouldScreenCallViaAudioProcessing;
245 }
246
Hall Liud4c62b92021-02-05 18:33:05 -0800247 public int getCallComposerAttachmentsToShow() {
248 return mCallComposerAttachmentsToShow;
249 }
250
Hall Liu5efe9972021-02-04 13:09:45 -0800251 public static final Creator<ParcelableCallResponse> CREATOR =
252 new Creator<ParcelableCallResponse>() {
253 @Override
254 public ParcelableCallResponse createFromParcel(Parcel in) {
255 return new ParcelableCallResponse(in);
256 }
257
258 @Override
259 public ParcelableCallResponse[] newArray(int size) {
260 return new ParcelableCallResponse[size];
261 }
262 };
263
264 @Override
265 public int describeContents() {
266 return 0;
267 }
268
269 @Override
270 public void writeToParcel(Parcel dest, int flags) {
271 dest.writeBoolean(mShouldDisallowCall);
272 dest.writeBoolean(mShouldRejectCall);
273 dest.writeBoolean(mShouldSilenceCall);
274 dest.writeBoolean(mShouldSkipCallLog);
275 dest.writeBoolean(mShouldSkipNotification);
276 dest.writeBoolean(mShouldScreenCallViaAudioProcessing);
Hall Liud4c62b92021-02-05 18:33:05 -0800277 dest.writeInt(mCallComposerAttachmentsToShow);
Hall Liu5efe9972021-02-04 13:09:45 -0800278 }
279 }
280
Hall Liud4c62b92021-02-05 18:33:05 -0800281 /**
282 * Information about how to respond to an incoming call. Call screening apps can construct an
283 * instance of this class using {@link CallResponse.Builder}.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800284 */
Sailesh Nepalf4460712016-01-27 16:45:51 -0800285 public static class CallResponse {
Hall Liud4c62b92021-02-05 18:33:05 -0800286 /**
287 * Bit flag indicating whether to show the picture attachment for call composer.
288 *
289 * Used with {@link Builder#setCallComposerAttachmentsToShow(int)}.
290 */
291 public static final int CALL_COMPOSER_ATTACHMENT_PICTURE = 1;
292
293 /**
294 * Bit flag indicating whether to show the location attachment for call composer.
295 *
296 * Used with {@link Builder#setCallComposerAttachmentsToShow(int)}.
297 */
298 public static final int CALL_COMPOSER_ATTACHMENT_LOCATION = 1 << 1;
299
300 /**
301 * Bit flag indicating whether to show the subject attachment for call composer.
302 *
303 * Used with {@link Builder#setCallComposerAttachmentsToShow(int)}.
304 */
305 public static final int CALL_COMPOSER_ATTACHMENT_SUBJECT = 1 << 2;
306
307 /**
308 * Bit flag indicating whether to show the priority attachment for call composer.
309 *
310 * Used with {@link Builder#setCallComposerAttachmentsToShow(int)}.
311 */
312 public static final int CALL_COMPOSER_ATTACHMENT_PRIORITY = 1 << 3;
313
314 /** @hide */
315 @Retention(RetentionPolicy.SOURCE)
316 @IntDef(prefix = "CALL_COMPOSER_ATTACHMENT_", flag = true,
317 value = {
318 CALL_COMPOSER_ATTACHMENT_PICTURE,
319 CALL_COMPOSER_ATTACHMENT_LOCATION,
320 CALL_COMPOSER_ATTACHMENT_SUBJECT,
321 CALL_COMPOSER_ATTACHMENT_PRIORITY
322 }
323 )
324 public @interface CallComposerAttachmentType {}
325
326 private static final int NUM_CALL_COMPOSER_ATTACHMENT_TYPES = 4;
327
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800328 private final boolean mShouldDisallowCall;
329 private final boolean mShouldRejectCall;
Usman Abdullah47b392d2019-03-06 15:54:56 -0800330 private final boolean mShouldSilenceCall;
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800331 private final boolean mShouldSkipCallLog;
332 private final boolean mShouldSkipNotification;
Hall Liu69554cf2019-11-11 17:44:09 -0800333 private final boolean mShouldScreenCallViaAudioProcessing;
Hall Liud4c62b92021-02-05 18:33:05 -0800334 private final int mCallComposerAttachmentsToShow;
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800335
336 private CallResponse(
337 boolean shouldDisallowCall,
338 boolean shouldRejectCall,
Usman Abdullah47b392d2019-03-06 15:54:56 -0800339 boolean shouldSilenceCall,
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800340 boolean shouldSkipCallLog,
Hall Liu6dfa2492019-10-01 17:20:39 -0700341 boolean shouldSkipNotification,
Hall Liud4c62b92021-02-05 18:33:05 -0800342 boolean shouldScreenCallViaAudioProcessing,
343 int callComposerAttachmentsToShow) {
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800344 if (!shouldDisallowCall
345 && (shouldRejectCall || shouldSkipCallLog || shouldSkipNotification)) {
346 throw new IllegalStateException("Invalid response state for allowed call.");
347 }
348
Hall Liu69554cf2019-11-11 17:44:09 -0800349 if (shouldDisallowCall && shouldScreenCallViaAudioProcessing) {
Hall Liu6dfa2492019-10-01 17:20:39 -0700350 throw new IllegalStateException("Invalid response state for allowed call.");
351 }
352
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800353 mShouldDisallowCall = shouldDisallowCall;
354 mShouldRejectCall = shouldRejectCall;
355 mShouldSkipCallLog = shouldSkipCallLog;
356 mShouldSkipNotification = shouldSkipNotification;
Usman Abdullah47b392d2019-03-06 15:54:56 -0800357 mShouldSilenceCall = shouldSilenceCall;
Hall Liu69554cf2019-11-11 17:44:09 -0800358 mShouldScreenCallViaAudioProcessing = shouldScreenCallViaAudioProcessing;
Hall Liud4c62b92021-02-05 18:33:05 -0800359 mCallComposerAttachmentsToShow = callComposerAttachmentsToShow;
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800360 }
361
362 /*
363 * @return Whether the incoming call should be blocked.
364 */
365 public boolean getDisallowCall() {
366 return mShouldDisallowCall;
367 }
368
369 /*
370 * @return Whether the incoming call should be disconnected as if the user had manually
371 * rejected it.
372 */
373 public boolean getRejectCall() {
374 return mShouldRejectCall;
375 }
376
377 /*
Usman Abdullah47b392d2019-03-06 15:54:56 -0800378 * @return Whether the ringtone should be silenced for the incoming call.
379 */
380 public boolean getSilenceCall() {
381 return mShouldSilenceCall;
382 }
383
384 /*
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800385 * @return Whether the incoming call should not be displayed in the call log.
386 */
387 public boolean getSkipCallLog() {
388 return mShouldSkipCallLog;
389 }
390
391 /*
392 * @return Whether a missed call notification should not be shown for the incoming call.
393 */
394 public boolean getSkipNotification() {
395 return mShouldSkipNotification;
396 }
397
Hall Liu6dfa2492019-10-01 17:20:39 -0700398 /**
399 * @return Whether we should enter the {@link Call#STATE_AUDIO_PROCESSING} state to allow
400 * for further screening of the call.
401 * @hide
402 */
Hall Liu69554cf2019-11-11 17:44:09 -0800403 public boolean getShouldScreenCallViaAudioProcessing() {
404 return mShouldScreenCallViaAudioProcessing;
Hall Liu6dfa2492019-10-01 17:20:39 -0700405 }
406
Hall Liud4c62b92021-02-05 18:33:05 -0800407 /**
408 * @return A bitmask of call composer attachments that should be shown to the user.
409 */
410 public @CallComposerAttachmentType int getCallComposerAttachmentsToShow() {
411 return mCallComposerAttachmentsToShow;
412 }
413
Hall Liu5efe9972021-02-04 13:09:45 -0800414 /** @hide */
415 public ParcelableCallResponse toParcelable() {
416 return new ParcelableCallResponse(
417 mShouldDisallowCall,
418 mShouldRejectCall,
419 mShouldSilenceCall,
420 mShouldSkipCallLog,
421 mShouldSkipNotification,
Hall Liud4c62b92021-02-05 18:33:05 -0800422 mShouldScreenCallViaAudioProcessing,
423 mCallComposerAttachmentsToShow
Hall Liu5efe9972021-02-04 13:09:45 -0800424 );
425 }
426
427 @Override
428 public boolean equals(Object o) {
429 if (this == o) return true;
430 if (o == null || getClass() != o.getClass()) return false;
431 CallResponse that = (CallResponse) o;
432 return mShouldDisallowCall == that.mShouldDisallowCall &&
433 mShouldRejectCall == that.mShouldRejectCall &&
434 mShouldSilenceCall == that.mShouldSilenceCall &&
435 mShouldSkipCallLog == that.mShouldSkipCallLog &&
436 mShouldSkipNotification == that.mShouldSkipNotification &&
Hall Liud4c62b92021-02-05 18:33:05 -0800437 mShouldScreenCallViaAudioProcessing
438 == that.mShouldScreenCallViaAudioProcessing &&
439 mCallComposerAttachmentsToShow == that.mCallComposerAttachmentsToShow;
Hall Liu5efe9972021-02-04 13:09:45 -0800440 }
441
442 @Override
443 public int hashCode() {
444 return Objects.hash(mShouldDisallowCall, mShouldRejectCall, mShouldSilenceCall,
445 mShouldSkipCallLog, mShouldSkipNotification,
Hall Liud4c62b92021-02-05 18:33:05 -0800446 mShouldScreenCallViaAudioProcessing,
447 mCallComposerAttachmentsToShow);
Hall Liu5efe9972021-02-04 13:09:45 -0800448 }
449
Sailesh Nepalf4460712016-01-27 16:45:51 -0800450 public static class Builder {
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800451 private boolean mShouldDisallowCall;
452 private boolean mShouldRejectCall;
Usman Abdullah47b392d2019-03-06 15:54:56 -0800453 private boolean mShouldSilenceCall;
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800454 private boolean mShouldSkipCallLog;
455 private boolean mShouldSkipNotification;
Hall Liu69554cf2019-11-11 17:44:09 -0800456 private boolean mShouldScreenCallViaAudioProcessing;
Hall Liud4c62b92021-02-05 18:33:05 -0800457 private int mCallComposerAttachmentsToShow = -1;
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800458
Tyler Gunne0caec72018-11-30 14:21:18 -0800459 /**
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800460 * Sets whether the incoming call should be blocked.
461 */
462 public Builder setDisallowCall(boolean shouldDisallowCall) {
463 mShouldDisallowCall = shouldDisallowCall;
464 return this;
465 }
466
Tyler Gunne0caec72018-11-30 14:21:18 -0800467 /**
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800468 * Sets whether the incoming call should be disconnected as if the user had manually
469 * rejected it. This property should only be set to true if the call is disallowed.
470 */
471 public Builder setRejectCall(boolean shouldRejectCall) {
472 mShouldRejectCall = shouldRejectCall;
473 return this;
474 }
475
Tyler Gunne0caec72018-11-30 14:21:18 -0800476 /**
Usman Abdullah47b392d2019-03-06 15:54:56 -0800477 * Sets whether ringing should be silenced for the incoming call. When set
478 * to {@code true}, the Telecom framework will not play a ringtone for the call.
479 * The call will, however, still be sent to the default dialer app if it is not blocked.
480 * A {@link CallScreeningService} can use this to ensure a potential nuisance call is
481 * still surfaced to the user, but in a less intrusive manner.
482 *
483 * Setting this to true only makes sense when the call has not been disallowed
484 * using {@link #setDisallowCall(boolean)}.
485 */
486 public @NonNull Builder setSilenceCall(boolean shouldSilenceCall) {
487 mShouldSilenceCall = shouldSilenceCall;
488 return this;
489 }
490
491 /**
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800492 * Sets whether the incoming call should not be displayed in the call log. This property
493 * should only be set to true if the call is disallowed.
Tyler Gunne0caec72018-11-30 14:21:18 -0800494 * <p>
495 * Note: Calls will still be logged with type
496 * {@link android.provider.CallLog.Calls#BLOCKED_TYPE}, regardless of how this property
497 * is set.
Thomas Stuarte1928792022-07-13 10:45:19 -0700498 * <p>
499 * Note: Only the carrier and system call screening apps can use this parameter;
500 * this parameter is ignored otherwise.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800501 */
502 public Builder setSkipCallLog(boolean shouldSkipCallLog) {
503 mShouldSkipCallLog = shouldSkipCallLog;
504 return this;
505 }
506
Tyler Gunne0caec72018-11-30 14:21:18 -0800507 /**
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800508 * Sets whether a missed call notification should not be shown for the incoming call.
509 * This property should only be set to true if the call is disallowed.
510 */
511 public Builder setSkipNotification(boolean shouldSkipNotification) {
512 mShouldSkipNotification = shouldSkipNotification;
513 return this;
514 }
515
Hall Liu6dfa2492019-10-01 17:20:39 -0700516 /**
517 * Sets whether to request background audio processing so that the in-call service can
518 * screen the call further. If set to {@code true}, {@link #setDisallowCall} should be
519 * called with {@code false}, and all other parameters in this builder will be ignored.
Tyler Gunn460b7d42020-05-15 10:19:32 -0700520 * <p>
Hall Liu6dfa2492019-10-01 17:20:39 -0700521 * This request will only be honored if the {@link CallScreeningService} shares the same
Tyler Gunna5ee1ca2021-04-30 10:41:54 -0700522 * uid as the system dialer app. Otherwise, the call will go through as usual.
Tyler Gunn460b7d42020-05-15 10:19:32 -0700523 * <p>
524 * Apps built with SDK version {@link android.os.Build.VERSION_CODES#R} or later which
525 * are using the microphone as part of audio processing should specify the
526 * foreground service type using the attribute
527 * {@link android.R.attr#foregroundServiceType} in the {@link CallScreeningService}
528 * service element of the app's manifest file.
529 * The {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MICROPHONE} attribute should be
530 * specified.
531 * @see
532 * <a href="https://developer.android.com/preview/privacy/foreground-service-types">
533 * the Android Developer Site</a> for more information.
Hall Liu6dfa2492019-10-01 17:20:39 -0700534 *
Hall Liu69554cf2019-11-11 17:44:09 -0800535 * @param shouldScreenCallViaAudioProcessing Whether to request further call screening.
Hall Liu6dfa2492019-10-01 17:20:39 -0700536 * @hide
537 */
538 @SystemApi
Hall Liuff4a1252020-01-01 16:27:14 -0800539 @RequiresPermission(Manifest.permission.CAPTURE_AUDIO_OUTPUT)
Hall Liu69554cf2019-11-11 17:44:09 -0800540 public @NonNull Builder setShouldScreenCallViaAudioProcessing(
541 boolean shouldScreenCallViaAudioProcessing) {
542 mShouldScreenCallViaAudioProcessing = shouldScreenCallViaAudioProcessing;
Hall Liu6dfa2492019-10-01 17:20:39 -0700543 return this;
544 }
545
Hall Liud4c62b92021-02-05 18:33:05 -0800546 /**
547 * Sets the call composer attachments that should be shown to the user.
548 *
549 * Attachments that are not shown will not be passed to the in-call UI responsible for
550 * displaying the call to the user.
551 *
552 * If this method is not called on a {@link Builder}, all attachments will be shown,
553 * except pictures, which will only be shown to users if the call is from a contact.
554 *
555 * Setting attachments to show will have no effect if the call screening service does
556 * not belong to the same package as the system dialer (as returned by
557 * {@link TelecomManager#getSystemDialerPackage()}).
558 *
559 * @param callComposerAttachmentsToShow A bitmask of call composer attachments to show.
560 */
561 public @NonNull Builder setCallComposerAttachmentsToShow(
562 @CallComposerAttachmentType int callComposerAttachmentsToShow) {
563 // If the argument is less than zero (meaning unset), no-op since the conversion
564 // to/from the parcelable version may call with that value.
565 if (callComposerAttachmentsToShow < 0) {
566 return this;
567 }
568
569 if ((callComposerAttachmentsToShow
570 & (1 << NUM_CALL_COMPOSER_ATTACHMENT_TYPES)) != 0) {
571 throw new IllegalArgumentException("Attachment types must match the ones"
572 + " defined in CallResponse");
573 }
574 mCallComposerAttachmentsToShow = callComposerAttachmentsToShow;
575 return this;
576 }
577
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800578 public CallResponse build() {
579 return new CallResponse(
580 mShouldDisallowCall,
581 mShouldRejectCall,
Usman Abdullah47b392d2019-03-06 15:54:56 -0800582 mShouldSilenceCall,
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800583 mShouldSkipCallLog,
Hall Liu6dfa2492019-10-01 17:20:39 -0700584 mShouldSkipNotification,
Hall Liud4c62b92021-02-05 18:33:05 -0800585 mShouldScreenCallViaAudioProcessing,
586 mCallComposerAttachmentsToShow);
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800587 }
588 }
589 }
590
591 public CallScreeningService() {
592 }
593
594 @Override
595 public IBinder onBind(Intent intent) {
596 Log.v(this, "onBind");
597 return new CallScreeningBinder();
598 }
599
600 @Override
601 public boolean onUnbind(Intent intent) {
602 Log.v(this, "onUnbind");
603 return false;
604 }
605
606 /**
Tyler Gunn467acc42020-10-07 15:42:06 -0700607 * Called when a new incoming or outgoing call is added.
Tyler Gunn9e76fd19b2018-12-17 09:56:11 -0800608 * <p>
609 * A {@link CallScreeningService} must indicate whether an incoming call is allowed or not by
610 * calling
611 * {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}.
612 * Your app can tell if a call is an incoming call by checking to see if
613 * {@link Call.Details#getCallDirection()} is {@link Call.Details#DIRECTION_INCOMING}.
614 * <p>
Tyler Gunn467acc42020-10-07 15:42:06 -0700615 * <em>Note:</em> A {@link CallScreeningService} must respond to a call within 5 seconds. After
616 * this time, the framework will unbind from the {@link CallScreeningService} and ignore its
617 * response.
618 * <p>
619 * <em>Note:</em> The {@link Call.Details} instance provided to a call screening service will
620 * only have the following properties set. The rest of the {@link Call.Details} properties will
621 * be set to their default value or {@code null}.
Tyler Gunne0caec72018-11-30 14:21:18 -0800622 * <ul>
Tyler Gunn9e76fd19b2018-12-17 09:56:11 -0800623 * <li>{@link Call.Details#getCallDirection()}</li>
Tyler Gunn467acc42020-10-07 15:42:06 -0700624 * <li>{@link Call.Details#getCallerNumberVerificationStatus()}</li>
Tyler Gunne0caec72018-11-30 14:21:18 -0800625 * <li>{@link Call.Details#getConnectTimeMillis()}</li>
626 * <li>{@link Call.Details#getCreationTimeMillis()}</li>
627 * <li>{@link Call.Details#getHandle()}</li>
Tyler Gunne0caec72018-11-30 14:21:18 -0800628 * </ul>
Tyler Gunn9e76fd19b2018-12-17 09:56:11 -0800629 * <p>
630 * Only calls where the {@link Call.Details#getHandle() handle} {@link Uri#getScheme() scheme}
631 * is {@link PhoneAccount#SCHEME_TEL} are passed for call
632 * screening. Further, only calls which are not in the user's contacts are passed for
Tyler Gunn467acc42020-10-07 15:42:06 -0700633 * screening, unless the {@link CallScreeningService} has been granted
634 * {@link Manifest.permission#READ_CONTACTS} permission by the user. For outgoing calls, no
635 * post-dial digits are passed.
636 * <p>
637 * Calls with a {@link Call.Details#getHandlePresentation()} of
Grace Jiacc16b042021-08-09 09:06:11 -0700638 * {@link TelecomManager#PRESENTATION_RESTRICTED}, {@link TelecomManager#PRESENTATION_UNKNOWN},
639 * {@link TelecomManager#PRESENTATION_UNAVAILABLE} or
640 * {@link TelecomManager#PRESENTATION_PAYPHONE} presentation are not provided to the
Tyler Gunn467acc42020-10-07 15:42:06 -0700641 * {@link CallScreeningService}.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800642 *
Tyler Gunn9e76fd19b2018-12-17 09:56:11 -0800643 * @param callDetails Information about a new call, see {@link Call.Details}.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800644 */
Tyler Gunn7e45b722018-12-04 12:56:45 -0800645 public abstract void onScreenCall(@NonNull Call.Details callDetails);
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800646
647 /**
Usman Abdullah47b392d2019-03-06 15:54:56 -0800648 * Responds to the given incoming call, either allowing it, silencing it or disallowing it.
Tyler Gunn7e45b722018-12-04 12:56:45 -0800649 * <p>
650 * The {@link CallScreeningService} calls this method to inform the system whether the call
Usman Abdullah47b392d2019-03-06 15:54:56 -0800651 * should be silently blocked or not. In the event that it should not be blocked, it may
652 * also be requested to ring silently.
Tyler Gunn9e76fd19b2018-12-17 09:56:11 -0800653 * <p>
654 * Calls to this method are ignored unless the {@link Call.Details#getCallDirection()} is
655 * {@link Call.Details#DIRECTION_INCOMING}.
Tyler Gunn467acc42020-10-07 15:42:06 -0700656 * <p>
657 * For incoming calls, a {@link CallScreeningService} MUST call this method within 5 seconds of
658 * {@link #onScreenCall(Call.Details)} being invoked by the platform.
659 * <p>
660 * Calls which are blocked/rejected will be logged to the system call log with a call type of
661 * {@link android.provider.CallLog.Calls#BLOCKED_TYPE} and
662 * {@link android.provider.CallLog.Calls#BLOCK_REASON_CALL_SCREENING_SERVICE} block reason.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800663 *
664 * @param callDetails The call to allow.
Tyler Gunn7e45b722018-12-04 12:56:45 -0800665 * <p>
666 * Must be the same {@link Call.Details call} which was provided to the
667 * {@link CallScreeningService} via {@link #onScreenCall(Call.Details)}.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800668 * @param response The {@link CallScreeningService.CallResponse} which contains information
669 * about how to respond to a call.
670 */
Tyler Gunn7e45b722018-12-04 12:56:45 -0800671 public final void respondToCall(@NonNull Call.Details callDetails,
672 @NonNull CallResponse response) {
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800673 try {
Hall Liu5efe9972021-02-04 13:09:45 -0800674 mCallScreeningAdapter.onScreeningResponse(
675 callDetails.getTelecomCallId(),
676 new ComponentName(getPackageName(), getClass().getName()),
677 response.toParcelable());
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800678 } catch (RemoteException e) {
Hall Liu5efe9972021-02-04 13:09:45 -0800679 Log.e(this, e, "Got remote exception when returning response");
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800680 }
681 }
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800682}