From f0bba5cb2775daa2acf2a0de950f7249ed9e56a1 Mon Sep 17 00:00:00 2001 From: Brandon Maxwell Date: Wed, 10 Feb 2016 16:39:21 -0800 Subject: Implementing class to play tones + This class will be used by the DialerRingtoneManager to play the call waiting tone. It exists to encapsulate the logic to play a tone in a background thread. + The TonePlayer includes some thread safety measures, but is not meant to be shared between multiple threads Bug=26936401 Change-Id: I630959177fcd8a4fc8ba7d3153f036746ad8a4cf --- .../incallui/async/SingleProdThreadExecutor.java | 3 +- .../incallui/ringtone/InCallTonePlayerTest.java | 158 +++++++++++++++++++++ 2 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 InCallUI/tests/src/com/android/incallui/ringtone/InCallTonePlayerTest.java (limited to 'InCallUI/tests/src/com/android') diff --git a/InCallUI/tests/src/com/android/incallui/async/SingleProdThreadExecutor.java b/InCallUI/tests/src/com/android/incallui/async/SingleProdThreadExecutor.java index ee27862b3..839bb2e96 100644 --- a/InCallUI/tests/src/com/android/incallui/async/SingleProdThreadExecutor.java +++ b/InCallUI/tests/src/com/android/incallui/async/SingleProdThreadExecutor.java @@ -22,7 +22,8 @@ import javax.annotation.concurrent.ThreadSafe; /** * {@link PausableExecutor} for use in tests. It is intended to be used between one test thread - * and one prod thread. + * and one prod thread. See {@link com.android.incallui.ringtone.InCallTonePlayerTest} for example + * usage. */ @ThreadSafe public final class SingleProdThreadExecutor implements PausableExecutor { diff --git a/InCallUI/tests/src/com/android/incallui/ringtone/InCallTonePlayerTest.java b/InCallUI/tests/src/com/android/incallui/ringtone/InCallTonePlayerTest.java new file mode 100644 index 000000000..096d21122 --- /dev/null +++ b/InCallUI/tests/src/com/android/incallui/ringtone/InCallTonePlayerTest.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.incallui.ringtone; + +import android.media.AudioManager; +import android.media.ToneGenerator; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.incallui.AudioModeProvider; +import com.android.incallui.async.PausableExecutor; +import com.android.incallui.async.SingleProdThreadExecutor; + +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +@SmallTest +public class InCallTonePlayerTest extends AndroidTestCase { + + @Mock private AudioModeProvider mAudioModeProvider; + @Mock private ToneGeneratorFactory mToneGeneratorFactory; + @Mock private ToneGenerator mToneGenerator; + private InCallTonePlayer mInCallTonePlayer; + + /* + * InCallTonePlayer milestones: + * 1) After tone starts playing + * 2) After tone finishes waiting (could have timed out) + * 3) After cleaning up state to allow new tone to play + */ + private PausableExecutor mExecutor; + + @Override + public void setUp() throws Exception { + super.setUp(); + MockitoAnnotations.initMocks(this); + Mockito.when(mToneGeneratorFactory.newInCallToneGenerator(Mockito.anyInt(), + Mockito.anyInt())).thenReturn(mToneGenerator); + mExecutor = new SingleProdThreadExecutor(); + mInCallTonePlayer = new InCallTonePlayer(mAudioModeProvider, mToneGeneratorFactory, + mExecutor); + } + + @Override + public void tearDown() throws Exception { + super.tearDown(); + // Stop any playing so the InCallTonePlayer isn't stuck waiting for the tone to complete + mInCallTonePlayer.stop(); + // 3 milestones in InCallTonePlayer, ack them to ensure that the prod thread doesn't block + // forever. It's fine to ack for more milestones than are hit + mExecutor.ackMilestoneForTesting(); + mExecutor.ackMilestoneForTesting(); + mExecutor.ackMilestoneForTesting(); + } + + public void testIsPlayingTone_False() { + assertFalse(mInCallTonePlayer.isPlayingTone()); + } + + public void testIsPlayingTone_True() throws InterruptedException { + mInCallTonePlayer.play(InCallTonePlayer.TONE_CALL_WAITING); + mExecutor.awaitMilestoneForTesting(); + + assertTrue(mInCallTonePlayer.isPlayingTone()); + } + + public void testPlay_InvalidTone() { + try { + mInCallTonePlayer.play(Integer.MIN_VALUE); + fail(); + } catch (IllegalArgumentException e) {} + } + + public void testPlay_CurrentlyPlaying() throws InterruptedException { + mInCallTonePlayer.play(InCallTonePlayer.TONE_CALL_WAITING); + mExecutor.awaitMilestoneForTesting(); + try { + mInCallTonePlayer.play(InCallTonePlayer.TONE_CALL_WAITING); + fail(); + } catch (IllegalStateException e) {} + } + + public void testPlay_BlueToothStream() { + // TODO (maxwelb): b/26932998 play through bluetooth + } + + public void testPlay_VoiceCallStream() throws InterruptedException { + mInCallTonePlayer.play(InCallTonePlayer.TONE_CALL_WAITING); + mExecutor.awaitMilestoneForTesting(); + Mockito.verify(mToneGeneratorFactory).newInCallToneGenerator(AudioManager.STREAM_VOICE_CALL, + InCallTonePlayer.VOLUME_RELATIVE_HIGH_PRIORITY); + } + + public void testPlay_Single() throws InterruptedException { + mInCallTonePlayer.play(InCallTonePlayer.TONE_CALL_WAITING); + mExecutor.awaitMilestoneForTesting(); + mExecutor.ackMilestoneForTesting(); + mInCallTonePlayer.stop(); + mExecutor.ackMilestoneForTesting(); + mExecutor.awaitMilestoneForTesting(); + mExecutor.ackMilestoneForTesting(); + + Mockito.verify(mToneGenerator).startTone(ToneGenerator.TONE_SUP_CALL_WAITING); + } + + public void testPlay_Consecutive() throws InterruptedException { + mInCallTonePlayer.play(InCallTonePlayer.TONE_CALL_WAITING); + mExecutor.awaitMilestoneForTesting(); + mExecutor.ackMilestoneForTesting(); + // Prevent waiting forever + mInCallTonePlayer.stop(); + mExecutor.ackMilestoneForTesting(); + mExecutor.awaitMilestoneForTesting(); + mExecutor.ackMilestoneForTesting(); + + mInCallTonePlayer.play(InCallTonePlayer.TONE_CALL_WAITING); + mExecutor.awaitMilestoneForTesting(); + mExecutor.ackMilestoneForTesting(); + mInCallTonePlayer.stop(); + mExecutor.ackMilestoneForTesting(); + mExecutor.awaitMilestoneForTesting(); + mExecutor.ackMilestoneForTesting(); + + Mockito.verify(mToneGenerator, Mockito.times(2)) + .startTone(ToneGenerator.TONE_SUP_CALL_WAITING); + } + + public void testStop_NotPlaying() { + // No crash + mInCallTonePlayer.stop(); + } + + public void testStop() throws InterruptedException { + mInCallTonePlayer.play(InCallTonePlayer.TONE_CALL_WAITING); + mExecutor.awaitMilestoneForTesting(); + + mInCallTonePlayer.stop(); + mExecutor.ackMilestoneForTesting(); + mExecutor.awaitMilestoneForTesting(); + + assertFalse(mInCallTonePlayer.isPlayingTone()); + } +} -- cgit v1.2.3