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