MissedCallNotifierImplTest.java revision 2c93c50e5be7d85b78c4af15aaa10e44f0bcdf3e
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.Context; 23import android.content.Intent; 24import android.content.pm.ApplicationInfo; 25import android.net.Uri; 26import android.os.UserHandle; 27import android.telephony.TelephonyManager; 28 29import com.android.server.telecom.Call; 30import com.android.server.telecom.Constants; 31import com.android.server.telecom.MissedCallNotifier; 32import com.android.server.telecom.TelecomBroadcastIntentProcessor; 33import com.android.server.telecom.components.TelecomBroadcastReceiver; 34import com.android.server.telecom.ui.MissedCallNotifierImpl; 35 36import org.mockito.ArgumentCaptor; 37import org.mockito.Mock; 38import org.mockito.MockitoAnnotations; 39 40import java.util.Arrays; 41import java.util.HashSet; 42 43import static org.mockito.Matchers.any; 44import static org.mockito.Matchers.eq; 45import static org.mockito.Matchers.isNull; 46import static org.mockito.Mockito.doReturn; 47import static org.mockito.Mockito.mock; 48import static org.mockito.Mockito.never; 49import static org.mockito.Mockito.spy; 50import static org.mockito.Mockito.times; 51import static org.mockito.Mockito.verify; 52import static org.mockito.Mockito.when; 53 54public class MissedCallNotifierImplTest extends TelecomTestCase { 55 56 private static final Uri TEL_CALL_HANDLE = Uri.parse("tel:+11915552620"); 57 private static final Uri SIP_CALL_HANDLE = Uri.parse("sip:testaddress@testdomain.com"); 58 private static final String CALLER_NAME = "Fake Name"; 59 private static final String MISSED_CALL_TITLE = "Missed Call"; 60 private static final String MISSED_CALLS_TITLE = "Missed Calls"; 61 private static final String MISSED_CALLS_MSG = "%s missed calls"; 62 private static final String USER_CALL_ACTIVITY_LABEL = "Phone"; 63 64 private static final int REQUEST_ID = 0; 65 private static final long CALL_TIMESTAMP; 66 static { 67 CALL_TIMESTAMP = System.currentTimeMillis() - 60 * 1000 * 5; 68 } 69 70 @Mock 71 private NotificationManager mNotificationManager; 72 73 @Override 74 public void setUp() throws Exception { 75 super.setUp(); 76 MockitoAnnotations.initMocks(this); 77 78 mContext = mComponentContextFixture.getTestDouble().getApplicationContext(); 79 mNotificationManager = (NotificationManager) mContext.getSystemService( 80 Context.NOTIFICATION_SERVICE); 81 TelephonyManager fakeTelephonyManager = (TelephonyManager) mContext.getSystemService( 82 Context.TELEPHONY_SERVICE); 83 when(fakeTelephonyManager.getNetworkCountryIso()).thenReturn("US"); 84 doReturn(new ApplicationInfo()).when(mContext).getApplicationInfo(); 85 doReturn("com.android.server.telecom.tests").when(mContext).getPackageName(); 86 87 mComponentContextFixture.putResource(R.string.notification_missedCallTitle, 88 MISSED_CALL_TITLE); 89 mComponentContextFixture.putResource(R.string.notification_missedCallsTitle, 90 MISSED_CALLS_TITLE); 91 mComponentContextFixture.putResource(R.string.notification_missedCallsMsg, 92 MISSED_CALLS_MSG); 93 mComponentContextFixture.putResource(R.string.userCallActivityLabel, 94 USER_CALL_ACTIVITY_LABEL); 95 } 96 97 public void testCancelNotification() { 98 Notification.Builder builder1 = makeNotificationBuilder("builder1"); 99 Notification.Builder builder2 = makeNotificationBuilder("builder2"); 100 MissedCallNotifierImpl.NotificationBuilderFactory fakeBuilderFactory = 101 makeNotificationBuilderFactory(builder1, builder1, builder2, builder2); 102 103 MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext, 104 fakeBuilderFactory); 105 106 Call fakeCall = makeFakeCall(TEL_CALL_HANDLE, CALLER_NAME, CALL_TIMESTAMP); 107 108 missedCallNotifier.showMissedCallNotification(fakeCall); 109 missedCallNotifier.clearMissedCalls(); 110 missedCallNotifier.showMissedCallNotification(fakeCall); 111 112 ArgumentCaptor<Integer> requestIdCaptor = ArgumentCaptor.forClass( 113 Integer.class); 114 verify(mNotificationManager, times(2)).notifyAsUser(isNull(String.class), 115 requestIdCaptor.capture(), any(Notification.class), eq(UserHandle.CURRENT)); 116 verify(mNotificationManager).cancelAsUser(any(String.class), eq(requestIdCaptor.getValue()), 117 eq(UserHandle.CURRENT)); 118 119 // Verify that the second call to showMissedCallNotification behaves like it were the first. 120 verify(builder2).setContentText(CALLER_NAME); 121 } 122 123 public void testNotifyMultipleMissedCalls() { 124 Notification.Builder[] builders = new Notification.Builder[4]; 125 126 for (int i = 0; i < 4; i++) { 127 builders[i] = makeNotificationBuilder("builder" + Integer.toString(i)); 128 } 129 130 Call fakeCall = makeFakeCall(TEL_CALL_HANDLE, CALLER_NAME, CALL_TIMESTAMP); 131 132 MissedCallNotifierImpl.NotificationBuilderFactory fakeBuilderFactory = 133 makeNotificationBuilderFactory(builders); 134 135 MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext, 136 fakeBuilderFactory); 137 138 missedCallNotifier.showMissedCallNotification(fakeCall); 139 missedCallNotifier.showMissedCallNotification(fakeCall); 140 141 // The following captor is to capture the two notifications that got passed into 142 // notifyAsUser. This distinguishes between the builders used for the full notification 143 // (i.e. the one potentially containing sensitive information, such as phone numbers), 144 // and the builders used for the notifications shown on the lockscreen, which have been 145 // scrubbed of such sensitive info. The notifications which are used as arguments 146 // to notifyAsUser are the versions which contain sensitive information. 147 ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass( 148 Notification.class); 149 verify(mNotificationManager, times(2)).notifyAsUser(isNull(String.class), eq(1), 150 notificationArgumentCaptor.capture(), eq(UserHandle.CURRENT)); 151 HashSet<String> privateNotifications = new HashSet<>(); 152 for (Notification n : notificationArgumentCaptor.getAllValues()) { 153 privateNotifications.add(n.toString()); 154 } 155 156 for (int i = 0; i < 4; i++) { 157 Notification.Builder builder = builders[i]; 158 verify(builder).setWhen(CALL_TIMESTAMP); 159 if (i >= 2) { 160 // The builders after the first two are for multiple missed calls. The notification 161 // for subsequent missed calls is expected to be different in terms of the text 162 // contents of the notification, and that is verified here. 163 if (privateNotifications.contains(builder.toString())) { 164 verify(builder).setContentText(String.format(MISSED_CALLS_MSG, 2)); 165 verify(builder).setContentTitle(MISSED_CALLS_TITLE); 166 } else { 167 verify(builder).setContentText(MISSED_CALLS_TITLE); 168 verify(builder).setContentTitle(USER_CALL_ACTIVITY_LABEL); 169 } 170 verify(builder, never()).addAction(any(Notification.Action.class)); 171 } else { 172 if (privateNotifications.contains(builder.toString())) { 173 verify(builder).setContentText(CALLER_NAME); 174 verify(builder).setContentTitle(MISSED_CALL_TITLE); 175 } else { 176 verify(builder).setContentText(MISSED_CALL_TITLE); 177 verify(builder).setContentTitle(USER_CALL_ACTIVITY_LABEL); 178 } 179 } 180 } 181 } 182 183 public void testNotifySingleCall() { 184 Notification.Builder builder1 = makeNotificationBuilder("builder1"); 185 Notification.Builder builder2 = makeNotificationBuilder("builder2"); 186 MissedCallNotifierImpl.NotificationBuilderFactory fakeBuilderFactory = 187 makeNotificationBuilderFactory(builder1, builder2); 188 189 MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext, 190 fakeBuilderFactory); 191 192 Call fakeCall = makeFakeCall(TEL_CALL_HANDLE, CALLER_NAME, CALL_TIMESTAMP); 193 missedCallNotifier.showMissedCallNotification(fakeCall); 194 195 ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass( 196 Notification.class); 197 verify(mNotificationManager).notifyAsUser(isNull(String.class), eq(1), 198 notificationArgumentCaptor.capture(), eq(UserHandle.CURRENT)); 199 200 Notification.Builder builder; 201 Notification.Builder publicBuilder; 202 203 if (notificationArgumentCaptor.getValue().toString().equals("builder1")) { 204 builder = builder1; 205 publicBuilder = builder2; 206 } else { 207 builder = builder2; 208 publicBuilder = builder1; 209 } 210 211 verify(builder).setWhen(CALL_TIMESTAMP); 212 verify(publicBuilder).setWhen(CALL_TIMESTAMP); 213 214 verify(builder).setContentText(CALLER_NAME); 215 verify(publicBuilder).setContentText(MISSED_CALL_TITLE); 216 217 verify(builder).setContentTitle(MISSED_CALL_TITLE); 218 verify(publicBuilder).setContentTitle(USER_CALL_ACTIVITY_LABEL); 219 220 // Create two intents that correspond to call-back and respond back with SMS, and assert 221 // that these pending intents have in fact been registered. 222 Intent callBackIntent = new Intent( 223 TelecomBroadcastIntentProcessor.ACTION_CALL_BACK_FROM_NOTIFICATION, 224 TEL_CALL_HANDLE, 225 mContext, 226 TelecomBroadcastReceiver.class); 227 Intent smsIntent = new Intent( 228 TelecomBroadcastIntentProcessor.ACTION_SEND_SMS_FROM_NOTIFICATION, 229 Uri.fromParts(Constants.SCHEME_SMSTO, TEL_CALL_HANDLE.getSchemeSpecificPart(), null), 230 mContext, 231 TelecomBroadcastReceiver.class); 232 233 assertNotNull(PendingIntent.getBroadcast(mContext, REQUEST_ID, 234 callBackIntent, PendingIntent.FLAG_NO_CREATE)); 235 assertNotNull(PendingIntent.getBroadcast(mContext, REQUEST_ID, 236 smsIntent, PendingIntent.FLAG_NO_CREATE)); 237 } 238 239 public void testNoSmsBackAfterMissedSipCall() { 240 Notification.Builder builder1 = makeNotificationBuilder("builder1"); 241 MissedCallNotifierImpl.NotificationBuilderFactory fakeBuilderFactory = 242 makeNotificationBuilderFactory(builder1); 243 244 MissedCallNotifier missedCallNotifier = new MissedCallNotifierImpl(mContext, 245 fakeBuilderFactory); 246 247 Call fakeCall = makeFakeCall(SIP_CALL_HANDLE, CALLER_NAME, CALL_TIMESTAMP); 248 missedCallNotifier.showMissedCallNotification(fakeCall); 249 250 // Create two intents that correspond to call-back and respond back with SMS, and assert 251 // that in the case of a SIP call, no SMS intent is generated. 252 Intent callBackIntent = new Intent( 253 TelecomBroadcastIntentProcessor.ACTION_CALL_BACK_FROM_NOTIFICATION, 254 SIP_CALL_HANDLE, 255 mContext, 256 TelecomBroadcastReceiver.class); 257 Intent smsIntent = new Intent( 258 TelecomBroadcastIntentProcessor.ACTION_SEND_SMS_FROM_NOTIFICATION, 259 Uri.fromParts(Constants.SCHEME_SMSTO, SIP_CALL_HANDLE.getSchemeSpecificPart(), 260 null), 261 mContext, 262 TelecomBroadcastReceiver.class); 263 264 assertNotNull(PendingIntent.getBroadcast(mContext, REQUEST_ID, 265 callBackIntent, PendingIntent.FLAG_NO_CREATE)); 266 assertNull(PendingIntent.getBroadcast(mContext, REQUEST_ID, 267 smsIntent, PendingIntent.FLAG_NO_CREATE)); 268 } 269 270 private Notification.Builder makeNotificationBuilder(String label) { 271 Notification.Builder builder = spy(new Notification.Builder(mContext)); 272 Notification notification = mock(Notification.class); 273 when(notification.toString()).thenReturn(label); 274 when(builder.toString()).thenReturn(label); 275 doReturn(notification).when(builder).build(); 276 return builder; 277 } 278 279 private Call makeFakeCall(Uri handle, String name, long timestamp) { 280 Call fakeCall = mock(Call.class); 281 when(fakeCall.getHandle()).thenReturn(handle); 282 when(fakeCall.getName()).thenReturn(name); 283 when(fakeCall.getCreationTimeMillis()).thenReturn(timestamp); 284 return fakeCall; 285 } 286 287 private MissedCallNotifierImpl.NotificationBuilderFactory makeNotificationBuilderFactory( 288 Notification.Builder... builders) { 289 MissedCallNotifierImpl.NotificationBuilderFactory builderFactory = 290 mock(MissedCallNotifierImpl.NotificationBuilderFactory.class); 291 when(builderFactory.getBuilder(mContext)).thenReturn(builders[0], 292 Arrays.copyOfRange(builders, 1, builders.length)); 293 return builderFactory; 294 } 295} 296