Home | History | Annotate | Download | only in a2dpsink
      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.any;
     20 import static org.mockito.Mockito.anyFloat;
     21 import static org.mockito.Mockito.anyInt;
     22 import static org.mockito.Mockito.doNothing;
     23 import static org.mockito.Mockito.eq;
     24 import static org.mockito.Mockito.spy;
     25 import static org.mockito.Mockito.times;
     26 import static org.mockito.Mockito.verify;
     27 import static org.mockito.Mockito.when;
     28 
     29 import android.content.Context;
     30 import android.content.res.Resources;
     31 import android.media.AudioManager;
     32 import android.media.AudioManager.OnAudioFocusChangeListener;
     33 import android.os.HandlerThread;
     34 import android.os.Looper;
     35 import android.test.AndroidTestCase;
     36 
     37 import org.junit.Before;
     38 import org.junit.Test;
     39 import org.junit.runner.RunWith;
     40 import org.mockito.ArgumentCaptor;
     41 import org.mockito.Mock;
     42 import org.mockito.runners.MockitoJUnitRunner;
     43 
     44 @RunWith(MockitoJUnitRunner.class)
     45 public class A2dpSinkStreamHandlerTest extends AndroidTestCase {
     46     static final int DUCK_PERCENT = 75;
     47     private HandlerThread mHandlerThread;
     48     A2dpSinkStreamHandler streamHandler;
     49     ArgumentCaptor<OnAudioFocusChangeListener> audioFocusChangeListenerArgumentCaptor;
     50 
     51     @Mock Context mockContext;
     52 
     53     @Mock A2dpSinkStateMachine mockA2dpSink;
     54 
     55     @Mock AudioManager mockAudioManager;
     56 
     57     @Mock Resources mockResources;
     58 
     59     @Before
     60     public void setUp() {
     61         // Mock the looper
     62         if (Looper.myLooper() == null) {
     63             Looper.prepare();
     64         }
     65 
     66         mHandlerThread = new HandlerThread("A2dpSinkStreamHandlerTest");
     67         mHandlerThread.start();
     68 
     69         audioFocusChangeListenerArgumentCaptor =
     70                 ArgumentCaptor.forClass(OnAudioFocusChangeListener.class);
     71         when(mockContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mockAudioManager);
     72         when(mockContext.getResources()).thenReturn(mockResources);
     73         when(mockResources.getInteger(anyInt())).thenReturn(DUCK_PERCENT);
     74         when(mockAudioManager.requestAudioFocus(audioFocusChangeListenerArgumentCaptor.capture(),
     75                      eq(AudioManager.STREAM_MUSIC), eq(AudioManager.AUDIOFOCUS_GAIN)))
     76                 .thenReturn(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
     77         when(mockAudioManager.abandonAudioFocus(any())).thenReturn(AudioManager.AUDIOFOCUS_GAIN);
     78         doNothing().when(mockA2dpSink).informAudioTrackGainNative(anyFloat());
     79         when(mockContext.getMainLooper()).thenReturn(mHandlerThread.getLooper());
     80 
     81         streamHandler = spy(new A2dpSinkStreamHandler(mockA2dpSink, mockContext));
     82     }
     83 
     84     @Test
     85     public void testSrcStart() {
     86         // Stream started without local play, expect no change in streaming.
     87         streamHandler.handleMessage(
     88                 streamHandler.obtainMessage(A2dpSinkStreamHandler.SRC_STR_START));
     89         verify(mockAudioManager, times(0)).requestAudioFocus(any(), anyInt(), anyInt());
     90         verify(mockA2dpSink, times(0)).informAudioFocusStateNative(1);
     91         verify(mockA2dpSink, times(0)).informAudioTrackGainNative(1.0f);
     92     }
     93 
     94     @Test
     95     public void testSrcStop() {
     96         // Stream stopped without local play, expect no change in streaming.
     97         streamHandler.handleMessage(
     98                 streamHandler.obtainMessage(A2dpSinkStreamHandler.SRC_STR_STOP));
     99         verify(mockAudioManager, times(0)).requestAudioFocus(any(), anyInt(), anyInt());
    100         verify(mockA2dpSink, times(0)).informAudioFocusStateNative(1);
    101         verify(mockA2dpSink, times(0)).informAudioTrackGainNative(1.0f);
    102     }
    103 
    104     @Test
    105     public void testSnkPlay() {
    106         // Play was pressed locally, expect streaming to start.
    107         streamHandler.handleMessage(streamHandler.obtainMessage(A2dpSinkStreamHandler.SNK_PLAY));
    108         verify(mockAudioManager, times(1)).requestAudioFocus(any(), anyInt(), anyInt());
    109         verify(mockA2dpSink, times(1)).informAudioFocusStateNative(1);
    110         verify(mockA2dpSink, times(1)).informAudioTrackGainNative(1.0f);
    111     }
    112 
    113     @Test
    114     public void testSnkPause() {
    115         // Pause was pressed locally, expect streaming to stop.
    116         streamHandler.handleMessage(streamHandler.obtainMessage(A2dpSinkStreamHandler.SNK_PAUSE));
    117         verify(mockAudioManager, times(0)).requestAudioFocus(any(), anyInt(), anyInt());
    118         verify(mockA2dpSink, times(0)).informAudioFocusStateNative(1);
    119         verify(mockA2dpSink, times(0)).informAudioTrackGainNative(1.0f);
    120     }
    121 
    122     @Test
    123     public void testDisconnect() {
    124         // Remote device was disconnected, expect streaming to stop.
    125         testSnkPlay();
    126         streamHandler.handleMessage(streamHandler.obtainMessage(A2dpSinkStreamHandler.DISCONNECT));
    127         verify(mockAudioManager, times(1)).abandonAudioFocus(any());
    128         verify(mockA2dpSink, times(1)).informAudioFocusStateNative(0);
    129     }
    130 
    131     @Test
    132     public void testSrcPlay() {
    133         // Play was pressed remotely, expect no streaming due to lack of audio focus.
    134         streamHandler.handleMessage(streamHandler.obtainMessage(A2dpSinkStreamHandler.SRC_PLAY));
    135         verify(mockAudioManager, times(0)).requestAudioFocus(any(), anyInt(), anyInt());
    136         verify(mockA2dpSink, times(0)).informAudioFocusStateNative(1);
    137         verify(mockA2dpSink, times(0)).informAudioTrackGainNative(1.0f);
    138     }
    139 
    140     @Test
    141     public void testSrcPause() {
    142         // Play was pressed locally, expect streaming to start.
    143         streamHandler.handleMessage(streamHandler.obtainMessage(A2dpSinkStreamHandler.SRC_PLAY));
    144         verify(mockAudioManager, times(0)).requestAudioFocus(any(), anyInt(), anyInt());
    145         verify(mockA2dpSink, times(0)).informAudioFocusStateNative(1);
    146         verify(mockA2dpSink, times(0)).informAudioTrackGainNative(1.0f);
    147     }
    148 
    149     @Test
    150     public void testFocusGain() {
    151         // Focus was gained, expect streaming to resume.
    152         testSnkPlay();
    153         streamHandler.handleMessage(streamHandler.obtainMessage(
    154                 A2dpSinkStreamHandler.AUDIO_FOCUS_CHANGE, AudioManager.AUDIOFOCUS_GAIN));
    155         verify(mockAudioManager, times(1)).requestAudioFocus(any(), anyInt(), anyInt());
    156         verify(mockA2dpSink, times(2)).informAudioFocusStateNative(1);
    157         verify(mockA2dpSink, times(2)).informAudioTrackGainNative(1.0f);
    158     }
    159 
    160     @Test
    161     public void testFocusTransientMayDuck() {
    162         // TransientMayDuck focus was gained, expect audio stream to duck.
    163         testSnkPlay();
    164         streamHandler.handleMessage(
    165                 streamHandler.obtainMessage(A2dpSinkStreamHandler.AUDIO_FOCUS_CHANGE,
    166                         AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK));
    167         verify(mockA2dpSink, times(1)).informAudioTrackGainNative(DUCK_PERCENT / 100.0f);
    168     }
    169 
    170     @Test
    171     public void testFocusLostTransient() {
    172         // Focus was lost transiently, expect streaming to stop.
    173         testSnkPlay();
    174         streamHandler.handleMessage(streamHandler.obtainMessage(
    175                 A2dpSinkStreamHandler.AUDIO_FOCUS_CHANGE, AudioManager.AUDIOFOCUS_LOSS_TRANSIENT));
    176         verify(mockAudioManager, times(0)).abandonAudioFocus(any());
    177         verify(mockA2dpSink, times(1)).informAudioFocusStateNative(0);
    178     }
    179 
    180     @Test
    181     public void testFocusLost() {
    182         // Focus was lost permanently, expect streaming to stop.
    183         testSnkPlay();
    184         streamHandler.handleMessage(streamHandler.obtainMessage(
    185                 A2dpSinkStreamHandler.AUDIO_FOCUS_CHANGE, AudioManager.AUDIOFOCUS_LOSS));
    186         verify(mockAudioManager, times(1)).abandonAudioFocus(any());
    187         verify(mockA2dpSink, times(1)).informAudioFocusStateNative(0);
    188     }
    189 }
    190