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