1 /* 2 * Copyright 2018 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 package com.android.bluetooth.hfp; 17 18 import static org.mockito.ArgumentMatchers.any; 19 import static org.mockito.Mockito.*; 20 21 import android.bluetooth.BluetoothAdapter; 22 import android.bluetooth.BluetoothDevice; 23 import android.content.Context; 24 import android.os.HandlerThread; 25 import android.os.IBinder; 26 import android.os.ServiceManager; 27 import android.support.test.filters.MediumTest; 28 import android.support.test.runner.AndroidJUnit4; 29 import android.telephony.PhoneStateListener; 30 import android.telephony.SubscriptionManager; 31 import android.telephony.TelephonyManager; 32 33 import com.android.bluetooth.TestUtils; 34 import com.android.internal.telephony.ISub; 35 36 import org.junit.After; 37 import org.junit.Before; 38 import org.junit.Test; 39 import org.junit.runner.RunWith; 40 import org.mockito.Mock; 41 import org.mockito.MockitoAnnotations; 42 43 import java.util.HashMap; 44 45 /** 46 * Unit test to verify various methods in {@link HeadsetPhoneState} 47 */ 48 @MediumTest 49 @RunWith(AndroidJUnit4.class) 50 public class HeadsetPhoneStateTest { 51 @Mock private ISub mISub; 52 @Mock private IBinder mISubBinder; 53 @Mock private HeadsetService mHeadsetService; 54 @Mock private TelephonyManager mTelephonyManager; 55 @Mock private SubscriptionManager mSubscriptionManager; 56 private HeadsetPhoneState mHeadsetPhoneState; 57 private BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter(); 58 private HandlerThread mHandlerThread; 59 private HashMap<String, IBinder> mServiceManagerMockedServices = new HashMap<>(); 60 private Object mServiceManagerOriginalServices; 61 62 @Before 63 public void setUp() throws Exception { 64 MockitoAnnotations.initMocks(this); 65 // Mock SubscriptionManager.getDefaultSubscriptionId() to return a valid value 66 when(mISub.getDefaultSubId()).thenReturn(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); 67 when(mISubBinder.queryLocalInterface(anyString())).thenReturn(mISub); 68 mServiceManagerMockedServices.put("isub", mISubBinder); 69 mServiceManagerOriginalServices = 70 TestUtils.replaceField(ServiceManager.class, "sCache", null, 71 mServiceManagerMockedServices); 72 // Stub other methods 73 when(mHeadsetService.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn( 74 mTelephonyManager); 75 when(mHeadsetService.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)).thenReturn( 76 mSubscriptionManager); 77 mHandlerThread = new HandlerThread("HeadsetStateMachineTestHandlerThread"); 78 mHandlerThread.start(); 79 when(mHeadsetService.getStateMachinesThreadLooper()).thenReturn(mHandlerThread.getLooper()); 80 mHeadsetPhoneState = new HeadsetPhoneState(mHeadsetService); 81 } 82 83 @After 84 public void tearDown() throws Exception { 85 mHeadsetPhoneState.cleanup(); 86 mHandlerThread.quit(); 87 if (mServiceManagerOriginalServices != null) { 88 TestUtils.replaceField(ServiceManager.class, "sCache", null, 89 mServiceManagerOriginalServices); 90 mServiceManagerOriginalServices = null; 91 } 92 93 } 94 95 /** 96 * Verify that {@link PhoneStateListener#LISTEN_NONE} should result in no subscription 97 */ 98 @Test 99 public void testListenForPhoneState_NoneResultsNoListen() { 100 BluetoothDevice device1 = TestUtils.getTestDevice(mAdapter, 1); 101 mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_NONE); 102 verifyZeroInteractions(mTelephonyManager); 103 } 104 105 /** 106 * Verify that {@link PhoneStateListener#LISTEN_SERVICE_STATE} should result in corresponding 107 * subscription 108 */ 109 @Test 110 public void testListenForPhoneState_ServiceOnly() { 111 BluetoothDevice device1 = TestUtils.getTestDevice(mAdapter, 1); 112 mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_SERVICE_STATE); 113 verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_SERVICE_STATE)); 114 verifyNoMoreInteractions(mTelephonyManager); 115 } 116 117 /** 118 * Verify that {@link PhoneStateListener#LISTEN_SERVICE_STATE} and 119 * {@link PhoneStateListener#LISTEN_SIGNAL_STRENGTHS} should result in corresponding 120 * subscription 121 */ 122 @Test 123 public void testListenForPhoneState_ServiceAndSignalStrength() { 124 BluetoothDevice device1 = TestUtils.getTestDevice(mAdapter, 1); 125 mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_SERVICE_STATE 126 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); 127 verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_SERVICE_STATE 128 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS)); 129 verify(mTelephonyManager).setRadioIndicationUpdateMode( 130 TelephonyManager.INDICATION_FILTER_SIGNAL_STRENGTH, 131 TelephonyManager.INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF); 132 verifyNoMoreInteractions(mTelephonyManager); 133 } 134 135 /** 136 * Verify that partially turnning off {@link PhoneStateListener#LISTEN_SIGNAL_STRENGTHS} update 137 * should only unsubscribe signal strength update 138 */ 139 @Test 140 public void testListenForPhoneState_ServiceAndSignalStrengthUpdateTurnOffSignalStrengh() { 141 BluetoothDevice device1 = TestUtils.getTestDevice(mAdapter, 1); 142 mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_SERVICE_STATE 143 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); 144 verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_SERVICE_STATE 145 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS)); 146 verify(mTelephonyManager).setRadioIndicationUpdateMode( 147 TelephonyManager.INDICATION_FILTER_SIGNAL_STRENGTH, 148 TelephonyManager.INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF); 149 mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_SERVICE_STATE); 150 verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_NONE)); 151 verify(mTelephonyManager).setRadioIndicationUpdateMode( 152 TelephonyManager.INDICATION_FILTER_SIGNAL_STRENGTH, 153 TelephonyManager.INDICATION_UPDATE_MODE_NORMAL); 154 verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_SERVICE_STATE)); 155 verifyNoMoreInteractions(mTelephonyManager); 156 } 157 158 /** 159 * Verify that completely disabling all updates should unsubscribe from everything 160 */ 161 @Test 162 public void testListenForPhoneState_ServiceAndSignalStrengthUpdateTurnOffAll() { 163 BluetoothDevice device1 = TestUtils.getTestDevice(mAdapter, 1); 164 mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_SERVICE_STATE 165 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); 166 verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_SERVICE_STATE 167 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS)); 168 verify(mTelephonyManager).setRadioIndicationUpdateMode( 169 TelephonyManager.INDICATION_FILTER_SIGNAL_STRENGTH, 170 TelephonyManager.INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF); 171 mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_NONE); 172 verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_NONE)); 173 verify(mTelephonyManager).setRadioIndicationUpdateMode( 174 TelephonyManager.INDICATION_FILTER_SIGNAL_STRENGTH, 175 TelephonyManager.INDICATION_UPDATE_MODE_NORMAL); 176 verifyNoMoreInteractions(mTelephonyManager); 177 } 178 179 /** 180 * Verify that when multiple devices tries to subscribe to the same indicator, the same 181 * subscription is not triggered twice. Also, when one of the device is unsubsidised from an 182 * indicator, the other device still remain subscribed. 183 */ 184 @Test 185 public void testListenForPhoneState_MultiDevice_AllUpAllDown() { 186 BluetoothDevice device1 = TestUtils.getTestDevice(mAdapter, 1); 187 BluetoothDevice device2 = TestUtils.getTestDevice(mAdapter, 2); 188 // Enabling updates from first device should trigger subscription 189 mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_SERVICE_STATE 190 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); 191 verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_SERVICE_STATE 192 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS)); 193 verify(mTelephonyManager).setRadioIndicationUpdateMode( 194 TelephonyManager.INDICATION_FILTER_SIGNAL_STRENGTH, 195 TelephonyManager.INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF); 196 verifyNoMoreInteractions(mTelephonyManager); 197 // Enabling updates from second device should not trigger the same subscription 198 mHeadsetPhoneState.listenForPhoneState(device2, PhoneStateListener.LISTEN_SERVICE_STATE 199 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); 200 verifyNoMoreInteractions(mTelephonyManager); 201 // Disabling updates from first device should not cancel subscription 202 mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_NONE); 203 verifyNoMoreInteractions(mTelephonyManager); 204 // Disabling updates from second device should cancel subscription 205 mHeadsetPhoneState.listenForPhoneState(device2, PhoneStateListener.LISTEN_NONE); 206 verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_NONE)); 207 verify(mTelephonyManager).setRadioIndicationUpdateMode( 208 TelephonyManager.INDICATION_FILTER_SIGNAL_STRENGTH, 209 TelephonyManager.INDICATION_UPDATE_MODE_NORMAL); 210 verifyNoMoreInteractions(mTelephonyManager); 211 } 212 213 /** 214 * Verity that two device each partially subscribe to an indicator result in subscription to 215 * both indicators. Also unsubscribing from one indicator from one device will not cause 216 * unrelated indicator from other device from being unsubscribed. 217 */ 218 @Test 219 public void testListenForPhoneState_MultiDevice_PartialUpPartialDown() { 220 BluetoothDevice device1 = TestUtils.getTestDevice(mAdapter, 1); 221 BluetoothDevice device2 = TestUtils.getTestDevice(mAdapter, 2); 222 // Partially enabling updates from first device should trigger partial subscription 223 mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_SERVICE_STATE); 224 verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_SERVICE_STATE)); 225 verifyNoMoreInteractions(mTelephonyManager); 226 // Partially enabling updates from second device should trigger partial subscription 227 mHeadsetPhoneState.listenForPhoneState(device2, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); 228 verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_NONE)); 229 verify(mTelephonyManager).setRadioIndicationUpdateMode( 230 TelephonyManager.INDICATION_FILTER_SIGNAL_STRENGTH, 231 TelephonyManager.INDICATION_UPDATE_MODE_NORMAL); 232 verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_SERVICE_STATE 233 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS)); 234 verify(mTelephonyManager).setRadioIndicationUpdateMode( 235 TelephonyManager.INDICATION_FILTER_SIGNAL_STRENGTH, 236 TelephonyManager.INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF); 237 verifyNoMoreInteractions(mTelephonyManager); 238 // Partially disabling updates from first device should not cancel all subscription 239 mHeadsetPhoneState.listenForPhoneState(device1, PhoneStateListener.LISTEN_NONE); 240 verify(mTelephonyManager, times(2)).listen(any(), eq(PhoneStateListener.LISTEN_NONE)); 241 verify(mTelephonyManager, times(2)).setRadioIndicationUpdateMode( 242 TelephonyManager.INDICATION_FILTER_SIGNAL_STRENGTH, 243 TelephonyManager.INDICATION_UPDATE_MODE_NORMAL); 244 verify(mTelephonyManager).listen(any(), eq(PhoneStateListener.LISTEN_SIGNAL_STRENGTHS)); 245 verify(mTelephonyManager, times(2)).setRadioIndicationUpdateMode( 246 TelephonyManager.INDICATION_FILTER_SIGNAL_STRENGTH, 247 TelephonyManager.INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF); 248 verifyNoMoreInteractions(mTelephonyManager); 249 // Partially disabling updates from second device should cancel subscription 250 mHeadsetPhoneState.listenForPhoneState(device2, PhoneStateListener.LISTEN_NONE); 251 verify(mTelephonyManager, times(3)).listen(any(), eq(PhoneStateListener.LISTEN_NONE)); 252 verify(mTelephonyManager, times(3)).setRadioIndicationUpdateMode( 253 TelephonyManager.INDICATION_FILTER_SIGNAL_STRENGTH, 254 TelephonyManager.INDICATION_UPDATE_MODE_NORMAL); 255 verifyNoMoreInteractions(mTelephonyManager); 256 } 257 } 258