• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.server.telecom.tests;
18 
19 import android.app.Notification;
20 import android.app.NotificationManager;
21 import android.app.PendingIntent;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.pm.ApplicationInfo;
26 import android.net.Uri;
27 import android.os.UserHandle;
28 import android.telecom.PhoneAccount;
29 import android.telecom.PhoneAccount.Builder;
30 import android.telecom.PhoneAccountHandle;
31 import android.telecom.TelecomManager;
32 import android.telephony.TelephonyManager;
33 import android.test.suitebuilder.annotation.SmallTest;
34 
35 import com.android.server.telecom.Call;
36 import com.android.server.telecom.Constants;
37 import com.android.server.telecom.MissedCallNotifier;
38 import com.android.server.telecom.PhoneAccountRegistrar;
39 import com.android.server.telecom.PhoneNumberUtilsAdapterImpl;
40 import com.android.server.telecom.TelecomBroadcastIntentProcessor;
41 import com.android.server.telecom.components.TelecomBroadcastReceiver;
42 import com.android.server.telecom.ui.MissedCallNotifierImpl;
43 import com.android.server.telecom.ui.MissedCallNotifierImpl.NotificationBuilderFactory;
44 
45 import org.mockito.ArgumentCaptor;
46 import org.mockito.Mock;
47 import org.mockito.MockitoAnnotations;
48 
49 import java.util.Arrays;
50 import java.util.HashSet;
51 
52 import static org.mockito.Matchers.any;
53 import static org.mockito.Matchers.eq;
54 import static org.mockito.Matchers.isNull;
55 import static org.mockito.Mockito.doReturn;
56 import static org.mockito.Mockito.mock;
57 import static org.mockito.Mockito.never;
58 import static org.mockito.Mockito.spy;
59 import static org.mockito.Mockito.times;
60 import static org.mockito.Mockito.verify;
61 import static org.mockito.Mockito.when;
62 
63 public class MissedCallNotifierImplTest extends TelecomTestCase {
64 
65     private static final Uri TEL_CALL_HANDLE = Uri.parse("tel:+11915552620");
66     private static final Uri SIP_CALL_HANDLE = Uri.parse("sip:testaddress@testdomain.com");
67     private static final String CALLER_NAME = "Fake Name";
68     private static final String MISSED_CALL_TITLE = "Missed Call";
69     private static final String MISSED_CALLS_TITLE = "Missed Calls";
70     private static final String MISSED_CALLS_MSG = "%s missed calls";
71     private static final String USER_CALL_ACTIVITY_LABEL = "Phone";
72 
73     private static final int REQUEST_ID = 0;
74     private static final long CALL_TIMESTAMP;
75     static {
76          CALL_TIMESTAMP = System.currentTimeMillis() - 60 * 1000 * 5;
77     }
78 
79     private static final UserHandle PRIMARY_USER = UserHandle.of(0);
80     private static final UserHandle SECONARY_USER = UserHandle.of(12);
81     private static final int NO_CAPABILITY = 0;
82 
83     @Mock
84     private NotificationManager mNotificationManager;
85 
86     @Mock
87     private PhoneAccountRegistrar mPhoneAccountRegistrar;
88 
89     @Mock
90     private TelecomManager mTelecomManager;
91 
92     @Override
setUp()93     public void setUp() throws Exception {
94         super.setUp();
95         MockitoAnnotations.initMocks(this);
96 
97         mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
98         mNotificationManager = (NotificationManager) mContext.getSystemService(
99                 Context.NOTIFICATION_SERVICE);
100         TelephonyManager fakeTelephonyManager = (TelephonyManager) mContext.getSystemService(
101                 Context.TELEPHONY_SERVICE);
102         when(fakeTelephonyManager.getNetworkCountryIso()).thenReturn("US");
103         doReturn(new ApplicationInfo()).when(mContext).getApplicationInfo();
104         doReturn("com.android.server.telecom.tests").when(mContext).getPackageName();
105 
106         mComponentContextFixture.putResource(R.string.notification_missedCallTitle,
107                 MISSED_CALL_TITLE);
108         mComponentContextFixture.putResource(R.string.notification_missedCallsTitle,
109                 MISSED_CALLS_TITLE);
110         mComponentContextFixture.putResource(R.string.notification_missedCallsMsg,
111                 MISSED_CALLS_MSG);
112         mComponentContextFixture.putResource(R.string.userCallActivityLabel,
113                 USER_CALL_ACTIVITY_LABEL);
114         mComponentContextFixture.setTelecomManager(mTelecomManager);
115     }
116 
117     @SmallTest
testCancelNotificationInPrimaryUser()118     public void testCancelNotificationInPrimaryUser() {
119         cancelNotificationTestInternal(PRIMARY_USER);
120     }
121 
122     @SmallTest
testCancelNotificationInSecondaryUser()123     public void testCancelNotificationInSecondaryUser() {
124         cancelNotificationTestInternal(SECONARY_USER);
125     }
126 
cancelNotificationTestInternal(UserHandle userHandle)127     private void cancelNotificationTestInternal(UserHandle userHandle) {
128         Notification.Builder builder1 = makeNotificationBuilder("builder1");
129         Notification.Builder builder2 = makeNotificationBuilder("builder2");
130         MissedCallNotifierImpl.NotificationBuilderFactory fakeBuilderFactory =
131                 makeNotificationBuilderFactory(builder1, builder1, builder2, builder2);
132 
133         MissedCallNotifier missedCallNotifier = makeMissedCallNotifier(fakeBuilderFactory,
134                 PRIMARY_USER);
135         PhoneAccount phoneAccount = makePhoneAccount(userHandle, NO_CAPABILITY);
136         Call fakeCall = makeFakeCall(TEL_CALL_HANDLE, CALLER_NAME, CALL_TIMESTAMP,
137                 phoneAccount.getAccountHandle());
138 
139         missedCallNotifier.showMissedCallNotification(fakeCall);
140         missedCallNotifier.clearMissedCalls(userHandle);
141         missedCallNotifier.showMissedCallNotification(fakeCall);
142 
143         ArgumentCaptor<Integer> requestIdCaptor = ArgumentCaptor.forClass(
144                 Integer.class);
145         verify(mNotificationManager, times(2)).notifyAsUser(isNull(String.class),
146                 requestIdCaptor.capture(), any(Notification.class), eq(userHandle));
147         verify(mNotificationManager).cancelAsUser(any(String.class), eq(requestIdCaptor.getValue()),
148                 eq(userHandle));
149 
150         // Verify that the second call to showMissedCallNotification behaves like it were the first.
151         verify(builder2).setContentText(CALLER_NAME);
152     }
153 
154     @SmallTest
testNotifyMultipleMissedCalls()155     public void testNotifyMultipleMissedCalls() {
156         Notification.Builder[] builders = new Notification.Builder[4];
157 
158         for (int i = 0; i < 4; i++) {
159             builders[i] = makeNotificationBuilder("builder" + Integer.toString(i));
160         }
161 
162         PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER, NO_CAPABILITY);
163         Call fakeCall = makeFakeCall(TEL_CALL_HANDLE, CALLER_NAME, CALL_TIMESTAMP,
164                 phoneAccount.getAccountHandle());
165 
166         MissedCallNotifierImpl.NotificationBuilderFactory fakeBuilderFactory =
167                 makeNotificationBuilderFactory(builders);
168 
169         MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
170                 mPhoneAccountRegistrar, new PhoneNumberUtilsAdapterImpl(), fakeBuilderFactory);
171 
172         missedCallNotifier.showMissedCallNotification(fakeCall);
173         missedCallNotifier.showMissedCallNotification(fakeCall);
174 
175         // The following captor is to capture the two notifications that got passed into
176         // notifyAsUser. This distinguishes between the builders used for the full notification
177         // (i.e. the one potentially containing sensitive information, such as phone numbers),
178         // and the builders used for the notifications shown on the lockscreen, which have been
179         // scrubbed of such sensitive info. The notifications which are used as arguments
180         // to notifyAsUser are the versions which contain sensitive information.
181         ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass(
182                 Notification.class);
183         verify(mNotificationManager, times(2)).notifyAsUser(isNull(String.class), eq(1),
184                 notificationArgumentCaptor.capture(), eq(PRIMARY_USER));
185         HashSet<String> privateNotifications = new HashSet<>();
186         for (Notification n : notificationArgumentCaptor.getAllValues()) {
187             privateNotifications.add(n.toString());
188         }
189 
190         for (int i = 0; i < 4; i++) {
191             Notification.Builder builder = builders[i];
192             verify(builder).setWhen(CALL_TIMESTAMP);
193             if (i >= 2) {
194                 // The builders after the first two are for multiple missed calls. The notification
195                 // for subsequent missed calls is expected to be different in terms of the text
196                 // contents of the notification, and that is verified here.
197                 if (privateNotifications.contains(builder.toString())) {
198                     verify(builder).setContentText(String.format(MISSED_CALLS_MSG, 2));
199                     verify(builder).setContentTitle(MISSED_CALLS_TITLE);
200                 } else {
201                     verify(builder).setContentText(MISSED_CALLS_TITLE);
202                     verify(builder).setContentTitle(USER_CALL_ACTIVITY_LABEL);
203                 }
204                 verify(builder, never()).addAction(any(Notification.Action.class));
205             } else {
206                 if (privateNotifications.contains(builder.toString())) {
207                     verify(builder).setContentText(CALLER_NAME);
208                     verify(builder).setContentTitle(MISSED_CALL_TITLE);
209                 } else {
210                     verify(builder).setContentText(MISSED_CALL_TITLE);
211                     verify(builder).setContentTitle(USER_CALL_ACTIVITY_LABEL);
212                 }
213             }
214         }
215     }
216 
217     @SmallTest
testNotifySingleCallInPrimaryUser()218     public void testNotifySingleCallInPrimaryUser() {
219         PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER, NO_CAPABILITY);
220         notifySingleCallTestInternal(phoneAccount, PRIMARY_USER);
221     }
222 
223     @SmallTest
testNotifySingleCallInSecondaryUser()224     public void testNotifySingleCallInSecondaryUser() {
225         PhoneAccount phoneAccount = makePhoneAccount(SECONARY_USER, NO_CAPABILITY);
226         notifySingleCallTestInternal(phoneAccount, PRIMARY_USER);
227     }
228 
229     @SmallTest
testNotifySingleCallInSecondaryUserWithMultiUserCapability()230     public void testNotifySingleCallInSecondaryUserWithMultiUserCapability() {
231         PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER,
232                 PhoneAccount.CAPABILITY_MULTI_USER);
233         notifySingleCallTestInternal(phoneAccount, PRIMARY_USER);
234     }
235 
236     @SmallTest
testNotifySingleCallWhenCurrentUserIsSecondaryUser()237     public void testNotifySingleCallWhenCurrentUserIsSecondaryUser() {
238         PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER, NO_CAPABILITY);
239         notifySingleCallTestInternal(phoneAccount, SECONARY_USER);
240     }
241 
242     @SmallTest
testNotifySingleCall()243     public void testNotifySingleCall() {
244         PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER, NO_CAPABILITY);
245         notifySingleCallTestInternal(phoneAccount, PRIMARY_USER);
246     }
247 
notifySingleCallTestInternal(PhoneAccount phoneAccount, UserHandle currentUser)248     private void notifySingleCallTestInternal(PhoneAccount phoneAccount, UserHandle currentUser) {
249         Notification.Builder builder1 = makeNotificationBuilder("builder1");
250         Notification.Builder builder2 = makeNotificationBuilder("builder2");
251         MissedCallNotifierImpl.NotificationBuilderFactory fakeBuilderFactory =
252                 makeNotificationBuilderFactory(builder1, builder2);
253 
254         MissedCallNotifier missedCallNotifier = makeMissedCallNotifier(fakeBuilderFactory,
255                 currentUser);
256 
257         Call fakeCall = makeFakeCall(TEL_CALL_HANDLE, CALLER_NAME, CALL_TIMESTAMP,
258                 phoneAccount.getAccountHandle());
259         missedCallNotifier.showMissedCallNotification(fakeCall);
260 
261         ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass(
262                 Notification.class);
263 
264         UserHandle expectedUserHandle;
265         if (phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
266             expectedUserHandle = currentUser;
267         } else {
268             expectedUserHandle = phoneAccount.getAccountHandle().getUserHandle();
269         }
270         verify(mNotificationManager).notifyAsUser(isNull(String.class), eq(1),
271                 notificationArgumentCaptor.capture(), eq((expectedUserHandle)));
272 
273         Notification.Builder builder;
274         Notification.Builder publicBuilder;
275 
276         if (notificationArgumentCaptor.getValue().toString().equals("builder1")) {
277             builder = builder1;
278             publicBuilder = builder2;
279         } else {
280             builder = builder2;
281             publicBuilder = builder1;
282         }
283 
284         verify(builder).setWhen(CALL_TIMESTAMP);
285         verify(publicBuilder).setWhen(CALL_TIMESTAMP);
286 
287         verify(builder).setContentText(CALLER_NAME);
288         verify(publicBuilder).setContentText(MISSED_CALL_TITLE);
289 
290         verify(builder).setContentTitle(MISSED_CALL_TITLE);
291         verify(publicBuilder).setContentTitle(USER_CALL_ACTIVITY_LABEL);
292 
293         // Create two intents that correspond to call-back and respond back with SMS, and assert
294         // that these pending intents have in fact been registered.
295         Intent callBackIntent = new Intent(
296                 TelecomBroadcastIntentProcessor.ACTION_CALL_BACK_FROM_NOTIFICATION,
297                 TEL_CALL_HANDLE,
298                 mContext,
299                 TelecomBroadcastReceiver.class);
300         Intent smsIntent = new Intent(
301                 TelecomBroadcastIntentProcessor.ACTION_SEND_SMS_FROM_NOTIFICATION,
302                 Uri.fromParts(Constants.SCHEME_SMSTO, TEL_CALL_HANDLE.getSchemeSpecificPart(), null),
303                 mContext,
304                 TelecomBroadcastReceiver.class);
305 
306         assertNotNull(PendingIntent.getBroadcast(mContext, REQUEST_ID,
307                 callBackIntent, PendingIntent.FLAG_NO_CREATE));
308         assertNotNull(PendingIntent.getBroadcast(mContext, REQUEST_ID,
309                 smsIntent, PendingIntent.FLAG_NO_CREATE));
310     }
311 
312     @SmallTest
testNoSmsBackAfterMissedSipCall()313     public void testNoSmsBackAfterMissedSipCall() {
314         Notification.Builder builder1 = makeNotificationBuilder("builder1");
315         MissedCallNotifierImpl.NotificationBuilderFactory fakeBuilderFactory =
316                 makeNotificationBuilderFactory(builder1);
317 
318         MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
319                 mPhoneAccountRegistrar, new PhoneNumberUtilsAdapterImpl(), fakeBuilderFactory);
320         PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER, NO_CAPABILITY);
321 
322         Call fakeCall =
323                 makeFakeCall(SIP_CALL_HANDLE, CALLER_NAME, CALL_TIMESTAMP,
324                 phoneAccount.getAccountHandle());
325         missedCallNotifier.showMissedCallNotification(fakeCall);
326 
327         // Create two intents that correspond to call-back and respond back with SMS, and assert
328         // that in the case of a SIP call, no SMS intent is generated.
329         Intent callBackIntent = new Intent(
330                 TelecomBroadcastIntentProcessor.ACTION_CALL_BACK_FROM_NOTIFICATION,
331                 SIP_CALL_HANDLE,
332                 mContext,
333                 TelecomBroadcastReceiver.class);
334         Intent smsIntent = new Intent(
335                 TelecomBroadcastIntentProcessor.ACTION_SEND_SMS_FROM_NOTIFICATION,
336                 Uri.fromParts(Constants.SCHEME_SMSTO, SIP_CALL_HANDLE.getSchemeSpecificPart(),
337                         null),
338                 mContext,
339                 TelecomBroadcastReceiver.class);
340 
341         assertNotNull(PendingIntent.getBroadcast(mContext, REQUEST_ID,
342                 callBackIntent, PendingIntent.FLAG_NO_CREATE));
343         assertNull(PendingIntent.getBroadcast(mContext, REQUEST_ID,
344                 smsIntent, PendingIntent.FLAG_NO_CREATE));
345     }
346 
makeNotificationBuilder(String label)347     private Notification.Builder makeNotificationBuilder(String label) {
348         Notification.Builder builder = spy(new Notification.Builder(mContext));
349         Notification notification = mock(Notification.class);
350         when(notification.toString()).thenReturn(label);
351         when(builder.toString()).thenReturn(label);
352         doReturn(notification).when(builder).build();
353         return builder;
354     }
355 
makeFakeCall(Uri handle, String name, long timestamp, PhoneAccountHandle phoneAccountHandle)356     private Call makeFakeCall(Uri handle, String name, long timestamp,
357             PhoneAccountHandle phoneAccountHandle) {
358         Call fakeCall = mock(Call.class);
359         when(fakeCall.getHandle()).thenReturn(handle);
360         when(fakeCall.getName()).thenReturn(name);
361         when(fakeCall.getCreationTimeMillis()).thenReturn(timestamp);
362         when(fakeCall.getTargetPhoneAccount()).thenReturn(phoneAccountHandle);
363         return fakeCall;
364     }
365 
makeNotificationBuilderFactory( Notification.Builder... builders)366     private MissedCallNotifierImpl.NotificationBuilderFactory makeNotificationBuilderFactory(
367             Notification.Builder... builders) {
368         MissedCallNotifierImpl.NotificationBuilderFactory builderFactory =
369                 mock(MissedCallNotifierImpl.NotificationBuilderFactory.class);
370         when(builderFactory.getBuilder(mContext)).thenReturn(builders[0],
371                 Arrays.copyOfRange(builders, 1, builders.length));
372         return builderFactory;
373     }
374 
makeMissedCallNotifier( NotificationBuilderFactory fakeBuilderFactory, UserHandle currentUser)375     private MissedCallNotifier makeMissedCallNotifier(
376             NotificationBuilderFactory fakeBuilderFactory, UserHandle currentUser) {
377         MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext,
378                 mPhoneAccountRegistrar, new PhoneNumberUtilsAdapterImpl(), fakeBuilderFactory);
379         missedCallNotifier.setCurrentUserHandle(currentUser);
380         return missedCallNotifier;
381     }
382 
makePhoneAccount(UserHandle userHandle, int capability)383     private PhoneAccount makePhoneAccount(UserHandle userHandle, int capability) {
384         ComponentName componentName = new ComponentName("com.anything", "com.whatever");
385         PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle(componentName, "id",
386                 userHandle);
387         PhoneAccount.Builder builder = new PhoneAccount.Builder(phoneAccountHandle, "test");
388         builder.setCapabilities(capability);
389         PhoneAccount phoneAccount = builder.build();
390         when(mPhoneAccountRegistrar.getPhoneAccountUnchecked(phoneAccountHandle))
391                 .thenReturn(phoneAccount);
392         return phoneAccount;
393     }
394 }
395