MissedCallNotifierImplTest.java revision a33c44b34eaed1ec2dd5c87e00e2c0865971b7d1
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