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.settings.connecteddevice; 17 18 import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; 19 import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import static org.mockito.ArgumentMatchers.any; 24 import static org.mockito.ArgumentMatchers.anyString; 25 import static org.mockito.Mockito.doReturn; 26 import static org.mockito.Mockito.spy; 27 import static org.mockito.Mockito.verify; 28 import static org.mockito.Mockito.when; 29 30 import android.bluetooth.BluetoothDevice; 31 import android.bluetooth.BluetoothProfile; 32 import android.content.Context; 33 import android.content.pm.PackageManager; 34 import android.media.AudioManager; 35 36 import androidx.appcompat.app.AlertDialog; 37 import androidx.fragment.app.FragmentActivity; 38 import androidx.preference.Preference; 39 import androidx.preference.PreferenceGroup; 40 import androidx.preference.PreferenceManager; 41 import androidx.preference.PreferenceScreen; 42 43 import com.android.settings.R; 44 import com.android.settings.bluetooth.AvailableMediaBluetoothDeviceUpdater; 45 import com.android.settings.bluetooth.Utils; 46 import com.android.settings.dashboard.DashboardFragment; 47 import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; 48 import com.android.settings.testutils.shadow.ShadowAudioManager; 49 import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; 50 import com.android.settings.testutils.shadow.ShadowBluetoothUtils; 51 import com.android.settings.utils.ActivityControllerWrapper; 52 import com.android.settingslib.bluetooth.BluetoothCallback; 53 import com.android.settingslib.bluetooth.BluetoothEventManager; 54 import com.android.settingslib.bluetooth.CachedBluetoothDevice; 55 import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; 56 import com.android.settingslib.bluetooth.HearingAidInfo; 57 import com.android.settingslib.bluetooth.LocalBluetoothManager; 58 59 import org.junit.Before; 60 import org.junit.Test; 61 import org.junit.runner.RunWith; 62 import org.mockito.Answers; 63 import org.mockito.Mock; 64 import org.mockito.MockitoAnnotations; 65 import org.robolectric.Robolectric; 66 import org.robolectric.RobolectricTestRunner; 67 import org.robolectric.RuntimeEnvironment; 68 import org.robolectric.annotation.Config; 69 70 /** Tests for {@link AvailableMediaDeviceGroupController}. */ 71 @RunWith(RobolectricTestRunner.class) 72 @Config(shadows = {ShadowAudioManager.class, ShadowBluetoothAdapter.class, 73 ShadowBluetoothUtils.class}) 74 public class AvailableMediaDeviceGroupControllerTest { 75 76 private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1"; 77 private static final String PREFERENCE_KEY_1 = "pref_key_1"; 78 79 @Mock 80 private DashboardFragment mDashboardFragment; 81 @Mock 82 private AvailableMediaBluetoothDeviceUpdater mAvailableMediaBluetoothDeviceUpdater; 83 @Mock 84 private PreferenceScreen mPreferenceScreen; 85 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 86 private PreferenceManager mPreferenceManager; 87 @Mock 88 private PackageManager mPackageManager; 89 @Mock 90 private BluetoothEventManager mEventManager; 91 @Mock 92 private LocalBluetoothManager mLocalBluetoothManager; 93 @Mock 94 private CachedBluetoothDeviceManager mCachedDeviceManager; 95 @Mock 96 private CachedBluetoothDevice mCachedBluetoothDevice; 97 98 private PreferenceGroup mPreferenceGroup; 99 private Context mContext; 100 private Preference mPreference; 101 private AvailableMediaDeviceGroupController mAvailableMediaDeviceGroupController; 102 private AudioManager mAudioManager; 103 104 @Before setUp()105 public void setUp() { 106 MockitoAnnotations.initMocks(this); 107 108 mContext = spy(RuntimeEnvironment.application); 109 mPreference = new Preference(mContext); 110 mPreference.setKey(PREFERENCE_KEY_1); 111 mPreferenceGroup = spy(new PreferenceScreen(mContext, null)); 112 113 final FragmentActivity mActivity = (FragmentActivity) ActivityControllerWrapper.setup( 114 Robolectric.buildActivity(FragmentActivity.class)).get(); 115 116 when(mPreferenceGroup.getPreferenceManager()).thenReturn(mPreferenceManager); 117 doReturn(mContext).when(mDashboardFragment).getContext(); 118 doReturn(mPackageManager).when(mContext).getPackageManager(); 119 doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH); 120 when(mDashboardFragment.getParentFragmentManager()).thenReturn( 121 mActivity.getSupportFragmentManager()); 122 123 ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager; 124 mLocalBluetoothManager = Utils.getLocalBtManager(mContext); 125 mAudioManager = mContext.getSystemService(AudioManager.class); 126 doReturn(mEventManager).when(mLocalBluetoothManager).getEventManager(); 127 when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager); 128 when(mCachedDeviceManager.findDevice(any(BluetoothDevice.class))).thenReturn( 129 mCachedBluetoothDevice); 130 when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS); 131 132 mAvailableMediaDeviceGroupController = spy( 133 new AvailableMediaDeviceGroupController(mContext)); 134 mAvailableMediaDeviceGroupController. 135 setBluetoothDeviceUpdater(mAvailableMediaBluetoothDeviceUpdater); 136 mAvailableMediaDeviceGroupController.mPreferenceGroup = mPreferenceGroup; 137 } 138 139 @Test onDeviceAdded_firstAdd_becomeVisibleAndPreferenceAdded()140 public void onDeviceAdded_firstAdd_becomeVisibleAndPreferenceAdded() { 141 mAvailableMediaDeviceGroupController.onDeviceAdded(mPreference); 142 143 assertThat(mPreferenceGroup.isVisible()).isTrue(); 144 assertThat((Preference) mPreferenceGroup.findPreference(PREFERENCE_KEY_1)) 145 .isEqualTo(mPreference); 146 } 147 148 @Test onDeviceRemoved_lastRemove_becomeInvisibleAndPreferenceRemoved()149 public void onDeviceRemoved_lastRemove_becomeInvisibleAndPreferenceRemoved() { 150 mPreferenceGroup.addPreference(mPreference); 151 152 mAvailableMediaDeviceGroupController.onDeviceRemoved(mPreference); 153 154 assertThat(mPreferenceGroup.isVisible()).isFalse(); 155 assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(0); 156 } 157 158 @Test onDeviceRemoved_notLastRemove_stillVisible()159 public void onDeviceRemoved_notLastRemove_stillVisible() { 160 mPreferenceGroup.setVisible(true); 161 mPreferenceGroup.addPreference(mPreference); 162 mPreferenceGroup.addPreference(new Preference(mContext)); 163 164 mAvailableMediaDeviceGroupController.onDeviceRemoved(mPreference); 165 166 assertThat(mPreferenceGroup.isVisible()).isTrue(); 167 } 168 169 @Test displayPreference_becomeInvisible()170 public void displayPreference_becomeInvisible() { 171 doReturn(mPreferenceGroup).when(mPreferenceScreen).findPreference(anyString()); 172 173 mAvailableMediaDeviceGroupController.displayPreference(mPreferenceScreen); 174 175 assertThat(mPreferenceGroup.isVisible()).isFalse(); 176 } 177 178 @Test testRegister()179 public void testRegister() { 180 // register the callback in onStart() 181 mAvailableMediaDeviceGroupController.onStart(); 182 183 verify(mAvailableMediaBluetoothDeviceUpdater).registerCallback(); 184 verify(mLocalBluetoothManager.getEventManager()).registerCallback( 185 any(BluetoothCallback.class)); 186 verify(mAvailableMediaBluetoothDeviceUpdater).refreshPreference(); 187 } 188 189 @Test testUnregister()190 public void testUnregister() { 191 // unregister the callback in onStop() 192 mAvailableMediaDeviceGroupController.onStop(); 193 verify(mAvailableMediaBluetoothDeviceUpdater).unregisterCallback(); 194 verify(mLocalBluetoothManager.getEventManager()).unregisterCallback( 195 any(BluetoothCallback.class)); 196 } 197 198 @Test testGetAvailabilityStatus_noBluetoothFeature_returnUnSupported()199 public void testGetAvailabilityStatus_noBluetoothFeature_returnUnSupported() { 200 doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH); 201 202 assertThat(mAvailableMediaDeviceGroupController.getAvailabilityStatus()).isEqualTo( 203 UNSUPPORTED_ON_DEVICE); 204 } 205 206 @Test testGetAvailabilityStatus_BluetoothFeature_returnSupported()207 public void testGetAvailabilityStatus_BluetoothFeature_returnSupported() { 208 doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH); 209 210 assertThat(mAvailableMediaDeviceGroupController.getAvailabilityStatus()).isEqualTo( 211 AVAILABLE_UNSEARCHABLE); 212 } 213 214 @Test setTitle_inCallState_showCallStateTitle()215 public void setTitle_inCallState_showCallStateTitle() { 216 mAudioManager.setMode(AudioManager.MODE_IN_CALL); 217 mAvailableMediaDeviceGroupController.onAudioModeChanged(); 218 219 assertThat(mPreferenceGroup.getTitle()).isEqualTo( 220 mContext.getText(R.string.connected_device_call_device_title)); 221 } 222 223 @Test setTitle_notInCallState_showMediaStateTitle()224 public void setTitle_notInCallState_showMediaStateTitle() { 225 mAudioManager.setMode(AudioManager.MODE_NORMAL); 226 mAvailableMediaDeviceGroupController.onAudioModeChanged(); 227 228 assertThat(mPreferenceGroup.getTitle()).isEqualTo( 229 mContext.getText(R.string.connected_device_media_device_title)); 230 } 231 232 @Test onStart_localBluetoothManagerNull_shouldNotCrash()233 public void onStart_localBluetoothManagerNull_shouldNotCrash() { 234 mAvailableMediaDeviceGroupController.mLocalBluetoothManager = null; 235 236 // Shouldn't crash 237 mAvailableMediaDeviceGroupController.onStart(); 238 } 239 240 @Test onStop_localBluetoothManagerNull_shouldNotCrash()241 public void onStop_localBluetoothManagerNull_shouldNotCrash() { 242 mAvailableMediaDeviceGroupController.mLocalBluetoothManager = null; 243 244 // Shouldn't crash 245 mAvailableMediaDeviceGroupController.onStop(); 246 } 247 248 @Test 249 @Config(shadows = ShadowAlertDialogCompat.class) onActiveDeviceChanged_hearingAidProfile_launchHearingAidPairingDialog()250 public void onActiveDeviceChanged_hearingAidProfile_launchHearingAidPairingDialog() { 251 when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true); 252 when(mCachedBluetoothDevice.getDeviceMode()).thenReturn( 253 HearingAidInfo.DeviceMode.MODE_BINAURAL); 254 when(mCachedBluetoothDevice.getDeviceSide()).thenReturn( 255 HearingAidInfo.DeviceSide.SIDE_LEFT); 256 mAvailableMediaDeviceGroupController.init(mDashboardFragment); 257 258 mAvailableMediaDeviceGroupController.onActiveDeviceChanged(mCachedBluetoothDevice, 259 BluetoothProfile.HEARING_AID); 260 261 final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); 262 assertThat(dialog.isShowing()).isTrue(); 263 } 264 } 265