1 /* 2 * Copyright (C) 2016 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.incallui; 18 19 import static org.mockito.Matchers.anyInt; 20 import static org.mockito.Mockito.any; 21 import static org.mockito.Mockito.anyBoolean; 22 import static org.mockito.Mockito.doAnswer; 23 import static org.mockito.Mockito.eq; 24 import static org.mockito.Mockito.timeout; 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.when; 27 28 import com.android.contacts.common.preference.ContactsPreferences; 29 30 import org.mockito.ArgumentCaptor; 31 import org.mockito.Mock; 32 import org.mockito.MockitoAnnotations; 33 import org.mockito.Spy; 34 import org.mockito.invocation.InvocationOnMock; 35 import org.mockito.stubbing.Answer; 36 37 import android.app.Notification; 38 import android.app.NotificationManager; 39 import android.content.ComponentName; 40 import android.content.Context; 41 import android.content.res.Resources; 42 import android.net.Uri; 43 import android.telecom.*; 44 import android.telecom.Call; 45 import android.telephony.TelephonyManager; 46 import android.test.AndroidTestCase; 47 import android.test.mock.MockContext; 48 49 /** 50 * Unit tests for {@link ExternalCallNotifier}. 51 */ 52 public class ExternalCallNotifierTest extends AndroidTestCase { 53 private static final int TIMEOUT_MILLIS = 5000; 54 private static final String NAME_PRIMARY = "Full Name"; 55 private static final String NAME_ALTERNATIVE = "Name, Full"; 56 private static final String LOCATION = "US"; 57 private static final String NUMBER = "6505551212"; 58 59 @Mock private ContactsPreferences mContactsPreferences; 60 @Mock private NotificationManager mNotificationManager; 61 @Mock private MockContext mMockContext; 62 @Mock private Resources mResources; 63 @Mock private StatusBarNotifier mStatusBarNotifier; 64 @Mock private ContactInfoCache mContactInfoCache; 65 @Mock private TelecomManager mTelecomManager; 66 @Mock private TelephonyManager mTelephonyManager; 67 @Mock private ProximitySensor mProximitySensor; 68 @Mock private CallList mCallList; 69 private InCallPresenter mInCallPresenter; 70 private ExternalCallNotifier mExternalCallNotifier; 71 private ContactInfoCache.ContactCacheEntry mContactInfo; 72 73 @Override 74 public void setUp() throws Exception { 75 super.setUp(); 76 MockitoAnnotations.initMocks(this); 77 78 when(mContactsPreferences.getDisplayOrder()) 79 .thenReturn(ContactsPreferences.DISPLAY_ORDER_PRIMARY); 80 81 // Setup the mock context to return mocks for some of the needed services; the notification 82 // service is especially important as we want to be able to intercept calls into it and 83 // validate the notifcations. 84 when(mMockContext.getSystemService(eq(Context.NOTIFICATION_SERVICE))) 85 .thenReturn(mNotificationManager); 86 when(mMockContext.getSystemService(eq(Context.TELECOM_SERVICE))) 87 .thenReturn(mTelecomManager); 88 when(mMockContext.getSystemService(eq(Context.TELEPHONY_SERVICE))) 89 .thenReturn(mTelephonyManager); 90 91 // These aspects of the context are used by the notification builder to build the actual 92 // notification; we will rely on the actual implementations of these. 93 when(mMockContext.getPackageManager()).thenReturn(mContext.getPackageManager()); 94 when(mMockContext.getResources()).thenReturn(mContext.getResources()); 95 when(mMockContext.getApplicationInfo()).thenReturn(mContext.getApplicationInfo()); 96 when(mMockContext.getContentResolver()).thenReturn(mContext.getContentResolver()); 97 when(mMockContext.getPackageName()).thenReturn(mContext.getPackageName()); 98 99 ContactsPreferencesFactory.setTestInstance(null); 100 mExternalCallNotifier = new ExternalCallNotifier(mMockContext, mContactInfoCache); 101 102 // We don't directly use the InCallPresenter in the test, or even in ExternalCallNotifier 103 // itself. However, ExternalCallNotifier needs to make instances of 104 // com.android.incallui.Call for the purpose of performing contact cache lookups. The 105 // Call class depends on the static InCallPresenter for a number of things, so we need to 106 // set it up here to prevent crashes. 107 mInCallPresenter = InCallPresenter.getInstance(); 108 mInCallPresenter.setUp(mMockContext, mCallList, new ExternalCallList(), 109 null, mStatusBarNotifier, mExternalCallNotifier, mContactInfoCache, 110 mProximitySensor); 111 112 // Unlocked all contact info is available 113 mContactInfo = new ContactInfoCache.ContactCacheEntry(); 114 mContactInfo.namePrimary = NAME_PRIMARY; 115 mContactInfo.nameAlternative = NAME_ALTERNATIVE; 116 mContactInfo.location = LOCATION; 117 mContactInfo.number = NUMBER; 118 119 // Given the mock ContactInfoCache cache, we need to mock out what happens when the 120 // ExternalCallNotifier calls into the contact info cache to do a lookup. We will always 121 // return mock info stored in mContactInfo. 122 doAnswer(new Answer() { 123 @Override 124 public Object answer(InvocationOnMock invocation) throws Throwable { 125 Object[] args = invocation.getArguments(); 126 com.android.incallui.Call call = (com.android.incallui.Call) args[0]; 127 ContactInfoCache.ContactInfoCacheCallback callback 128 = (ContactInfoCache.ContactInfoCacheCallback) args[2]; 129 callback.onContactInfoComplete(call.getId(), mContactInfo); 130 return null; 131 } 132 }).when(mContactInfoCache).findInfo(any(com.android.incallui.Call.class), anyBoolean(), 133 any(ContactInfoCache.ContactInfoCacheCallback.class)); 134 } 135 136 @Override 137 public void tearDown() throws Exception { 138 super.tearDown(); 139 ContactsPreferencesFactory.setTestInstance(null); 140 mInCallPresenter.tearDown(); 141 } 142 143 public void testPostNonPullable() { 144 TestTelecomCall call = getTestCall(false); 145 mExternalCallNotifier.onExternalCallAdded(call.getCall()); 146 Notification notification = verifyNotificationPosted(); 147 assertNull(notification.actions); 148 } 149 150 public void testPostPullable() { 151 TestTelecomCall call = getTestCall(true); 152 mExternalCallNotifier.onExternalCallAdded(call.getCall()); 153 Notification notification = verifyNotificationPosted(); 154 assertEquals(1, notification.actions.length); 155 } 156 157 public void testNotificationDismissed() { 158 TestTelecomCall call = getTestCall(false); 159 mExternalCallNotifier.onExternalCallAdded(call.getCall()); 160 verifyNotificationPosted(); 161 162 mExternalCallNotifier.onExternalCallRemoved(call.getCall()); 163 verify(mNotificationManager, timeout(TIMEOUT_MILLIS)).cancel(eq("EXTERNAL_CALL"), eq(0)); 164 } 165 166 public void testNotificationUpdated() { 167 TestTelecomCall call = getTestCall(false); 168 mExternalCallNotifier.onExternalCallAdded(call.getCall()); 169 verifyNotificationPosted(); 170 171 call.setCapabilities(android.telecom.Call.Details.CAPABILITY_CAN_PULL_CALL); 172 mExternalCallNotifier.onExternalCallUpdated(call.getCall()); 173 174 ArgumentCaptor<Notification> notificationCaptor = 175 ArgumentCaptor.forClass(Notification.class); 176 verify(mNotificationManager, timeout(TIMEOUT_MILLIS).times(2)) 177 .notify(eq("EXTERNAL_CALL"), eq(0), notificationCaptor.capture()); 178 Notification notification1 = notificationCaptor.getAllValues().get(0); 179 assertNull(notification1.actions); 180 Notification notification2 = notificationCaptor.getAllValues().get(1); 181 assertEquals(1, notification2.actions.length); 182 } 183 184 private Notification verifyNotificationPosted() { 185 ArgumentCaptor<Notification> notificationCaptor = 186 ArgumentCaptor.forClass(Notification.class); 187 verify(mNotificationManager, timeout(TIMEOUT_MILLIS)) 188 .notify(eq("EXTERNAL_CALL"), eq(0), notificationCaptor.capture()); 189 return notificationCaptor.getValue(); 190 } 191 192 private TestTelecomCall getTestCall(boolean canPull) { 193 TestTelecomCall testCall = TestTelecomCall.createInstance( 194 "1", 195 Uri.parse("tel:650-555-1212"), /* handle */ 196 TelecomManager.PRESENTATION_ALLOWED, /* handlePresentation */ 197 "Joe", /* callerDisplayName */ 198 TelecomManager.PRESENTATION_ALLOWED, /* callerDisplayNamePresentation */ 199 new PhoneAccountHandle(new ComponentName("test", "class"), 200 "handle"), /* accountHandle */ 201 canPull ? android.telecom.Call.Details.CAPABILITY_CAN_PULL_CALL : 0, /* capabilities */ 202 Call.Details.PROPERTY_IS_EXTERNAL_CALL, /* properties */ 203 null, /* disconnectCause */ 204 0, /* connectTimeMillis */ 205 null, /* GatewayInfo */ 206 VideoProfile.STATE_AUDIO_ONLY, /* videoState */ 207 null, /* statusHints */ 208 null, /* extras */ 209 null /* intentExtras */); 210 return testCall; 211 } 212 } 213