1 /*
2  * Copyright (C) 2015 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.cts;
18 
19 import static android.telecom.cts.TestUtils.shouldTestTelecom;
20 
21 import android.content.ContentResolver;
22 import android.telecom.cts.MockCallScreeningService.CallScreeningServiceCallbacks;
23 
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.net.Uri;
27 import android.os.Bundle;
28 import android.telecom.Call;
29 import android.telecom.CallScreeningService;
30 import android.telecom.Connection;
31 import android.telecom.PhoneAccount;
32 import android.telecom.PhoneAccountHandle;
33 import android.telecom.TelecomManager;
34 import android.test.InstrumentationTestCase;
35 import android.text.TextUtils;
36 
37 import java.util.concurrent.TimeUnit;
38 
39 /**
40  * Verify that call screening service gets a chance to block calls.
41  */
42 public class CallScreeningServiceTest extends InstrumentationTestCase {
43     private static final Uri TEST_NUMBER = Uri.fromParts("tel", "7", null);
44 
45     public static final PhoneAccountHandle TEST_PHONE_ACCOUNT_HANDLE = new PhoneAccountHandle(
46             new ComponentName(TestUtils.PACKAGE, TestUtils.COMPONENT),
47             TestUtils.ACCOUNT_ID_1);
48 
49     public static final PhoneAccount TEST_PHONE_ACCOUNT = PhoneAccount.builder(
50             TEST_PHONE_ACCOUNT_HANDLE, TestUtils.ACCOUNT_LABEL)
51             .setAddress(Uri.parse("tel:555-TEST"))
52             .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
53                     PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
54             .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
55             .build();
56 
57     private Context mContext;
58     private TelecomManager mTelecomManager;
59     private String mPreviousDefaultDialer;
60     MockConnectionService mConnectionService;
61     private boolean mCallFound;
62     private ContentResolver mContentResolver;
63     private int mCallerNumberVerificationStatus;
64 
65     @Override
setUp()66     protected void setUp() throws Exception {
67         super.setUp();
68         mContext = getInstrumentation().getContext();
69         mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
70         if (shouldTestTelecom(mContext)) {
71             mPreviousDefaultDialer = TestUtils.getDefaultDialer(getInstrumentation());
72             TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
73             setupConnectionService();
74             MockCallScreeningService.enableService(mContext);
75         }
76         mContentResolver = getInstrumentation().getTargetContext().getContentResolver();
77     }
78 
79     @Override
tearDown()80     protected void tearDown() throws Exception {
81         if (!TextUtils.isEmpty(mPreviousDefaultDialer)) {
82             TestUtils.setDefaultDialer(getInstrumentation(), mPreviousDefaultDialer);
83             mTelecomManager.unregisterPhoneAccount(TEST_PHONE_ACCOUNT_HANDLE);
84             CtsConnectionService.tearDown();
85             mConnectionService = null;
86             MockCallScreeningService.disableService(mContext);
87         }
88         super.tearDown();
89     }
90 
91     /**
92      * Tests that when sending a CALL intent via the Telecom stack, Telecom binds to the registered
93      * {@link CallScreeningService}s and invokes onScreenCall.
94      */
testTelephonyCall_bindsToCallScreeningService()95     public void testTelephonyCall_bindsToCallScreeningService() {
96         if (!shouldTestTelecom(mContext)) {
97             return;
98         }
99 
100         CallScreeningServiceCallbacks callbacks = createCallbacks();
101         MockCallScreeningService.setCallbacks(callbacks);
102         addNewIncomingCall(TEST_NUMBER);
103 
104         try {
105             if (callbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
106                         TimeUnit.SECONDS)) {
107                 assertTrue(mCallFound);
108                 return;
109             }
110         } catch (InterruptedException e) {
111         }
112 
113         fail("No call added to CallScreeningService.");
114     }
115 
116     /**
117      * Tests that when sendinga a CALL intent via the Telecom stack and the test number is in the
118      * user's contact, Telecom binds to the registered {@link CallScreeningService}s and invokes
119      * onScreenCall.
120      */
testBindsToCallScreeningServiceWhenContactExist()121     public void testBindsToCallScreeningServiceWhenContactExist() throws Exception {
122         if (!shouldTestTelecom(mContext)) {
123             return;
124         }
125 
126         CallScreeningServiceCallbacks callbacks = createCallbacks();
127         MockCallScreeningService.setCallbacks(callbacks);
128         Uri contactUri = TestUtils.insertContact(mContentResolver,
129                 TEST_NUMBER.getSchemeSpecificPart());
130         addNewIncomingCall(TEST_NUMBER);
131 
132         try {
133             if (callbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
134                     TimeUnit.SECONDS)) {
135                 assertTrue(mCallFound);
136 
137                 return;
138             }
139         } catch (InterruptedException e) {
140         } finally {
141             assertEquals(1, TestUtils.deleteContact(mContentResolver, contactUri));
142         }
143 
144         fail("No call added to CallScreeningService.");
145     }
146 
147     /**
148      * Tests passing of number verification status.
149      */
testVerificationFailed()150     public void testVerificationFailed() {
151         if (!shouldTestTelecom(mContext)) {
152             return;
153         }
154 
155         CallScreeningServiceCallbacks callbacks = createCallbacks();
156         MockCallScreeningService.setCallbacks(callbacks);
157         addNewIncomingCall(MockConnectionService.VERSTAT_FAILED_NUMBER);
158 
159         try {
160             if (callbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
161                     TimeUnit.SECONDS)) {
162                 assertTrue(mCallFound);
163                 assertEquals(Connection.VERIFICATION_STATUS_FAILED,
164                         mCallerNumberVerificationStatus);
165                 return;
166             }
167         } catch (InterruptedException e) {
168         }
169     }
170 
171     /**
172      * Tests passing of number verification status.
173      */
testNumberNotVerified()174     public void testNumberNotVerified() {
175         if (!shouldTestTelecom(mContext)) {
176             return;
177         }
178 
179         CallScreeningServiceCallbacks callbacks = createCallbacks();
180         MockCallScreeningService.setCallbacks(callbacks);
181         addNewIncomingCall(MockConnectionService.VERSTAT_NOT_VERIFIED_NUMBER);
182 
183         try {
184             if (callbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
185                     TimeUnit.SECONDS)) {
186                 assertTrue(mCallFound);
187                 assertEquals(Connection.VERIFICATION_STATUS_NOT_VERIFIED,
188                         mCallerNumberVerificationStatus);
189                 return;
190             }
191         } catch (InterruptedException e) {
192         }
193 
194         fail("No call added to CallScreeningService.");
195     }
196 
addNewIncomingCall(Uri incomingHandle)197     private void addNewIncomingCall(Uri incomingHandle) {
198         Bundle extras = new Bundle();
199         extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, incomingHandle);
200         mTelecomManager.addNewIncomingCall(TEST_PHONE_ACCOUNT_HANDLE, extras);
201     }
202 
createCallbacks()203     private CallScreeningServiceCallbacks createCallbacks() {
204         return new CallScreeningServiceCallbacks() {
205             @Override
206             public void onScreenCall(Call.Details callDetails) {
207                 mCallFound = true;
208                 mCallerNumberVerificationStatus = callDetails.getCallerNumberVerificationStatus();
209                 CallScreeningService.CallResponse response =
210                         new CallScreeningService.CallResponse.Builder()
211                         .setDisallowCall(true)
212                         .setRejectCall(true)
213                         .setSilenceCall(false)
214                         .setSkipCallLog(true)
215                         .setSkipNotification(true)
216                         .build();
217                 getService().respondToCall(callDetails, response);
218                 lock.release();
219             }
220         };
221     }
222 
223     private void setupConnectionService() throws Exception {
224         mConnectionService = new MockConnectionService();
225         CtsConnectionService.setUp(mConnectionService);
226 
227         mTelecomManager.registerPhoneAccount(TEST_PHONE_ACCOUNT);
228         TestUtils.enablePhoneAccount(getInstrumentation(), TEST_PHONE_ACCOUNT_HANDLE);
229         // Wait till the adb commands have executed and account is enabled in Telecom database.
230         assertPhoneAccountEnabled(TEST_PHONE_ACCOUNT_HANDLE);
231     }
232 
233     private void assertPhoneAccountEnabled(final PhoneAccountHandle handle) {
234         waitUntilConditionIsTrueOrTimeout(
235                 new Condition() {
236                     @Override
237                     public Object expected() {
238                         return true;
239                     }
240 
241                     @Override
242                     public Object actual() {
243                         PhoneAccount phoneAccount = mTelecomManager.getPhoneAccount(handle);
244                         return (phoneAccount != null && phoneAccount.isEnabled());
245                     }
246                 },
247                 TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
248                 "Phone account enable failed for " + handle
249         );
250     }
251 
252     private void waitUntilConditionIsTrueOrTimeout(Condition condition, long timeout,
253             String description) {
254         final long start = System.currentTimeMillis();
255         while (!condition.expected().equals(condition.actual())
256                 && System.currentTimeMillis() - start < timeout) {
257             sleep(50);
258         }
259         assertEquals(description, condition.expected(), condition.actual());
260     }
261 
262     private void sleep(long ms) {
263         try {
264             Thread.sleep(ms);
265         } catch (InterruptedException e) {
266         }
267     }
268 
269     protected interface Condition {
270         Object expected();
271         Object actual();
272     }
273 }
274