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.server.telecom.tests; 18 19 import android.content.Context; 20 import android.graphics.Bitmap; 21 import android.graphics.drawable.BitmapDrawable; 22 import android.graphics.drawable.Drawable; 23 import android.net.Uri; 24 import android.support.test.InstrumentationRegistry; 25 import android.test.suitebuilder.annotation.SmallTest; 26 import android.telecom.Logging.Session; 27 28 import com.android.internal.telephony.CallerInfo; 29 import com.android.internal.telephony.CallerInfoAsyncQuery; 30 import com.android.server.telecom.CallerInfoAsyncQueryFactory; 31 import com.android.server.telecom.CallerInfoLookupHelper; 32 import com.android.server.telecom.ContactsAsyncHelper; 33 import com.android.server.telecom.TelecomSystem; 34 35 import org.junit.Before; 36 import org.junit.Test; 37 import org.junit.runner.RunWith; 38 import org.junit.runners.JUnit4; 39 import org.mockito.ArgumentCaptor; 40 import org.mockito.Mock; 41 42 import java.io.FileNotFoundException; 43 import java.io.InputStream; 44 import java.util.concurrent.CountDownLatch; 45 46 import static org.junit.Assert.assertEquals; 47 import static org.mockito.Matchers.any; 48 import static org.mockito.Matchers.anyInt; 49 import static org.mockito.Matchers.anyString; 50 import static org.mockito.Matchers.eq; 51 import static org.mockito.Matchers.isNull; 52 import static org.mockito.Mockito.mock; 53 import static org.mockito.Mockito.times; 54 import static org.mockito.Mockito.verify; 55 import static org.mockito.Mockito.when; 56 57 @RunWith(JUnit4.class) 58 public class CallerInfoLookupHelperTest extends TelecomTestCase { 59 @Mock Context mContext; 60 @Mock CallerInfoAsyncQueryFactory mFactory; 61 @Mock ContactsAsyncHelper mContactsAsyncHelper; 62 @Mock Drawable mDrawable2; 63 64 CallerInfo mCallerInfo1; 65 CallerInfo mCallerInfo2; 66 67 @Mock Drawable mDrawable1; 68 CallerInfoLookupHelper mCallerInfoLookupHelper; 69 static final Uri URI1 = Uri.parse("tel:555-555-7010"); 70 static final Uri URI2 = Uri.parse("tel:555-555-7016"); 71 72 static final Uri CONTACTS_PHOTO_URI = Uri.parse( 73 "android.resource://com.android.server.telecom.tests/" 74 + R.drawable.contacts_sample_photo_small); 75 76 Bitmap mBitmap; 77 78 @Override 79 @Before 80 public void setUp() throws Exception { 81 super.setUp(); 82 mCallerInfoLookupHelper = new CallerInfoLookupHelper(mContext, 83 mFactory, mContactsAsyncHelper, new TelecomSystem.SyncRoot() { }); 84 when(mFactory.startQuery(anyInt(), eq(mContext), anyString(), 85 any(CallerInfoAsyncQuery.OnQueryCompleteListener.class), any())) 86 .thenReturn(mock(CallerInfoAsyncQuery.class)); 87 mCallerInfo1 = new CallerInfo(); 88 mCallerInfo2 = new CallerInfo(); 89 90 if (mBitmap == null) { 91 InputStream is; 92 try { 93 is = InstrumentationRegistry.getContext() 94 .getContentResolver().openInputStream(CONTACTS_PHOTO_URI); 95 } catch (FileNotFoundException e) { 96 return; 97 } 98 99 Drawable d = Drawable.createFromStream(is, CONTACTS_PHOTO_URI.toString()); 100 mBitmap = ((BitmapDrawable) d).getBitmap(); 101 } 102 } 103 104 @SmallTest 105 @Test 106 public void testLookupWithEmptyHandle() { 107 CallerInfoLookupHelper.OnQueryCompleteListener listener = mock( 108 CallerInfoLookupHelper.OnQueryCompleteListener.class); 109 mCallerInfoLookupHelper.startLookup(Uri.EMPTY, listener); 110 111 verify(listener).onCallerInfoQueryComplete(eq(Uri.EMPTY), isNull(CallerInfo.class)); 112 verifyProperCleanup(); 113 } 114 115 @SmallTest 116 @Test 117 public void testSimpleLookup() { 118 CallerInfoLookupHelper.OnQueryCompleteListener listener = mock( 119 CallerInfoLookupHelper.OnQueryCompleteListener.class); 120 mCallerInfo1.contactDisplayPhotoUri = CONTACTS_PHOTO_URI; 121 122 mCallerInfoLookupHelper.startLookup(URI1, listener); 123 waitForActionCompletion(); 124 125 // CallerInfo section 126 ArgumentCaptor<CallerInfoAsyncQuery.OnQueryCompleteListener> queryListenerCaptor = 127 ArgumentCaptor.forClass(CallerInfoAsyncQuery.OnQueryCompleteListener.class); 128 ArgumentCaptor<Session> logSessionCaptor = ArgumentCaptor.forClass(Session.class); 129 verify(mFactory).startQuery(anyInt(), eq(mContext), eq(URI1.getSchemeSpecificPart()), 130 queryListenerCaptor.capture(), logSessionCaptor.capture()); 131 132 queryListenerCaptor.getValue().onQueryComplete( 133 0, logSessionCaptor.getValue(), mCallerInfo1); 134 verify(listener).onCallerInfoQueryComplete(URI1, mCallerInfo1); 135 waitForActionCompletion(); 136 137 // Contacts photo section 138 ArgumentCaptor<ContactsAsyncHelper.OnImageLoadCompleteListener> imageListenerCaptor = 139 ArgumentCaptor.forClass(ContactsAsyncHelper.OnImageLoadCompleteListener.class); 140 verify(mContactsAsyncHelper).startObtainPhotoAsync(anyInt(), eq(mContext), 141 eq(CONTACTS_PHOTO_URI), imageListenerCaptor.capture(), logSessionCaptor.capture()); 142 143 imageListenerCaptor.getValue().onImageLoadComplete(0, mDrawable1, mBitmap, 144 logSessionCaptor.getValue()); 145 verify(listener).onContactPhotoQueryComplete(URI1, mCallerInfo1); 146 assertEquals(mDrawable1, mCallerInfo1.cachedPhoto); 147 assertEquals(mBitmap, mCallerInfo1.cachedPhotoIcon); 148 149 verifyProperCleanup(); 150 } 151 152 @SmallTest 153 @Test 154 public void testLookupWithTwoListeners() { 155 CallerInfoLookupHelper.OnQueryCompleteListener callListener = mock( 156 CallerInfoLookupHelper.OnQueryCompleteListener.class); 157 CallerInfoLookupHelper.OnQueryCompleteListener otherListener = mock( 158 CallerInfoLookupHelper.OnQueryCompleteListener.class); 159 mCallerInfo1.contactDisplayPhotoUri = CONTACTS_PHOTO_URI; 160 161 mCallerInfoLookupHelper.startLookup(URI1, callListener); 162 mCallerInfoLookupHelper.startLookup(URI1, otherListener); 163 waitForActionCompletion(); 164 165 ArgumentCaptor<CallerInfoAsyncQuery.OnQueryCompleteListener> queryListenerCaptor = 166 ArgumentCaptor.forClass(CallerInfoAsyncQuery.OnQueryCompleteListener.class); 167 ArgumentCaptor<Session> logSessionCaptor = ArgumentCaptor.forClass(Session.class); 168 verify(mFactory, times(1)).startQuery(anyInt(), eq(mContext), 169 eq(URI1.getSchemeSpecificPart()), queryListenerCaptor.capture(), 170 logSessionCaptor.capture()); 171 172 queryListenerCaptor.getValue().onQueryComplete( 173 0, logSessionCaptor.getValue(), mCallerInfo1); 174 verify(callListener, times(1)).onCallerInfoQueryComplete(URI1, mCallerInfo1); 175 verify(otherListener, times(1)).onCallerInfoQueryComplete(URI1, mCallerInfo1); 176 waitForActionCompletion(); 177 178 ArgumentCaptor<ContactsAsyncHelper.OnImageLoadCompleteListener> imageListenerCaptor = 179 ArgumentCaptor.forClass(ContactsAsyncHelper.OnImageLoadCompleteListener.class); 180 verify(mContactsAsyncHelper).startObtainPhotoAsync(anyInt(), eq(mContext), 181 eq(CONTACTS_PHOTO_URI), imageListenerCaptor.capture(), logSessionCaptor.capture()); 182 183 imageListenerCaptor.getValue().onImageLoadComplete(0, mDrawable1, mBitmap, 184 logSessionCaptor.getValue()); 185 verify(callListener).onContactPhotoQueryComplete(URI1, mCallerInfo1); 186 verify(otherListener).onContactPhotoQueryComplete(URI1, mCallerInfo1); 187 assertEquals(mDrawable1, mCallerInfo1.cachedPhoto); 188 assertEquals(mBitmap, mCallerInfo1.cachedPhotoIcon); 189 190 verifyProperCleanup(); 191 } 192 193 @SmallTest 194 @Test 195 public void testListenerAddedAfterCallerInfoBeforePhoto() { 196 CallerInfoLookupHelper.OnQueryCompleteListener callListener = mock( 197 CallerInfoLookupHelper.OnQueryCompleteListener.class); 198 CallerInfoLookupHelper.OnQueryCompleteListener otherListener = mock( 199 CallerInfoLookupHelper.OnQueryCompleteListener.class); 200 mCallerInfo1.contactDisplayPhotoUri = CONTACTS_PHOTO_URI; 201 202 mCallerInfoLookupHelper.startLookup(URI1, callListener); 203 waitForActionCompletion(); 204 205 ArgumentCaptor<CallerInfoAsyncQuery.OnQueryCompleteListener> queryListenerCaptor = 206 ArgumentCaptor.forClass(CallerInfoAsyncQuery.OnQueryCompleteListener.class); 207 ArgumentCaptor<Session> logSessionCaptor = ArgumentCaptor.forClass(Session.class); 208 verify(mFactory, times(1)).startQuery(anyInt(), eq(mContext), 209 eq(URI1.getSchemeSpecificPart()), queryListenerCaptor.capture(), 210 logSessionCaptor.capture()); 211 212 queryListenerCaptor.getValue().onQueryComplete( 213 0, logSessionCaptor.getValue(), mCallerInfo1); 214 verify(callListener, times(1)).onCallerInfoQueryComplete(URI1, mCallerInfo1); 215 waitForActionCompletion(); 216 217 ArgumentCaptor<ContactsAsyncHelper.OnImageLoadCompleteListener> imageListenerCaptor = 218 ArgumentCaptor.forClass(ContactsAsyncHelper.OnImageLoadCompleteListener.class); 219 verify(mContactsAsyncHelper).startObtainPhotoAsync(anyInt(), eq(mContext), 220 eq(CONTACTS_PHOTO_URI), imageListenerCaptor.capture(), logSessionCaptor.capture()); 221 mCallerInfoLookupHelper.startLookup(URI1, otherListener); 222 verify(otherListener, times(1)).onCallerInfoQueryComplete(URI1, mCallerInfo1); 223 224 imageListenerCaptor.getValue().onImageLoadComplete(0, mDrawable1, mBitmap, 225 logSessionCaptor.getValue()); 226 verify(callListener).onContactPhotoQueryComplete(URI1, mCallerInfo1); 227 verify(otherListener).onContactPhotoQueryComplete(URI1, mCallerInfo1); 228 assertEquals(mDrawable1, mCallerInfo1.cachedPhoto); 229 assertEquals(mBitmap, mCallerInfo1.cachedPhotoIcon); 230 231 verifyProperCleanup(); 232 } 233 234 private void verifyProperCleanup() { 235 assertEquals(0, mCallerInfoLookupHelper.getCallerInfoEntries().size()); 236 } 237 238 private void waitForActionCompletion() { 239 final CountDownLatch lock = new CountDownLatch(1); 240 mCallerInfoLookupHelper.getHandler().post(lock::countDown); 241 while (lock.getCount() > 0) { 242 try { 243 lock.await(); 244 } catch (InterruptedException e) { 245 // do nothing 246 } 247 } 248 } 249 } 250