• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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.contacts;
18 
19 import static com.android.contacts.CallDetailActivity.Tasks.UPDATE_PHONE_CALL_DETAILS;
20 import static com.android.contacts.voicemail.VoicemailPlaybackPresenter.Tasks.CHECK_FOR_CONTENT;
21 import static com.android.contacts.voicemail.VoicemailPlaybackPresenter.Tasks.PREPARE_MEDIA_PLAYER;
22 
23 import com.android.contacts.util.AsyncTaskExecutors;
24 import com.android.contacts.util.FakeAsyncTaskExecutor;
25 import com.android.contacts.util.IntegrationTestUtils;
26 import com.android.contacts.util.LocaleTestUtils;
27 import com.android.internal.view.menu.ContextMenuBuilder;
28 import com.google.common.base.Preconditions;
29 import com.google.common.io.Closeables;
30 
31 import android.content.ContentResolver;
32 import android.content.ContentUris;
33 import android.content.ContentValues;
34 import android.content.Intent;
35 import android.content.res.AssetManager;
36 import android.net.Uri;
37 import android.provider.CallLog;
38 import android.provider.VoicemailContract;
39 import android.test.ActivityInstrumentationTestCase2;
40 import android.test.suitebuilder.annotation.LargeTest;
41 import android.test.suitebuilder.annotation.Suppress;
42 import android.view.Menu;
43 import android.widget.TextView;
44 
45 import java.io.IOException;
46 import java.io.InputStream;
47 import java.io.OutputStream;
48 import java.util.List;
49 import java.util.Locale;
50 
51 /**
52  * Unit tests for the {@link CallDetailActivity}.
53  */
54 @LargeTest
55 public class CallDetailActivityTest extends ActivityInstrumentationTestCase2<CallDetailActivity> {
56     private static final String TEST_ASSET_NAME = "quick_test_recording.mp3";
57     private static final String MIME_TYPE = "audio/mp3";
58     private static final String CONTACT_NUMBER = "+1412555555";
59     private static final String VOICEMAIL_FILE_LOCATION = "/sdcard/sadlfj893w4j23o9sfu.mp3";
60 
61     private Uri mCallLogUri;
62     private Uri mVoicemailUri;
63     private IntegrationTestUtils mTestUtils;
64     private LocaleTestUtils mLocaleTestUtils;
65     private FakeAsyncTaskExecutor mFakeAsyncTaskExecutor;
66     private CallDetailActivity mActivityUnderTest;
67 
CallDetailActivityTest()68     public CallDetailActivityTest() {
69         super(CallDetailActivity.class);
70     }
71 
72     @Override
setUp()73     protected void setUp() throws Exception {
74         super.setUp();
75         mFakeAsyncTaskExecutor = new FakeAsyncTaskExecutor(getInstrumentation());
76         AsyncTaskExecutors.setFactoryForTest(mFakeAsyncTaskExecutor.getFactory());
77         // I don't like the default of focus-mode for tests, the green focus border makes the
78         // screenshots look weak.
79         setActivityInitialTouchMode(true);
80         mTestUtils = new IntegrationTestUtils(getInstrumentation());
81         // Some of the tests rely on the text that appears on screen - safest to force a
82         // specific locale.
83         mLocaleTestUtils = new LocaleTestUtils(getInstrumentation().getTargetContext());
84         mLocaleTestUtils.setLocale(Locale.US);
85     }
86 
87     @Override
tearDown()88     protected void tearDown() throws Exception {
89         mLocaleTestUtils.restoreLocale();
90         mLocaleTestUtils = null;
91         cleanUpUri();
92         mTestUtils = null;
93         AsyncTaskExecutors.setFactoryForTest(null);
94         super.tearDown();
95     }
96 
testInitialActivityStartsWithFetchingVoicemail()97     public void testInitialActivityStartsWithFetchingVoicemail() throws Throwable {
98         setActivityIntentForTestVoicemailEntry();
99         startActivityUnderTest();
100         // When the activity first starts, we will show "Fetching voicemail" on the screen.
101         // The duration should not be visible.
102         assertHasOneTextViewContaining("Fetching voicemail");
103         assertZeroTextViewsContaining("00:00");
104     }
105 
testWhenCheckForContentCompletes_UiShowsBuffering()106     public void testWhenCheckForContentCompletes_UiShowsBuffering() throws Throwable {
107         setActivityIntentForTestVoicemailEntry();
108         startActivityUnderTest();
109         // There is a background check that is testing to see if we have the content available.
110         // Once that task completes, we shouldn't be showing the fetching message, we should
111         // be showing "Buffering".
112         mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
113         assertHasOneTextViewContaining("Buffering");
114         assertZeroTextViewsContaining("Fetching voicemail");
115     }
116 
testInvalidVoicemailShowsErrorMessage()117     public void testInvalidVoicemailShowsErrorMessage() throws Throwable {
118         setActivityIntentForTestVoicemailEntry();
119         startActivityUnderTest();
120         mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
121         // There should be exactly one background task ready to prepare the media player.
122         // Preparing the media player will have thrown an IOException since the file doesn't exist.
123         // This should have put a failed to play message on screen, buffering is gone.
124         mFakeAsyncTaskExecutor.runTask(PREPARE_MEDIA_PLAYER);
125         assertHasOneTextViewContaining("Couldn't play voicemail");
126         assertZeroTextViewsContaining("Buffering");
127     }
128 
testOnResumeDoesNotCreateManyFragments()129     public void testOnResumeDoesNotCreateManyFragments() throws Throwable {
130         // There was a bug where every time the activity was resumed, a new fragment was created.
131         // Before the fix, this was failing reproducibly with at least 3 "Buffering" views.
132         setActivityIntentForTestVoicemailEntry();
133         startActivityUnderTest();
134         mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
135         getInstrumentation().runOnMainSync(new Runnable() {
136             @Override
137             public void run() {
138                 getInstrumentation().callActivityOnPause(mActivityUnderTest);
139                 getInstrumentation().callActivityOnResume(mActivityUnderTest);
140                 getInstrumentation().callActivityOnPause(mActivityUnderTest);
141                 getInstrumentation().callActivityOnResume(mActivityUnderTest);
142             }
143         });
144         assertHasOneTextViewContaining("Buffering");
145     }
146 
147     /**
148      * Test for bug where increase rate button with invalid voicemail causes a crash.
149      * <p>
150      * The repro steps for this crash were to open a voicemail that does not have an attachment,
151      * then click the play button (which just reported an error), then after that try to adjust the
152      * rate.  See http://b/5047879.
153      */
testClickIncreaseRateButtonWithInvalidVoicemailDoesNotCrash()154     public void testClickIncreaseRateButtonWithInvalidVoicemailDoesNotCrash() throws Throwable {
155         setActivityIntentForTestVoicemailEntry();
156         startActivityUnderTest();
157         mTestUtils.clickButton(mActivityUnderTest, R.id.playback_start_stop);
158         mTestUtils.clickButton(mActivityUnderTest, R.id.rate_increase_button);
159     }
160 
161     /** Test for bug where missing Extras on intent used to start Activity causes NPE. */
testCallLogUriWithMissingExtrasShouldNotCauseNPE()162     public void testCallLogUriWithMissingExtrasShouldNotCauseNPE() throws Throwable {
163         setActivityIntentForTestCallEntry();
164         startActivityUnderTest();
165     }
166 
167     /**
168      * Test for bug where voicemails should not have remove-from-call-log entry.
169      * <p>
170      * See http://b/5054103.
171      */
testVoicemailDoesNotHaveRemoveFromCallLog()172     public void testVoicemailDoesNotHaveRemoveFromCallLog() throws Throwable {
173         setActivityIntentForTestVoicemailEntry();
174         startActivityUnderTest();
175         Menu menu = new ContextMenuBuilder(mActivityUnderTest);
176         mActivityUnderTest.onCreateOptionsMenu(menu);
177         mActivityUnderTest.onPrepareOptionsMenu(menu);
178         assertFalse(menu.findItem(R.id.menu_remove_from_call_log).isVisible());
179     }
180 
181     /** Test to check that I haven't broken the remove-from-call-log entry from regular calls. */
testRegularCallDoesHaveRemoveFromCallLog()182     public void testRegularCallDoesHaveRemoveFromCallLog() throws Throwable {
183         setActivityIntentForTestCallEntry();
184         startActivityUnderTest();
185         Menu menu = new ContextMenuBuilder(mActivityUnderTest);
186         mActivityUnderTest.onCreateOptionsMenu(menu);
187         mActivityUnderTest.onPrepareOptionsMenu(menu);
188         assertTrue(menu.findItem(R.id.menu_remove_from_call_log).isVisible());
189     }
190 
191     /**
192      * Test to show that we are correctly displaying playback rate on the ui.
193      * <p>
194      * See bug http://b/5044075.
195      */
196     @Suppress
testVoicemailPlaybackRateDisplayedOnUi()197     public void testVoicemailPlaybackRateDisplayedOnUi() throws Throwable {
198         setActivityIntentForTestVoicemailEntry();
199         startActivityUnderTest();
200         // Find the TextView containing the duration.  It should be initially displaying "00:00".
201         List<TextView> views = mTestUtils.getTextViewsWithString(mActivityUnderTest, "00:00");
202         assertEquals(1, views.size());
203         TextView timeDisplay = views.get(0);
204         // Hit the plus button.  At this point we should be displaying "fast speed".
205         mTestUtils.clickButton(mActivityUnderTest, R.id.rate_increase_button);
206         assertEquals("fast speed", mTestUtils.getText(timeDisplay));
207         // Hit the minus button.  We should be back to "normal" speed.
208         mTestUtils.clickButton(mActivityUnderTest, R.id.rate_decrease_button);
209         assertEquals("normal speed", mTestUtils.getText(timeDisplay));
210         // Wait for one and a half seconds.  The timer will be back.
211         Thread.sleep(1500);
212         assertEquals("00:00", mTestUtils.getText(timeDisplay));
213     }
214 
215     @Suppress
testClickingCallStopsPlayback()216     public void testClickingCallStopsPlayback() throws Throwable {
217         setActivityIntentForRealFileVoicemailEntry();
218         startActivityUnderTest();
219         mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
220         mFakeAsyncTaskExecutor.runTask(PREPARE_MEDIA_PLAYER);
221         mTestUtils.clickButton(mActivityUnderTest, R.id.playback_speakerphone);
222         mTestUtils.clickButton(mActivityUnderTest, R.id.playback_start_stop);
223         mTestUtils.clickButton(mActivityUnderTest, R.id.call_and_sms_main_action);
224         Thread.sleep(2000);
225         // TODO: Suppressed the test for now, because I'm looking for an easy way to say "the audio
226         // is not playing at this point", and I can't find it without doing dirty things.
227     }
228 
setActivityIntentForTestCallEntry()229     private void setActivityIntentForTestCallEntry() {
230         Preconditions.checkState(mCallLogUri == null, "mUri should be null");
231         ContentResolver contentResolver = getContentResolver();
232         ContentValues values = new ContentValues();
233         values.put(CallLog.Calls.NUMBER, CONTACT_NUMBER);
234         values.put(CallLog.Calls.TYPE, CallLog.Calls.INCOMING_TYPE);
235         mCallLogUri = contentResolver.insert(CallLog.Calls.CONTENT_URI, values);
236         setActivityIntent(new Intent(Intent.ACTION_VIEW, mCallLogUri));
237     }
238 
setActivityIntentForTestVoicemailEntry()239     private void setActivityIntentForTestVoicemailEntry() {
240         Preconditions.checkState(mVoicemailUri == null, "mUri should be null");
241         ContentResolver contentResolver = getContentResolver();
242         ContentValues values = new ContentValues();
243         values.put(VoicemailContract.Voicemails.NUMBER, CONTACT_NUMBER);
244         values.put(VoicemailContract.Voicemails.HAS_CONTENT, 1);
245         values.put(VoicemailContract.Voicemails._DATA, VOICEMAIL_FILE_LOCATION);
246         mVoicemailUri = contentResolver.insert(VoicemailContract.Voicemails.CONTENT_URI, values);
247         Uri callLogUri = ContentUris.withAppendedId(CallLog.Calls.CONTENT_URI_WITH_VOICEMAIL,
248                 ContentUris.parseId(mVoicemailUri));
249         Intent intent = new Intent(Intent.ACTION_VIEW, callLogUri);
250         intent.putExtra(CallDetailActivity.EXTRA_VOICEMAIL_URI, mVoicemailUri);
251         setActivityIntent(intent);
252     }
253 
setActivityIntentForRealFileVoicemailEntry()254     private void setActivityIntentForRealFileVoicemailEntry() throws IOException {
255         Preconditions.checkState(mVoicemailUri == null, "mUri should be null");
256         ContentValues values = new ContentValues();
257         values.put(VoicemailContract.Voicemails.DATE, String.valueOf(System.currentTimeMillis()));
258         values.put(VoicemailContract.Voicemails.NUMBER, CONTACT_NUMBER);
259         values.put(VoicemailContract.Voicemails.MIME_TYPE, MIME_TYPE);
260         values.put(VoicemailContract.Voicemails.HAS_CONTENT, 1);
261         String packageName = getInstrumentation().getTargetContext().getPackageName();
262         mVoicemailUri = getContentResolver().insert(
263                 VoicemailContract.Voicemails.buildSourceUri(packageName), values);
264         AssetManager assets = getAssets();
265         OutputStream outputStream = null;
266         InputStream inputStream = null;
267         try {
268             inputStream = assets.open(TEST_ASSET_NAME);
269             outputStream = getContentResolver().openOutputStream(mVoicemailUri);
270             copyBetweenStreams(inputStream, outputStream);
271         } finally {
272             Closeables.closeQuietly(outputStream);
273             Closeables.closeQuietly(inputStream);
274         }
275         Uri callLogUri = ContentUris.withAppendedId(CallLog.Calls.CONTENT_URI_WITH_VOICEMAIL,
276                 ContentUris.parseId(mVoicemailUri));
277         Intent intent = new Intent(Intent.ACTION_VIEW, callLogUri);
278         intent.putExtra(CallDetailActivity.EXTRA_VOICEMAIL_URI, mVoicemailUri);
279         setActivityIntent(intent);
280     }
281 
copyBetweenStreams(InputStream in, OutputStream out)282     public void copyBetweenStreams(InputStream in, OutputStream out) throws IOException {
283         byte[] buffer = new byte[1024];
284         int bytesRead;
285         int total = 0;
286         while ((bytesRead = in.read(buffer)) != -1) {
287             total += bytesRead;
288             out.write(buffer, 0, bytesRead);
289         }
290     }
291 
cleanUpUri()292     private void cleanUpUri() {
293         if (mVoicemailUri != null) {
294             getContentResolver().delete(VoicemailContract.Voicemails.CONTENT_URI,
295                     "_ID = ?", new String[] { String.valueOf(ContentUris.parseId(mVoicemailUri)) });
296             mVoicemailUri = null;
297         }
298         if (mCallLogUri != null) {
299             getContentResolver().delete(CallLog.Calls.CONTENT_URI_WITH_VOICEMAIL,
300                     "_ID = ?", new String[] { String.valueOf(ContentUris.parseId(mCallLogUri)) });
301             mCallLogUri = null;
302         }
303     }
304 
getContentResolver()305     private ContentResolver getContentResolver() {
306         return getInstrumentation().getTargetContext().getContentResolver();
307     }
308 
assertHasOneTextViewContaining(String text)309     private TextView assertHasOneTextViewContaining(String text) throws Throwable {
310         Preconditions.checkNotNull(mActivityUnderTest, "forget to call startActivityUnderTest()?");
311         List<TextView> views = mTestUtils.getTextViewsWithString(mActivityUnderTest, text);
312         assertEquals("There should have been one TextView with text '" + text + "' but found "
313                 + views, 1, views.size());
314         return views.get(0);
315     }
316 
assertZeroTextViewsContaining(String text)317     private void assertZeroTextViewsContaining(String text) throws Throwable {
318         Preconditions.checkNotNull(mActivityUnderTest, "forget to call startActivityUnderTest()?");
319         List<TextView> views = mTestUtils.getTextViewsWithString(mActivityUnderTest, text);
320         assertEquals("There should have been no TextViews with text '" + text + "' but found "
321                 + views, 0,  views.size());
322     }
323 
startActivityUnderTest()324     private void startActivityUnderTest() throws Throwable {
325         Preconditions.checkState(mActivityUnderTest == null, "must only start the activity once");
326         mActivityUnderTest = getActivity();
327         assertNotNull("activity should not be null", mActivityUnderTest);
328         // We have to run all tasks, not just one.
329         // This is because it seems that we can have onResume, onPause, onResume during the course
330         // of a single unit test.
331         mFakeAsyncTaskExecutor.runAllTasks(UPDATE_PHONE_CALL_DETAILS);
332     }
333 
getAssets()334     private AssetManager getAssets() {
335         return getInstrumentation().getContext().getAssets();
336     }
337 }
338