• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.bluetooth.a2dpsink;
18 
19 import static org.mockito.Mockito.*;
20 
21 import android.content.Context;
22 import android.content.pm.PackageManager;
23 import android.content.res.Resources;
24 import android.media.AudioManager;
25 import android.os.HandlerThread;
26 import android.os.Looper;
27 import android.support.test.InstrumentationRegistry;
28 import android.support.test.filters.MediumTest;
29 import android.support.test.runner.AndroidJUnit4;
30 
31 import com.android.bluetooth.R;
32 
33 import org.junit.Assume;
34 import org.junit.Before;
35 import org.junit.Test;
36 import org.junit.runner.RunWith;
37 import org.mockito.Mock;
38 import org.mockito.MockitoAnnotations;
39 
40 @MediumTest
41 @RunWith(AndroidJUnit4.class)
42 public class A2dpSinkStreamHandlerTest {
43     private static final int DUCK_PERCENT = 75;
44     private HandlerThread mHandlerThread;
45     private A2dpSinkStreamHandler mStreamHandler;
46     private Context mTargetContext;
47 
48     @Mock private Context mMockContext;
49 
50     @Mock private A2dpSinkStateMachine mMockA2dpSink;
51 
52     @Mock private AudioManager mMockAudioManager;
53 
54     @Mock private Resources mMockResources;
55 
56     @Mock private PackageManager mMockPackageManager;
57 
58     @Before
setUp()59     public void setUp() {
60         mTargetContext = InstrumentationRegistry.getTargetContext();
61         Assume.assumeTrue("Ignore test when A2dpSinkService is not enabled",
62                 mTargetContext.getResources().getBoolean(R.bool.profile_supported_a2dp_sink));
63         MockitoAnnotations.initMocks(this);
64         // Mock the looper
65         if (Looper.myLooper() == null) {
66             Looper.prepare();
67         }
68 
69         mHandlerThread = new HandlerThread("A2dpSinkStreamHandlerTest");
70         mHandlerThread.start();
71 
72         when(mMockContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mMockAudioManager);
73         when(mMockContext.getResources()).thenReturn(mMockResources);
74         when(mMockResources.getInteger(anyInt())).thenReturn(DUCK_PERCENT);
75         when(mMockAudioManager.requestAudioFocus(any())).thenReturn(
76                 AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
77         when(mMockAudioManager.abandonAudioFocus(any())).thenReturn(AudioManager.AUDIOFOCUS_GAIN);
78         doNothing().when(mMockA2dpSink).informAudioTrackGainNative(anyFloat());
79         when(mMockContext.getMainLooper()).thenReturn(mHandlerThread.getLooper());
80         when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
81         when(mMockPackageManager.hasSystemFeature(any())).thenReturn(false);
82 
83         mStreamHandler = spy(new A2dpSinkStreamHandler(mMockA2dpSink, mMockContext));
84     }
85 
86     @Test
testSrcStart()87     public void testSrcStart() {
88         // Stream started without local play, expect no change in streaming.
89         mStreamHandler.handleMessage(
90                 mStreamHandler.obtainMessage(A2dpSinkStreamHandler.SRC_STR_START));
91         verify(mMockAudioManager, times(0)).requestAudioFocus(any());
92         verify(mMockA2dpSink, times(0)).informAudioFocusStateNative(1);
93         verify(mMockA2dpSink, times(0)).informAudioTrackGainNative(1.0f);
94     }
95 
96     @Test
testSrcStop()97     public void testSrcStop() {
98         // Stream stopped without local play, expect no change in streaming.
99         mStreamHandler.handleMessage(
100                 mStreamHandler.obtainMessage(A2dpSinkStreamHandler.SRC_STR_STOP));
101         verify(mMockAudioManager, times(0)).requestAudioFocus(any());
102         verify(mMockA2dpSink, times(0)).informAudioFocusStateNative(1);
103         verify(mMockA2dpSink, times(0)).informAudioTrackGainNative(1.0f);
104     }
105 
106     @Test
testSnkPlay()107     public void testSnkPlay() {
108         // Play was pressed locally, expect streaming to start.
109         mStreamHandler.handleMessage(mStreamHandler.obtainMessage(A2dpSinkStreamHandler.SNK_PLAY));
110         verify(mMockAudioManager, times(1)).requestAudioFocus(any());
111         verify(mMockA2dpSink, times(1)).informAudioFocusStateNative(1);
112         verify(mMockA2dpSink, times(1)).informAudioTrackGainNative(1.0f);
113     }
114 
115     @Test
testSnkPause()116     public void testSnkPause() {
117         // Pause was pressed locally, expect streaming to stop.
118         mStreamHandler.handleMessage(mStreamHandler.obtainMessage(A2dpSinkStreamHandler.SNK_PAUSE));
119         verify(mMockAudioManager, times(0)).requestAudioFocus(any());
120         verify(mMockA2dpSink, times(0)).informAudioFocusStateNative(1);
121         verify(mMockA2dpSink, times(0)).informAudioTrackGainNative(1.0f);
122     }
123 
124     @Test
testDisconnect()125     public void testDisconnect() {
126         // Remote device was disconnected, expect streaming to stop.
127         testSnkPlay();
128         mStreamHandler.handleMessage(
129                 mStreamHandler.obtainMessage(A2dpSinkStreamHandler.DISCONNECT));
130         verify(mMockAudioManager, times(0)).abandonAudioFocus(any());
131         verify(mMockA2dpSink, times(0)).informAudioFocusStateNative(0);
132     }
133 
134     @Test
testSrcPlay()135     public void testSrcPlay() {
136         // Play was pressed remotely, expect no streaming due to lack of audio focus.
137         mStreamHandler.handleMessage(mStreamHandler.obtainMessage(A2dpSinkStreamHandler.SRC_PLAY));
138         verify(mMockAudioManager, times(0)).requestAudioFocus(any());
139         verify(mMockA2dpSink, times(0)).informAudioFocusStateNative(1);
140         verify(mMockA2dpSink, times(0)).informAudioTrackGainNative(1.0f);
141     }
142 
143     @Test
testSrcPlayIot()144     public void testSrcPlayIot() {
145         // Play was pressed remotely for an iot device, expect streaming to start.
146         when(mMockPackageManager.hasSystemFeature(any())).thenReturn(true);
147         mStreamHandler.handleMessage(mStreamHandler.obtainMessage(A2dpSinkStreamHandler.SRC_PLAY));
148         verify(mMockAudioManager, times(1)).requestAudioFocus(any());
149         verify(mMockA2dpSink, times(1)).informAudioFocusStateNative(1);
150         verify(mMockA2dpSink, times(1)).informAudioTrackGainNative(1.0f);
151     }
152 
153     @Test
testSrcPause()154     public void testSrcPause() {
155         // Play was pressed locally, expect streaming to start.
156         mStreamHandler.handleMessage(mStreamHandler.obtainMessage(A2dpSinkStreamHandler.SRC_PLAY));
157         verify(mMockAudioManager, times(0)).requestAudioFocus(any());
158         verify(mMockA2dpSink, times(0)).informAudioFocusStateNative(1);
159         verify(mMockA2dpSink, times(0)).informAudioTrackGainNative(1.0f);
160     }
161 
162     @Test
testFocusGain()163     public void testFocusGain() {
164         // Focus was gained, expect streaming to resume.
165         testSnkPlay();
166         mStreamHandler.handleMessage(
167                 mStreamHandler.obtainMessage(A2dpSinkStreamHandler.AUDIO_FOCUS_CHANGE,
168                         AudioManager.AUDIOFOCUS_GAIN));
169         verify(mMockAudioManager, times(1)).requestAudioFocus(any());
170         verify(mMockA2dpSink, times(2)).informAudioFocusStateNative(1);
171         verify(mMockA2dpSink, times(2)).informAudioTrackGainNative(1.0f);
172     }
173 
174     @Test
testFocusTransientMayDuck()175     public void testFocusTransientMayDuck() {
176         // TransientMayDuck focus was gained, expect audio stream to duck.
177         testSnkPlay();
178         mStreamHandler.handleMessage(
179                 mStreamHandler.obtainMessage(A2dpSinkStreamHandler.AUDIO_FOCUS_CHANGE,
180                         AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK));
181         verify(mMockA2dpSink, times(1)).informAudioTrackGainNative(DUCK_PERCENT / 100.0f);
182     }
183 
184     @Test
testFocusLostTransient()185     public void testFocusLostTransient() {
186         // Focus was lost transiently, expect streaming to stop.
187         testSnkPlay();
188         mStreamHandler.handleMessage(
189                 mStreamHandler.obtainMessage(A2dpSinkStreamHandler.AUDIO_FOCUS_CHANGE,
190                         AudioManager.AUDIOFOCUS_LOSS_TRANSIENT));
191         verify(mMockAudioManager, times(0)).abandonAudioFocus(any());
192         verify(mMockA2dpSink, times(1)).informAudioFocusStateNative(0);
193     }
194 
195     @Test
testFocusLost()196     public void testFocusLost() {
197         // Focus was lost permanently, expect streaming to stop.
198         testSnkPlay();
199         mStreamHandler.handleMessage(
200                 mStreamHandler.obtainMessage(A2dpSinkStreamHandler.AUDIO_FOCUS_CHANGE,
201                         AudioManager.AUDIOFOCUS_LOSS));
202         verify(mMockAudioManager, times(1)).abandonAudioFocus(any());
203         verify(mMockA2dpSink, times(1)).informAudioFocusStateNative(0);
204     }
205 }
206