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