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