• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.server.telecom.callfiltering;
18 
19 import android.provider.CallLog;
20 import android.provider.CallLog.Calls;
21 import android.telecom.CallScreeningService;
22 import android.text.TextUtils;
23 
24 import java.util.Objects;
25 
26 public class CallFilteringResult {
27     public static class Builder {
28         private boolean mShouldAllowCall;
29         private boolean mShouldReject;
30         private boolean mShouldAddToCallLog;
31         private boolean mShouldShowNotification;
32         private boolean mShouldSilence = false;
33         private boolean mShouldScreenViaAudio = false;
34         private boolean mContactExists = false;
35         private int mCallBlockReason = Calls.BLOCK_REASON_NOT_BLOCKED;
36         private CharSequence mCallScreeningAppName = null;
37         private String mCallScreeningComponentName = null;
38         private CallScreeningService.ParcelableCallResponse mCallScreeningResponse = null;
39         private boolean mIsResponseFromSystemDialer = false;
40 
setShouldAllowCall(boolean shouldAllowCall)41         public Builder setShouldAllowCall(boolean shouldAllowCall) {
42             mShouldAllowCall = shouldAllowCall;
43             return this;
44         }
45 
setShouldReject(boolean shouldReject)46         public Builder setShouldReject(boolean shouldReject) {
47             mShouldReject = shouldReject;
48             return this;
49         }
50 
setShouldAddToCallLog(boolean shouldAddToCallLog)51         public Builder setShouldAddToCallLog(boolean shouldAddToCallLog) {
52             mShouldAddToCallLog = shouldAddToCallLog;
53             return this;
54         }
55 
setShouldShowNotification(boolean shouldShowNotification)56         public Builder setShouldShowNotification(boolean shouldShowNotification) {
57             mShouldShowNotification = shouldShowNotification;
58             return this;
59         }
60 
setShouldSilence(boolean shouldSilence)61         public Builder setShouldSilence(boolean shouldSilence) {
62             mShouldSilence = shouldSilence;
63             return this;
64         }
65 
setCallBlockReason(int callBlockReason)66         public Builder setCallBlockReason(int callBlockReason) {
67             mCallBlockReason = callBlockReason;
68             return this;
69         }
70 
setShouldScreenViaAudio(boolean shouldScreenViaAudio)71         public Builder setShouldScreenViaAudio(boolean shouldScreenViaAudio) {
72             mShouldScreenViaAudio = shouldScreenViaAudio;
73             return this;
74         }
75 
setCallScreeningAppName(CharSequence callScreeningAppName)76         public Builder setCallScreeningAppName(CharSequence callScreeningAppName) {
77             mCallScreeningAppName = callScreeningAppName;
78             return this;
79         }
80 
setCallScreeningComponentName(String callScreeningComponentName)81         public Builder setCallScreeningComponentName(String callScreeningComponentName) {
82             mCallScreeningComponentName = callScreeningComponentName;
83             return this;
84         }
85 
setCallScreeningResponse( CallScreeningService.ParcelableCallResponse response, boolean isFromSystemDialer)86         public Builder setCallScreeningResponse(
87                 CallScreeningService.ParcelableCallResponse response, boolean isFromSystemDialer) {
88             mCallScreeningResponse = response;
89             mIsResponseFromSystemDialer = isFromSystemDialer;
90             return this;
91         }
92 
setContactExists(boolean contactExists)93         public Builder setContactExists(boolean contactExists) {
94             mContactExists = contactExists;
95             return this;
96         }
97 
from(CallFilteringResult result)98         public static Builder from(CallFilteringResult result) {
99             return new Builder()
100                     .setShouldAllowCall(result.shouldAllowCall)
101                     .setShouldReject(result.shouldReject)
102                     .setShouldAddToCallLog(result.shouldAddToCallLog)
103                     .setShouldShowNotification(result.shouldShowNotification)
104                     .setShouldSilence(result.shouldSilence)
105                     .setCallBlockReason(result.mCallBlockReason)
106                     .setShouldScreenViaAudio(result.shouldScreenViaAudio)
107                     .setCallScreeningAppName(result.mCallScreeningAppName)
108                     .setCallScreeningComponentName(result.mCallScreeningComponentName)
109                     .setCallScreeningResponse(result.mCallScreeningResponse,
110                             result.mIsResponseFromSystemDialer)
111                     .setContactExists(result.contactExists);
112         }
113 
build()114         public CallFilteringResult build() {
115             return new CallFilteringResult(mShouldAllowCall, mShouldReject, mShouldSilence,
116                     mShouldAddToCallLog, mShouldShowNotification, mCallBlockReason,
117                     mCallScreeningAppName, mCallScreeningComponentName, mCallScreeningResponse,
118                     mIsResponseFromSystemDialer, mShouldScreenViaAudio, mContactExists);
119         }
120     }
121 
122     public boolean shouldAllowCall;
123     public boolean shouldReject;
124     public boolean shouldSilence;
125     public boolean shouldAddToCallLog;
126     public boolean shouldScreenViaAudio = false;
127     public boolean shouldShowNotification;
128     public int mCallBlockReason;
129     public CharSequence mCallScreeningAppName;
130     public String mCallScreeningComponentName;
131     public CallScreeningService.ParcelableCallResponse mCallScreeningResponse;
132     public boolean mIsResponseFromSystemDialer;
133     public boolean contactExists;
134 
CallFilteringResult(boolean shouldAllowCall, boolean shouldReject, boolean shouldSilence, boolean shouldAddToCallLog, boolean shouldShowNotification, int callBlockReason, CharSequence callScreeningAppName, String callScreeningComponentName, CallScreeningService.ParcelableCallResponse callScreeningResponse, boolean isResponseFromSystemDialer, boolean shouldScreenViaAudio, boolean contactExists)135     private CallFilteringResult(boolean shouldAllowCall, boolean shouldReject, boolean
136             shouldSilence, boolean shouldAddToCallLog, boolean shouldShowNotification, int
137             callBlockReason, CharSequence callScreeningAppName, String callScreeningComponentName,
138             CallScreeningService.ParcelableCallResponse callScreeningResponse,
139             boolean isResponseFromSystemDialer,
140             boolean shouldScreenViaAudio, boolean contactExists) {
141         this.shouldAllowCall = shouldAllowCall;
142         this.shouldReject = shouldReject;
143         this.shouldSilence = shouldSilence;
144         this.shouldAddToCallLog = shouldAddToCallLog;
145         this.shouldShowNotification = shouldShowNotification;
146         this.shouldScreenViaAudio = shouldScreenViaAudio;
147         this.mCallBlockReason = callBlockReason;
148         this.mCallScreeningAppName = callScreeningAppName;
149         this.mCallScreeningComponentName = callScreeningComponentName;
150         this.mCallScreeningResponse = callScreeningResponse;
151         this.mIsResponseFromSystemDialer = isResponseFromSystemDialer;
152         this.contactExists = contactExists;
153     }
154 
155     /**
156      * Combine this CallFilteringResult with another, returning a CallFilteringResult with the more
157      * restrictive properties of the two. Where there are multiple call filtering components which
158      * block a call, the first filter from {@link BlockCheckerFilter},
159      * {@link DirectToVoicemailFilter}, {@link CallScreeningServiceFilter} which blocked a call
160      * shall be used to populate the call block reason, component name, etc.
161      */
combine(CallFilteringResult other)162     public CallFilteringResult combine(CallFilteringResult other) {
163         if (other == null) {
164             return this;
165         }
166 
167         if (isBlockedByProvider(mCallBlockReason)) {
168             return getCombinedCallFilteringResult(other, mCallBlockReason,
169                     null /*callScreeningAppName*/, null /*callScreeningComponentName*/);
170         } else if (isBlockedByProvider(other.mCallBlockReason)) {
171             return getCombinedCallFilteringResult(other, other.mCallBlockReason,
172                     null /*callScreeningAppName*/, null /*callScreeningComponentName*/);
173         }
174 
175         if (mCallBlockReason == Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL
176                 || other.mCallBlockReason == Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL) {
177             return getCombinedCallFilteringResult(other, Calls.BLOCK_REASON_DIRECT_TO_VOICEMAIL,
178                     null /*callScreeningAppName*/, null /*callScreeningComponentName*/);
179         }
180 
181         if (shouldReject && mCallBlockReason == CallLog.Calls.BLOCK_REASON_CALL_SCREENING_SERVICE) {
182             return getCombinedCallFilteringResult(other, Calls.BLOCK_REASON_CALL_SCREENING_SERVICE,
183                     mCallScreeningAppName, mCallScreeningComponentName);
184         } else if (other.shouldReject && other.mCallBlockReason == CallLog.Calls
185                 .BLOCK_REASON_CALL_SCREENING_SERVICE) {
186             return getCombinedCallFilteringResult(other, Calls.BLOCK_REASON_CALL_SCREENING_SERVICE,
187                     other.mCallScreeningAppName, other.mCallScreeningComponentName);
188         }
189 
190         if (shouldScreenViaAudio) {
191             return getCombinedCallFilteringResult(other, Calls.BLOCK_REASON_NOT_BLOCKED,
192                     mCallScreeningAppName, mCallScreeningComponentName);
193         } else if (other.shouldScreenViaAudio) {
194             return getCombinedCallFilteringResult(other, Calls.BLOCK_REASON_NOT_BLOCKED,
195                     other.mCallScreeningAppName, other.mCallScreeningComponentName);
196         }
197 
198         Builder b = new Builder()
199                 .setShouldAllowCall(shouldAllowCall && other.shouldAllowCall)
200                 .setShouldReject(shouldReject || other.shouldReject)
201                 .setShouldSilence(shouldSilence || other.shouldSilence)
202                 .setShouldAddToCallLog(shouldAddToCallLog && other.shouldAddToCallLog)
203                 .setShouldShowNotification(shouldShowNotification && other.shouldShowNotification)
204                 .setShouldScreenViaAudio(shouldScreenViaAudio || other.shouldScreenViaAudio)
205                 .setContactExists(contactExists || other.contactExists);
206         combineScreeningResponses(b, this, other);
207         return b.build();
208     }
209 
isBlockedByProvider(int blockReason)210     private boolean isBlockedByProvider(int blockReason) {
211         if (blockReason == Calls.BLOCK_REASON_BLOCKED_NUMBER
212             || blockReason == Calls.BLOCK_REASON_UNKNOWN_NUMBER
213             || blockReason == Calls.BLOCK_REASON_RESTRICTED_NUMBER
214             || blockReason == Calls.BLOCK_REASON_PAY_PHONE
215             || blockReason == Calls.BLOCK_REASON_NOT_IN_CONTACTS) {
216             return true;
217         }
218 
219         return false;
220     }
221 
getCombinedCallFilteringResult(CallFilteringResult other, int callBlockReason, CharSequence callScreeningAppName, String callScreeningComponentName)222     private CallFilteringResult getCombinedCallFilteringResult(CallFilteringResult other,
223             int callBlockReason, CharSequence callScreeningAppName,
224             String callScreeningComponentName) {
225         Builder b = new Builder()
226                 .setShouldAllowCall(shouldAllowCall && other.shouldAllowCall)
227                 .setShouldReject(shouldReject || other.shouldReject)
228                 .setShouldSilence(shouldSilence || other.shouldSilence)
229                 .setShouldAddToCallLog(shouldAddToCallLog && other.shouldAddToCallLog)
230                 .setShouldShowNotification(shouldShowNotification && other.shouldShowNotification)
231                 .setShouldScreenViaAudio(shouldScreenViaAudio || other.shouldScreenViaAudio)
232                 .setCallBlockReason(callBlockReason)
233                 .setCallScreeningAppName(callScreeningAppName)
234                 .setCallScreeningComponentName(callScreeningComponentName)
235                 .setContactExists(contactExists || other.contactExists);
236         combineScreeningResponses(b, this, other);
237         return b.build();
238     }
239 
combineScreeningResponses(Builder builder, CallFilteringResult r1, CallFilteringResult r2)240     private static void combineScreeningResponses(Builder builder, CallFilteringResult r1,
241             CallFilteringResult r2) {
242         if (r1.mIsResponseFromSystemDialer) {
243             builder.setCallScreeningResponse(r1.mCallScreeningResponse, true);
244             builder.setCallScreeningComponentName(r1.mCallScreeningComponentName);
245             builder.setCallScreeningAppName(r1.mCallScreeningAppName);
246         } else if (r2.mIsResponseFromSystemDialer) {
247             builder.setCallScreeningResponse(r2.mCallScreeningResponse, true);
248             builder.setCallScreeningComponentName(r2.mCallScreeningComponentName);
249             builder.setCallScreeningAppName(r2.mCallScreeningAppName);
250         } else {
251             if (r1.mCallScreeningResponse != null) {
252                 builder.setCallScreeningResponse(r1.mCallScreeningResponse, false);
253                 builder.setCallScreeningComponentName(r1.mCallScreeningComponentName);
254                 builder.setCallScreeningAppName(r1.mCallScreeningAppName);
255             } else {
256                 builder.setCallScreeningResponse(r2.mCallScreeningResponse, false);
257                 builder.setCallScreeningComponentName(r2.mCallScreeningComponentName);
258                 builder.setCallScreeningAppName(r2.mCallScreeningAppName);
259             }
260         }
261     }
262 
263     @Override
equals(Object o)264     public boolean equals(Object o) {
265         if (this == o) return true;
266         if (o == null || getClass() != o.getClass()) return false;
267 
268         CallFilteringResult that = (CallFilteringResult) o;
269 
270         if (shouldAllowCall != that.shouldAllowCall) return false;
271         if (shouldReject != that.shouldReject) return false;
272         if (shouldSilence != that.shouldSilence) return false;
273         if (shouldAddToCallLog != that.shouldAddToCallLog) return false;
274         if (shouldShowNotification != that.shouldShowNotification) return false;
275         if (mCallBlockReason != that.mCallBlockReason) return false;
276         if (contactExists != that.contactExists) return false;
277 
278         if (!Objects.equals(mCallScreeningAppName, that.mCallScreeningAppName)) return false;
279         if (!Objects.equals(mCallScreeningComponentName, that.mCallScreeningComponentName)) {
280             return false;
281         }
282         return true;
283     }
284 
285     @Override
hashCode()286     public int hashCode() {
287         int result = (shouldAllowCall ? 1 : 0);
288         result = 31 * result + (shouldReject ? 1 : 0);
289         result = 31 * result + (shouldSilence ? 1 : 0);
290         result = 31 * result + (shouldAddToCallLog ? 1 : 0);
291         result = 31 * result + (shouldShowNotification ? 1 : 0);
292         return result;
293     }
294 
295     @Override
toString()296     public String toString() {
297         StringBuilder sb = new StringBuilder();
298         sb.append("[");
299         if (shouldAllowCall) {
300             sb.append("Allow");
301         } else if (shouldReject) {
302             sb.append("Reject");
303         } else if (shouldSilence) {
304             sb.append("Silence");
305         } else {
306             sb.append("Ignore");
307         }
308 
309         if (shouldScreenViaAudio) {
310             sb.append(", audio processing");
311         }
312 
313         if (shouldAddToCallLog) {
314             sb.append(", logged");
315         }
316 
317         if (shouldShowNotification) {
318             sb.append(", notified");
319         }
320 
321         if (contactExists) {
322             sb.append(", contact exists");
323         }
324 
325         if (mCallBlockReason != 0) {
326             sb.append(", mCallBlockReason = ");
327             sb.append(mCallBlockReason);
328         }
329 
330         if (!TextUtils.isEmpty(mCallScreeningAppName)) {
331             sb.append(", mCallScreeningAppName = ");
332             sb.append(mCallScreeningAppName);
333         }
334 
335         if (!TextUtils.isEmpty(mCallScreeningComponentName)) {
336             sb.append(", mCallScreeningComponentName = ");
337             sb.append(mCallScreeningComponentName);
338         }
339         sb.append("]");
340 
341         return sb.toString();
342     }
343 }
344