1/*
2 * Copyright (C) 2015 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.dialer.voicemail;
18
19import static com.android.dialer.voicemail.VoicemailPlaybackPresenter.Tasks.CHECK_FOR_CONTENT;
20
21import android.app.Activity;
22import android.content.ContentResolver;
23import android.content.ContentUris;
24import android.content.ContentValues;
25import android.content.Context;
26import android.content.res.AssetManager;
27import android.net.Uri;
28import android.provider.VoicemailContract;
29import android.test.ActivityInstrumentationTestCase2;
30import android.test.suitebuilder.annotation.LargeTest;
31import android.view.View;
32import android.widget.TextView;
33
34import com.android.contacts.common.test.IntegrationTestUtils;
35import com.android.dialer.R;
36import com.android.dialer.calllog.CallLogActivity;
37import com.android.dialer.util.AsyncTaskExecutors;
38import com.android.dialer.util.FakeAsyncTaskExecutor;
39import com.android.dialer.util.LocaleTestUtils;
40import com.android.dialer.voicemail.VoicemailPlaybackLayout;
41import com.android.dialer.voicemail.VoicemailPlaybackPresenter;
42
43import java.io.IOException;
44import java.io.InputStream;
45import java.io.OutputStream;
46import java.util.List;
47import java.util.Locale;
48
49/**
50 * Unit tests for the {@link VoicemailPlaybackPresenter} and {@link VoicemailPlaybackLayout}.
51 */
52@LargeTest
53public class VoicemailPlaybackTest extends ActivityInstrumentationTestCase2<CallLogActivity> {
54    private static final String TEST_ASSET_NAME = "quick_test_recording.mp3";
55    private static final String MIME_TYPE = "audio/mp3";
56    private static final String CONTACT_NUMBER = "+1412555555";
57    private static final String VOICEMAIL_FILE_LOCATION = "/sdcard/sadlfj893w4j23o9sfu.mp3";
58
59    private Activity mActivity;
60    private VoicemailPlaybackPresenter mPresenter;
61    private VoicemailPlaybackLayout mLayout;
62
63    private Uri mVoicemailUri;
64    private IntegrationTestUtils mTestUtils;
65    private LocaleTestUtils mLocaleTestUtils;
66    private FakeAsyncTaskExecutor mFakeAsyncTaskExecutor;
67
68    public VoicemailPlaybackTest() {
69        super(CallLogActivity.class);
70    }
71
72    @Override
73    public void setUp() throws Exception {
74        super.setUp();
75
76        mFakeAsyncTaskExecutor = new FakeAsyncTaskExecutor(getInstrumentation());
77        AsyncTaskExecutors.setFactoryForTest(mFakeAsyncTaskExecutor.getFactory());
78        mTestUtils = new IntegrationTestUtils(getInstrumentation());
79
80        // Some of the tests rely on the text - safest to force a specific locale.
81        mLocaleTestUtils = new LocaleTestUtils(getInstrumentation().getTargetContext());
82        mLocaleTestUtils.setLocale(Locale.US);
83
84        mActivity = getActivity();
85        mLayout = new VoicemailPlaybackLayout(mActivity);
86        mLayout.onFinishInflate();
87
88        mPresenter = VoicemailPlaybackPresenter.getInstance(mActivity, null);
89    }
90
91    @Override
92    protected void tearDown() throws Exception {
93        cleanUpVoicemailUri();
94
95        mLocaleTestUtils.restoreLocale();
96        mLocaleTestUtils = null;
97
98        mLayout = null;
99        mPresenter = null;
100        mTestUtils = null;
101        AsyncTaskExecutors.setFactoryForTest(null);
102
103        super.tearDown();
104    }
105
106    public void testFetchingVoicemail() throws Throwable {
107        setUriForRealFileVoicemailEntry();
108        setPlaybackViewForPresenter();
109        assertHasOneTextViewContaining("Loading voicemail");
110    }
111
112    public void testWhenCheckForContentCompletes() throws Throwable {
113        setUriForRealFileVoicemailEntry();
114        setPlaybackViewForPresenter();
115
116        // There is a background check that is testing to see if we have the content available.
117        // Once that task completes, we shouldn't be showing the fetching message.
118        mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
119        getInstrumentation().waitForIdleSync();
120
121        assertHasOneTextViewContaining("Buffering");
122        assertHasZeroTextViewsContaining("Loading voicemail");
123    }
124
125    public void testInvalidVoicemailShowsErrorMessage() throws Throwable {
126        setUriForInvalidVoicemailEntry();
127        setPlaybackViewForPresenter();
128
129        mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
130        getInstrumentation().waitForIdleSync();
131
132        // The media player will have thrown an IOException since the file doesn't exist.
133        // This should have put a failed to play message on screen, buffering is gone.
134        assertHasOneTextViewContaining("Couldn't play voicemail");
135        assertHasZeroTextViewsContaining("Buffering");
136    }
137
138    public void testClickingSpeakerphoneButton() throws Throwable {
139        setUriForRealFileVoicemailEntry();
140        setPlaybackViewForPresenter();
141
142        // Wait for check for content to complete.
143        mFakeAsyncTaskExecutor.runTask(CHECK_FOR_CONTENT);
144        getInstrumentation().waitForIdleSync();
145
146        // Force the speakerphone to false to start.
147        mPresenter.setSpeakerphoneOn(false);
148        assertFalse(mPresenter.isSpeakerphoneOn());
149
150        View speakerphoneButton = mLayout.findViewById(R.id.playback_speakerphone);
151        speakerphoneButton.performClick();
152        assertTrue(mPresenter.isSpeakerphoneOn());
153    }
154
155    private void cleanUpVoicemailUri() {
156        if (mVoicemailUri != null) {
157            getContentResolver().delete(VoicemailContract.Voicemails.CONTENT_URI,
158                    "_ID = ?", new String[] { String.valueOf(ContentUris.parseId(mVoicemailUri)) });
159            mVoicemailUri = null;
160        }
161    }
162
163    private void setUriForRealFileVoicemailEntry() throws IOException {
164        assertNull(mVoicemailUri);
165        ContentValues values = new ContentValues();
166        values.put(VoicemailContract.Voicemails.DATE, String.valueOf(System.currentTimeMillis()));
167        values.put(VoicemailContract.Voicemails.NUMBER, CONTACT_NUMBER);
168        values.put(VoicemailContract.Voicemails.MIME_TYPE, MIME_TYPE);
169        values.put(VoicemailContract.Voicemails.HAS_CONTENT, 1);
170        String packageName = getInstrumentation().getTargetContext().getPackageName();
171        mVoicemailUri = getContentResolver().insert(
172                VoicemailContract.Voicemails.buildSourceUri(packageName), values);
173        AssetManager assets = getAssets();
174        try (InputStream inputStream = assets.open(TEST_ASSET_NAME);
175             OutputStream outputStream = getContentResolver().openOutputStream(mVoicemailUri)) {
176            copyBetweenStreams(inputStream, outputStream);
177        }
178    }
179
180    private void setUriForInvalidVoicemailEntry() {
181        assertNull(mVoicemailUri);
182        ContentResolver contentResolver = getContentResolver();
183        ContentValues values = new ContentValues();
184        values.put(VoicemailContract.Voicemails.NUMBER, CONTACT_NUMBER);
185        values.put(VoicemailContract.Voicemails.HAS_CONTENT, 1);
186        values.put(VoicemailContract.Voicemails._DATA, VOICEMAIL_FILE_LOCATION);
187        mVoicemailUri = contentResolver.insert(VoicemailContract.Voicemails.CONTENT_URI, values);
188    }
189
190    private void setPlaybackViewForPresenter() {
191        getInstrumentation().runOnMainSync(new Runnable() {
192            @Override
193            public void run() {
194                mPresenter.setPlaybackView(mLayout, mVoicemailUri, false);
195            }
196        });
197    }
198
199    public void copyBetweenStreams(InputStream in, OutputStream out) throws IOException {
200        byte[] buffer = new byte[1024];
201        int bytesRead;
202        while ((bytesRead = in.read(buffer)) > 0) {
203            out.write(buffer, 0, bytesRead);
204        }
205    }
206
207    private void assertHasOneTextViewContaining(String text) throws Throwable {
208        assertNotNull(mLayout);
209        List<TextView> views = mTestUtils.getTextViewsWithString(mLayout, text);
210        assertEquals("There should have been one TextView with text '" + text + "' but found "
211                + views, 1, views.size());
212    }
213
214    private void assertHasZeroTextViewsContaining(String text) throws Throwable {
215        assertNotNull(mLayout);
216        List<TextView> views = mTestUtils.getTextViewsWithString(mLayout, text);
217        assertEquals("There should have been no TextViews with text '" + text + "' but found "
218                + views, 0,  views.size());
219    }
220
221    private ContentResolver getContentResolver() {
222        return getInstrumentation().getTargetContext().getContentResolver();
223    }
224
225    private AssetManager getAssets() {
226        return getInstrumentation().getContext().getAssets();
227    }
228}
229