blob: 826ad82dfbb2869e0211fb8c71a834f4519ca42a [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 Gunnd081f042018-12-04 12:56:45 -080019import android.annotation.NonNull;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080020import android.annotation.SdkConstant;
21import android.app.Service;
tonyzhu9e1d4f82018-10-22 15:11:31 +080022import android.content.ComponentName;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080023import android.content.Intent;
Tyler Gunn94f8f112018-12-17 09:56:11 -080024import android.net.Uri;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080025import android.os.Handler;
26import android.os.IBinder;
27import android.os.Looper;
28import android.os.Message;
29import android.os.RemoteException;
30
31import com.android.internal.os.SomeArgs;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080032import com.android.internal.telecom.ICallScreeningAdapter;
Tyler Gunn3cd820f2018-11-30 14:21:18 -080033import com.android.internal.telecom.ICallScreeningService;
Sailesh Nepal1bef3392016-01-24 18:21:53 -080034
35/**
36 * This service can be implemented by the default dialer (see
Tyler Gunn94f8f112018-12-17 09:56:11 -080037 * {@link TelecomManager#getDefaultDialerPackage()}) or a third party app to allow or disallow
38 * incoming calls before they are shown to a user. This service can also provide
39 * {@link CallIdentification} information for calls.
Sailesh Nepal1bef3392016-01-24 18:21:53 -080040 * <p>
41 * Below is an example manifest registration for a {@code CallScreeningService}.
42 * <pre>
43 * {@code
44 * <service android:name="your.package.YourCallScreeningServiceImplementation"
45 * android:permission="android.permission.BIND_SCREENING_SERVICE">
46 * <intent-filter>
47 * <action android:name="android.telecom.CallScreeningService"/>
48 * </intent-filter>
49 * </service>
50 * }
51 * </pre>
Tyler Gunnd081f042018-12-04 12:56:45 -080052 * <p>
53 * A CallScreeningService performs two functions:
54 * <ol>
55 * <li>Call blocking/screening - the service can choose which calls will ring on the user's
56 * device, and which will be silently sent to voicemail.</li>
57 * <li>Call identification - the service can optionally provide {@link CallIdentification}
58 * information about a {@link Call.Details call} which will be shown to the user in the
59 * Dialer app.</li>
60 * </ol>
Tyler Gunn94f8f112018-12-17 09:56:11 -080061 * <p>
62 * <h2>Becoming the {@link CallScreeningService}</h2>
63 * Telecom will bind to a single app chosen by the user which implements the
64 * {@link CallScreeningService} API when there are new incoming and outgoing calls.
65 * <p>
66 * The code snippet below illustrates how your app can request that it fills the call screening
67 * role.
68 * <pre>
69 * {@code
70 * private static final int REQUEST_ID = 1;
71 *
72 * public void requestRole() {
73 * RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
74 * Intent intent = roleManager.createRequestRoleIntent("android.app.role.CALL_SCREENING_APP");
75 * startActivityForResult(intent, REQUEST_ID);
76 * }
77 *
78 * &#64;Override
79 * public void onActivityResult(int requestCode, int resultCode, Intent data) {
80 * if (requestCode == REQUEST_ID) {
81 * if (resultCode == android.app.Activity.RESULT_OK) {
82 * // Your app is now the call screening app
83 * } else {
84 * // Your app is not the call screening app
85 * }
86 * }
87 * }
88 * </pre>
Sailesh Nepal1bef3392016-01-24 18:21:53 -080089 */
90public abstract class CallScreeningService extends Service {
91 /**
92 * The {@link Intent} that must be declared as handled by the service.
93 */
94 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
95 public static final String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
96
97 private static final int MSG_SCREEN_CALL = 1;
98
99 private final Handler mHandler = new Handler(Looper.getMainLooper()) {
100 @Override
101 public void handleMessage(Message msg) {
102 switch (msg.what) {
103 case MSG_SCREEN_CALL:
104 SomeArgs args = (SomeArgs) msg.obj;
105 try {
106 mCallScreeningAdapter = (ICallScreeningAdapter) args.arg1;
107 onScreenCall(
108 Call.Details.createFromParcelableCall((ParcelableCall) args.arg2));
109 } finally {
110 args.recycle();
111 }
112 break;
113 }
114 }
115 };
116
117 private final class CallScreeningBinder extends ICallScreeningService.Stub {
118 @Override
119 public void screenCall(ICallScreeningAdapter adapter, ParcelableCall call) {
120 Log.v(this, "screenCall");
121 SomeArgs args = SomeArgs.obtain();
122 args.arg1 = adapter;
123 args.arg2 = call;
124 mHandler.obtainMessage(MSG_SCREEN_CALL, args).sendToTarget();
125 }
126 }
127
128 private ICallScreeningAdapter mCallScreeningAdapter;
129
130 /*
131 * Information about how to respond to an incoming call.
132 */
Sailesh Nepalf4460712016-01-27 16:45:51 -0800133 public static class CallResponse {
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800134 private final boolean mShouldDisallowCall;
135 private final boolean mShouldRejectCall;
136 private final boolean mShouldSkipCallLog;
137 private final boolean mShouldSkipNotification;
138
139 private CallResponse(
140 boolean shouldDisallowCall,
141 boolean shouldRejectCall,
142 boolean shouldSkipCallLog,
143 boolean shouldSkipNotification) {
144 if (!shouldDisallowCall
145 && (shouldRejectCall || shouldSkipCallLog || shouldSkipNotification)) {
146 throw new IllegalStateException("Invalid response state for allowed call.");
147 }
148
149 mShouldDisallowCall = shouldDisallowCall;
150 mShouldRejectCall = shouldRejectCall;
151 mShouldSkipCallLog = shouldSkipCallLog;
152 mShouldSkipNotification = shouldSkipNotification;
153 }
154
155 /*
156 * @return Whether the incoming call should be blocked.
157 */
158 public boolean getDisallowCall() {
159 return mShouldDisallowCall;
160 }
161
162 /*
163 * @return Whether the incoming call should be disconnected as if the user had manually
164 * rejected it.
165 */
166 public boolean getRejectCall() {
167 return mShouldRejectCall;
168 }
169
170 /*
171 * @return Whether the incoming call should not be displayed in the call log.
172 */
173 public boolean getSkipCallLog() {
174 return mShouldSkipCallLog;
175 }
176
177 /*
178 * @return Whether a missed call notification should not be shown for the incoming call.
179 */
180 public boolean getSkipNotification() {
181 return mShouldSkipNotification;
182 }
183
Sailesh Nepalf4460712016-01-27 16:45:51 -0800184 public static class Builder {
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800185 private boolean mShouldDisallowCall;
186 private boolean mShouldRejectCall;
187 private boolean mShouldSkipCallLog;
188 private boolean mShouldSkipNotification;
189
Tyler Gunn3cd820f2018-11-30 14:21:18 -0800190 /**
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800191 * Sets whether the incoming call should be blocked.
192 */
193 public Builder setDisallowCall(boolean shouldDisallowCall) {
194 mShouldDisallowCall = shouldDisallowCall;
195 return this;
196 }
197
Tyler Gunn3cd820f2018-11-30 14:21:18 -0800198 /**
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800199 * Sets whether the incoming call should be disconnected as if the user had manually
200 * rejected it. This property should only be set to true if the call is disallowed.
201 */
202 public Builder setRejectCall(boolean shouldRejectCall) {
203 mShouldRejectCall = shouldRejectCall;
204 return this;
205 }
206
Tyler Gunn3cd820f2018-11-30 14:21:18 -0800207 /**
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800208 * Sets whether the incoming call should not be displayed in the call log. This property
209 * should only be set to true if the call is disallowed.
Tyler Gunn3cd820f2018-11-30 14:21:18 -0800210 * <p>
211 * Note: Calls will still be logged with type
212 * {@link android.provider.CallLog.Calls#BLOCKED_TYPE}, regardless of how this property
213 * is set.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800214 */
215 public Builder setSkipCallLog(boolean shouldSkipCallLog) {
216 mShouldSkipCallLog = shouldSkipCallLog;
217 return this;
218 }
219
Tyler Gunn3cd820f2018-11-30 14:21:18 -0800220 /**
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800221 * Sets whether a missed call notification should not be shown for the incoming call.
222 * This property should only be set to true if the call is disallowed.
223 */
224 public Builder setSkipNotification(boolean shouldSkipNotification) {
225 mShouldSkipNotification = shouldSkipNotification;
226 return this;
227 }
228
229 public CallResponse build() {
230 return new CallResponse(
231 mShouldDisallowCall,
232 mShouldRejectCall,
233 mShouldSkipCallLog,
234 mShouldSkipNotification);
235 }
236 }
237 }
238
239 public CallScreeningService() {
240 }
241
242 @Override
243 public IBinder onBind(Intent intent) {
244 Log.v(this, "onBind");
245 return new CallScreeningBinder();
246 }
247
248 @Override
249 public boolean onUnbind(Intent intent) {
250 Log.v(this, "onUnbind");
251 return false;
252 }
253
254 /**
Tyler Gunn94f8f112018-12-17 09:56:11 -0800255 * Called when a new incoming or outgoing call is added which is not in the user's contact list.
256 * <p>
257 * A {@link CallScreeningService} must indicate whether an incoming call is allowed or not by
258 * calling
259 * {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}.
260 * Your app can tell if a call is an incoming call by checking to see if
261 * {@link Call.Details#getCallDirection()} is {@link Call.Details#DIRECTION_INCOMING}.
262 * <p>
263 * For incoming or outgoing calls, the {@link CallScreeningService} can call
264 * {@link #provideCallIdentification(Call.Details, CallIdentification)} in order to provide
265 * {@link CallIdentification} for the call.
Tyler Gunn3cd820f2018-11-30 14:21:18 -0800266 * <p>
267 * Note: The {@link Call.Details} instance provided to a call screening service will only have
268 * the following properties set. The rest of the {@link Call.Details} properties will be set to
269 * their default value or {@code null}.
270 * <ul>
Tyler Gunn94f8f112018-12-17 09:56:11 -0800271 * <li>{@link Call.Details#getCallDirection()}</li>
Tyler Gunn3cd820f2018-11-30 14:21:18 -0800272 * <li>{@link Call.Details#getConnectTimeMillis()}</li>
273 * <li>{@link Call.Details#getCreationTimeMillis()}</li>
274 * <li>{@link Call.Details#getHandle()}</li>
275 * <li>{@link Call.Details#getHandlePresentation()}</li>
276 * </ul>
Tyler Gunn94f8f112018-12-17 09:56:11 -0800277 * <p>
278 * Only calls where the {@link Call.Details#getHandle() handle} {@link Uri#getScheme() scheme}
279 * is {@link PhoneAccount#SCHEME_TEL} are passed for call
280 * screening. Further, only calls which are not in the user's contacts are passed for
281 * screening. For outgoing calls, no post-dial digits are passed.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800282 *
Tyler Gunn94f8f112018-12-17 09:56:11 -0800283 * @param callDetails Information about a new call, see {@link Call.Details}.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800284 */
Tyler Gunnd081f042018-12-04 12:56:45 -0800285 public abstract void onScreenCall(@NonNull Call.Details callDetails);
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800286
287 /**
Tyler Gunn94f8f112018-12-17 09:56:11 -0800288 * Responds to the given incoming call, either allowing it or disallowing it.
Tyler Gunnd081f042018-12-04 12:56:45 -0800289 * <p>
290 * The {@link CallScreeningService} calls this method to inform the system whether the call
291 * should be silently blocked or not.
Tyler Gunn94f8f112018-12-17 09:56:11 -0800292 * <p>
293 * Calls to this method are ignored unless the {@link Call.Details#getCallDirection()} is
294 * {@link Call.Details#DIRECTION_INCOMING}.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800295 *
296 * @param callDetails The call to allow.
Tyler Gunnd081f042018-12-04 12:56:45 -0800297 * <p>
298 * Must be the same {@link Call.Details call} which was provided to the
299 * {@link CallScreeningService} via {@link #onScreenCall(Call.Details)}.
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800300 * @param response The {@link CallScreeningService.CallResponse} which contains information
301 * about how to respond to a call.
302 */
Tyler Gunnd081f042018-12-04 12:56:45 -0800303 public final void respondToCall(@NonNull Call.Details callDetails,
304 @NonNull CallResponse response) {
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800305 try {
306 if (response.getDisallowCall()) {
307 mCallScreeningAdapter.disallowCall(
308 callDetails.getTelecomCallId(),
309 response.getRejectCall(),
310 !response.getSkipCallLog(),
tonyzhu9e1d4f82018-10-22 15:11:31 +0800311 !response.getSkipNotification(),
312 new ComponentName(getPackageName(), getClass().getName()));
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800313 } else {
314 mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
315 }
316 } catch (RemoteException e) {
317 }
318 }
Tyler Gunnd081f042018-12-04 12:56:45 -0800319
320 /**
321 * Provide {@link CallIdentification} information about a {@link Call.Details call}.
322 * <p>
323 * The {@link CallScreeningService} calls this method to provide information it has identified
324 * about a {@link Call.Details call}. This information will potentially be shown to the user
325 * in the {@link InCallService dialer} app. It will be logged to the
326 * {@link android.provider.CallLog}.
327 * <p>
328 * A {@link CallScreeningService} should only call this method for calls for which it is able to
329 * provide some {@link CallIdentification} for. {@link CallIdentification} instances with no
330 * fields set will be ignored by the system.
331 *
332 * @param callDetails The call to provide information for.
333 * <p>
334 * Must be the same {@link Call.Details call} which was provided to the
335 * {@link CallScreeningService} via {@link #onScreenCall(Call.Details)}.
336 * @param identification An instance of {@link CallIdentification} with information about the
337 * {@link Call.Details call}.
338 */
339 public final void provideCallIdentification(@NonNull Call.Details callDetails,
340 @NonNull CallIdentification identification) {
341 try {
342 mCallScreeningAdapter.provideCallIdentification(callDetails.getTelecomCallId(),
343 identification);
344 } catch (RemoteException e) {
345 }
346 }
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800347}