1 /*
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 
17 package android.telecom;
18 
19 import android.Manifest;
20 import android.annotation.NonNull;
21 import android.annotation.RequiresPermission;
22 import android.annotation.SdkConstant;
23 import android.annotation.SystemApi;
24 import android.annotation.TestApi;
25 import android.app.Service;
26 import android.content.ComponentName;
27 import android.content.Intent;
28 import android.net.Uri;
29 import android.os.Handler;
30 import android.os.IBinder;
31 import android.os.Looper;
32 import android.os.Message;
33 import android.os.RemoteException;
34 
35 import com.android.internal.os.SomeArgs;
36 import com.android.internal.telecom.ICallScreeningAdapter;
37 import com.android.internal.telecom.ICallScreeningService;
38 
39 /**
40  * This service can be implemented by the default dialer (see
41  * {@link TelecomManager#getDefaultDialerPackage()}) or a third party app to allow or disallow
42  * incoming calls before they are shown to a user. A {@link CallScreeningService} can also see
43  * outgoing calls for the purpose of providing caller ID services for those calls.
44  * <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>
56  * <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 - services which provide call identification functionality can
62  *     display a user-interface of their choosing which contains identifying information for a call.
63  *     </li>
64  * </ol>
65  * <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(RoleManager.ROLE_CALL_SCREENING);
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>
93  */
94 public abstract class CallScreeningService extends Service {
95     /**
96      * The {@link Intent} that must be declared as handled by the service.
97      */
98     @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
99     public static final String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
100 
101     private static final int MSG_SCREEN_CALL = 1;
102 
103     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
104         @Override
105         public void handleMessage(Message msg) {
106             switch (msg.what) {
107                 case MSG_SCREEN_CALL:
108                     SomeArgs args = (SomeArgs) msg.obj;
109                     try {
110                         mCallScreeningAdapter = (ICallScreeningAdapter) args.arg1;
111                         Call.Details callDetails = Call.Details
112                                 .createFromParcelableCall((ParcelableCall) args.arg2);
113                         onScreenCall(callDetails);
114                         if (callDetails.getCallDirection() == Call.Details.DIRECTION_OUTGOING) {
115                             mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
116                         }
117                     } catch (RemoteException e) {
118                         Log.w(this, "Exception when screening call: " + e);
119                     } finally {
120                         args.recycle();
121                     }
122                     break;
123             }
124         }
125     };
126 
127     private final class CallScreeningBinder extends ICallScreeningService.Stub {
128         @Override
screenCall(ICallScreeningAdapter adapter, ParcelableCall call)129         public void screenCall(ICallScreeningAdapter adapter, ParcelableCall call) {
130             Log.v(this, "screenCall");
131             SomeArgs args = SomeArgs.obtain();
132             args.arg1 = adapter;
133             args.arg2 = call;
134             mHandler.obtainMessage(MSG_SCREEN_CALL, args).sendToTarget();
135         }
136     }
137 
138     private ICallScreeningAdapter mCallScreeningAdapter;
139 
140     /*
141      * Information about how to respond to an incoming call.
142      */
143     public static class CallResponse {
144         private final boolean mShouldDisallowCall;
145         private final boolean mShouldRejectCall;
146         private final boolean mShouldSilenceCall;
147         private final boolean mShouldSkipCallLog;
148         private final boolean mShouldSkipNotification;
149         private final boolean mShouldScreenCallViaAudioProcessing;
150 
CallResponse( boolean shouldDisallowCall, boolean shouldRejectCall, boolean shouldSilenceCall, boolean shouldSkipCallLog, boolean shouldSkipNotification, boolean shouldScreenCallViaAudioProcessing)151         private CallResponse(
152                 boolean shouldDisallowCall,
153                 boolean shouldRejectCall,
154                 boolean shouldSilenceCall,
155                 boolean shouldSkipCallLog,
156                 boolean shouldSkipNotification,
157                 boolean shouldScreenCallViaAudioProcessing) {
158             if (!shouldDisallowCall
159                     && (shouldRejectCall || shouldSkipCallLog || shouldSkipNotification)) {
160                 throw new IllegalStateException("Invalid response state for allowed call.");
161             }
162 
163             if (shouldDisallowCall && shouldScreenCallViaAudioProcessing) {
164                 throw new IllegalStateException("Invalid response state for allowed call.");
165             }
166 
167             mShouldDisallowCall = shouldDisallowCall;
168             mShouldRejectCall = shouldRejectCall;
169             mShouldSkipCallLog = shouldSkipCallLog;
170             mShouldSkipNotification = shouldSkipNotification;
171             mShouldSilenceCall = shouldSilenceCall;
172             mShouldScreenCallViaAudioProcessing = shouldScreenCallViaAudioProcessing;
173         }
174 
175         /*
176          * @return Whether the incoming call should be blocked.
177          */
getDisallowCall()178         public boolean getDisallowCall() {
179             return mShouldDisallowCall;
180         }
181 
182         /*
183          * @return Whether the incoming call should be disconnected as if the user had manually
184          * rejected it.
185          */
getRejectCall()186         public boolean getRejectCall() {
187             return mShouldRejectCall;
188         }
189 
190         /*
191          * @return Whether the ringtone should be silenced for the incoming call.
192          */
getSilenceCall()193         public boolean getSilenceCall() {
194             return mShouldSilenceCall;
195         }
196 
197         /*
198          * @return Whether the incoming call should not be displayed in the call log.
199          */
getSkipCallLog()200         public boolean getSkipCallLog() {
201             return mShouldSkipCallLog;
202         }
203 
204         /*
205          * @return Whether a missed call notification should not be shown for the incoming call.
206          */
getSkipNotification()207         public boolean getSkipNotification() {
208             return mShouldSkipNotification;
209         }
210 
211         /**
212          * @return Whether we should enter the {@link Call#STATE_AUDIO_PROCESSING} state to allow
213          * for further screening of the call.
214          * @hide
215          */
getShouldScreenCallViaAudioProcessing()216         public boolean getShouldScreenCallViaAudioProcessing() {
217             return mShouldScreenCallViaAudioProcessing;
218         }
219 
220         public static class Builder {
221             private boolean mShouldDisallowCall;
222             private boolean mShouldRejectCall;
223             private boolean mShouldSilenceCall;
224             private boolean mShouldSkipCallLog;
225             private boolean mShouldSkipNotification;
226             private boolean mShouldScreenCallViaAudioProcessing;
227 
228             /**
229              * Sets whether the incoming call should be blocked.
230              */
setDisallowCall(boolean shouldDisallowCall)231             public Builder setDisallowCall(boolean shouldDisallowCall) {
232                 mShouldDisallowCall = shouldDisallowCall;
233                 return this;
234             }
235 
236             /**
237              * Sets whether the incoming call should be disconnected as if the user had manually
238              * rejected it. This property should only be set to true if the call is disallowed.
239              */
setRejectCall(boolean shouldRejectCall)240             public Builder setRejectCall(boolean shouldRejectCall) {
241                 mShouldRejectCall = shouldRejectCall;
242                 return this;
243             }
244 
245             /**
246              * Sets whether ringing should be silenced for the incoming call.  When set
247              * to {@code true}, the Telecom framework will not play a ringtone for the call.
248              * The call will, however, still be sent to the default dialer app if it is not blocked.
249              * A {@link CallScreeningService} can use this to ensure a potential nuisance call is
250              * still surfaced to the user, but in a less intrusive manner.
251              *
252              * Setting this to true only makes sense when the call has not been disallowed
253              * using {@link #setDisallowCall(boolean)}.
254              */
setSilenceCall(boolean shouldSilenceCall)255             public @NonNull Builder setSilenceCall(boolean shouldSilenceCall) {
256                 mShouldSilenceCall = shouldSilenceCall;
257                 return this;
258             }
259 
260             /**
261              * Sets whether the incoming call should not be displayed in the call log. This property
262              * should only be set to true if the call is disallowed.
263              * <p>
264              * Note: Calls will still be logged with type
265              * {@link android.provider.CallLog.Calls#BLOCKED_TYPE}, regardless of how this property
266              * is set.
267              */
setSkipCallLog(boolean shouldSkipCallLog)268             public Builder setSkipCallLog(boolean shouldSkipCallLog) {
269                 mShouldSkipCallLog = shouldSkipCallLog;
270                 return this;
271             }
272 
273             /**
274              * Sets whether a missed call notification should not be shown for the incoming call.
275              * This property should only be set to true if the call is disallowed.
276              */
setSkipNotification(boolean shouldSkipNotification)277             public Builder setSkipNotification(boolean shouldSkipNotification) {
278                 mShouldSkipNotification = shouldSkipNotification;
279                 return this;
280             }
281 
282             /**
283              * Sets whether to request background audio processing so that the in-call service can
284              * screen the call further. If set to {@code true}, {@link #setDisallowCall} should be
285              * called with {@code false}, and all other parameters in this builder will be ignored.
286              *
287              * This request will only be honored if the {@link CallScreeningService} shares the same
288              * uid as the default dialer app. Otherwise, the call will go through as usual.
289              *
290              * @param shouldScreenCallViaAudioProcessing Whether to request further call screening.
291              * @hide
292              */
293             @SystemApi
294             @TestApi
295             @RequiresPermission(Manifest.permission.CAPTURE_AUDIO_OUTPUT)
setShouldScreenCallViaAudioProcessing( boolean shouldScreenCallViaAudioProcessing)296             public @NonNull Builder setShouldScreenCallViaAudioProcessing(
297                     boolean shouldScreenCallViaAudioProcessing) {
298                 mShouldScreenCallViaAudioProcessing = shouldScreenCallViaAudioProcessing;
299                 return this;
300             }
301 
build()302             public CallResponse build() {
303                 return new CallResponse(
304                         mShouldDisallowCall,
305                         mShouldRejectCall,
306                         mShouldSilenceCall,
307                         mShouldSkipCallLog,
308                         mShouldSkipNotification,
309                         mShouldScreenCallViaAudioProcessing);
310             }
311        }
312     }
313 
CallScreeningService()314     public CallScreeningService() {
315     }
316 
317     @Override
onBind(Intent intent)318     public IBinder onBind(Intent intent) {
319         Log.v(this, "onBind");
320         return new CallScreeningBinder();
321     }
322 
323     @Override
onUnbind(Intent intent)324     public boolean onUnbind(Intent intent) {
325         Log.v(this, "onUnbind");
326         return false;
327     }
328 
329     /**
330      * Called when a new incoming or outgoing call is added which is not in the user's contact list.
331      * <p>
332      * A {@link CallScreeningService} must indicate whether an incoming call is allowed or not by
333      * calling
334      * {@link CallScreeningService#respondToCall(Call.Details, CallScreeningService.CallResponse)}.
335      * Your app can tell if a call is an incoming call by checking to see if
336      * {@link Call.Details#getCallDirection()} is {@link Call.Details#DIRECTION_INCOMING}.
337      * <p>
338      * Note: The {@link Call.Details} instance provided to a call screening service will only have
339      * the following properties set.  The rest of the {@link Call.Details} properties will be set to
340      * their default value or {@code null}.
341      * <ul>
342      *     <li>{@link Call.Details#getCallDirection()}</li>
343      *     <li>{@link Call.Details#getConnectTimeMillis()}</li>
344      *     <li>{@link Call.Details#getCreationTimeMillis()}</li>
345      *     <li>{@link Call.Details#getHandle()}</li>
346      *     <li>{@link Call.Details#getHandlePresentation()}</li>
347      * </ul>
348      * <p>
349      * Only calls where the {@link Call.Details#getHandle() handle} {@link Uri#getScheme() scheme}
350      * is {@link PhoneAccount#SCHEME_TEL} are passed for call
351      * screening.  Further, only calls which are not in the user's contacts are passed for
352      * screening.  For outgoing calls, no post-dial digits are passed.
353      *
354      * @param callDetails Information about a new call, see {@link Call.Details}.
355      */
onScreenCall(@onNull Call.Details callDetails)356     public abstract void onScreenCall(@NonNull Call.Details callDetails);
357 
358     /**
359      * Responds to the given incoming call, either allowing it, silencing it or disallowing it.
360      * <p>
361      * The {@link CallScreeningService} calls this method to inform the system whether the call
362      * should be silently blocked or not. In the event that it should not be blocked, it may
363      * also be requested to ring silently.
364      * <p>
365      * Calls to this method are ignored unless the {@link Call.Details#getCallDirection()} is
366      * {@link Call.Details#DIRECTION_INCOMING}.
367      *
368      * @param callDetails The call to allow.
369      *                    <p>
370      *                    Must be the same {@link Call.Details call} which was provided to the
371      *                    {@link CallScreeningService} via {@link #onScreenCall(Call.Details)}.
372      * @param response The {@link CallScreeningService.CallResponse} which contains information
373      * about how to respond to a call.
374      */
respondToCall(@onNull Call.Details callDetails, @NonNull CallResponse response)375     public final void respondToCall(@NonNull Call.Details callDetails,
376             @NonNull CallResponse response) {
377         try {
378             if (response.getDisallowCall()) {
379                 mCallScreeningAdapter.disallowCall(
380                         callDetails.getTelecomCallId(),
381                         response.getRejectCall(),
382                         !response.getSkipCallLog(),
383                         !response.getSkipNotification(),
384                         new ComponentName(getPackageName(), getClass().getName()));
385             } else if (response.getSilenceCall()) {
386                 mCallScreeningAdapter.silenceCall(callDetails.getTelecomCallId());
387             } else if (response.getShouldScreenCallViaAudioProcessing()) {
388                 mCallScreeningAdapter.screenCallFurther(callDetails.getTelecomCallId());
389             } else {
390                 mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
391             }
392         } catch (RemoteException e) {
393         }
394     }
395 }
396