Loading packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -610,6 +610,11 @@ public class CachedBluetoothDeviceManager { return mOngoingSetMemberPair != null && mOngoingSetMemberPair.equals(device); } @NonNull public HearingAidDeviceManager getHearingAidDeviceManager() { return mHearingAidDeviceManager; } private void log(String msg) { if (DEBUG) { Log.d(TAG, msg); Loading packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java +53 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.settingslib.bluetooth; import static android.bluetooth.BluetoothDevice.BOND_BONDED; import android.annotation.CallbackExecutor; import android.bluetooth.BluetoothCsipSetCoordinator; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHapClient; Loading Loading @@ -44,7 +45,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.stream.Collectors; /** Loading @@ -59,6 +63,8 @@ public class HearingAidDeviceManager { private final LocalBluetoothManager mBtManager; private final List<CachedBluetoothDevice> mCachedDevices; private final HearingAidAudioRoutingHelper mRoutingHelper; private static final Map<ConnectionStatusListener, Executor> mConnectionStatusListeners = new ConcurrentHashMap<>(); @ConnectionStatus private int mDevicesConnectionStatus = ConnectionStatus.NO_DEVICE_BONDED; private boolean mInitialDevicesConnectionStatusUpdate = false; Loading Loading @@ -100,14 +106,60 @@ public class HearingAidDeviceManager { int CONNECTING_OR_DISCONNECTING = 2; int ACTIVE = 3; } /** * Interface for connection status listener. */ public interface ConnectionStatusListener { /** * Callback when hearing devices connection status change. * * <p>devices here means singular device or binaural device. * E.g. One of hearing device is in CONNECTED status and another is in DISCONNECTED, * it will callback CONNECTED status. * * @param status Updated {@link ConnectionStatus} */ void onDevicesConnectionStatusChanged(@ConnectionStatus int status); } /** * Registers a listener to be notified of connection status changes. * * @param listener The listener to register. * @param executor The executor on which the listener's callback will be run. */ public void registerConnectionStatusListener( @NonNull ConnectionStatusListener listener, @NonNull @CallbackExecutor Executor executor) { mConnectionStatusListeners.put(listener, executor); } /** * Unregisters a listener previously registered with * {@link #registerConnectionStatusListener(ConnectionStatusListener, Executor)}. * * @param listener The listener to unregister. */ public void unregisterConnectionStatusListener( @NonNull ConnectionStatusListener listener) { mConnectionStatusListeners.remove(listener); } private void notifyDevicesConnectionStatusChanged(int status) { mConnectionStatusListeners.forEach((listener, executor) -> executor.execute(() -> listener.onDevicesConnectionStatusChanged(status))); } /** * Updates the connection status of the hearing devices based on the currently bonded * hearing aid devices. */ synchronized void notifyDevicesConnectionStatusChanged() { final int prevVal = mDevicesConnectionStatus; updateDevicesConnectionStatus(); // TODO: b/357882387 - notify connection status changes for the callers if (mDevicesConnectionStatus != prevVal) { notifyDevicesConnectionStatusChanged(mDevicesConnectionStatus); } } private void updateDevicesConnectionStatus() { Loading packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java +39 −1 Original line number Diff line number Diff line Loading @@ -114,7 +114,10 @@ public class HearingAidDeviceManagerTest { private BluetoothDevice mDevice1; @Mock private BluetoothDevice mDevice2; @Mock private HearingAidDeviceManager.ConnectionStatusListener mConnectionStatusListener; @Mock private HearingAidDeviceManager.ConnectionStatusListener mConnectionStatusListener2; private BluetoothClass createBtClass(int deviceClass) { Parcel p = Parcel.obtain(); Loading Loading @@ -914,6 +917,41 @@ public class HearingAidDeviceManagerTest { ConnectionStatus.NO_DEVICE_BONDED); } @Test public void notifyDevicesConnectionStatusChanged_noRegisteredListener_noCallback() { when(mCachedDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHapClientProfile, mLeAudioProfile)); when(mCachedDevice1.isConnected()).thenReturn(true); mCachedDeviceManager.mCachedDevices.add(mCachedDevice1); mHearingAidDeviceManager.registerConnectionStatusListener( mConnectionStatusListener, mContext.getMainExecutor()); mHearingAidDeviceManager.unregisterConnectionStatusListener( mConnectionStatusListener); mHearingAidDeviceManager.notifyDevicesConnectionStatusChanged(); verify(mConnectionStatusListener, never()).onDevicesConnectionStatusChanged(anyInt()); } @Test public void notifyDevicesConnectionStatusChanged_twoRegisteredListener_callbackEachConnected() { when(mCachedDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHapClientProfile, mLeAudioProfile)); when(mCachedDevice1.isConnected()).thenReturn(true); mCachedDeviceManager.mCachedDevices.add(mCachedDevice1); mHearingAidDeviceManager.registerConnectionStatusListener( mConnectionStatusListener, mContext.getMainExecutor()); mHearingAidDeviceManager.registerConnectionStatusListener( mConnectionStatusListener2, mContext.getMainExecutor()); mHearingAidDeviceManager.notifyDevicesConnectionStatusChanged(); verify(mConnectionStatusListener).onDevicesConnectionStatusChanged( ConnectionStatus.CONNECTED); verify(mConnectionStatusListener2).onDevicesConnectionStatusChanged( ConnectionStatus.CONNECTED); } private HearingAidInfo getLeftAshaHearingAidInfo(long hiSyncId) { return new HearingAidInfo.Builder() .setAshaDeviceSide(HearingAidInfo.DeviceSide.SIDE_LEFT) Loading packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java +4 −1 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.view.accessibility.AccessibilityManager; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.settingslib.bluetooth.HearingAidDeviceManager; import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import com.android.systemui.accessibility.utils.TestUtils; Loading Loading @@ -58,13 +59,15 @@ public class DragToInteractAnimationControllerTest extends SysuiTestCase { @Mock private AccessibilityManager mAccessibilityManager; @Mock private HearingAidDeviceManager mHearingAidDeviceManager; @Before public void setUp() throws Exception { final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class); final SecureSettings mockSecureSettings = TestUtils.mockSecureSettings(); final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager, mockSecureSettings); mockSecureSettings, mHearingAidDeviceManager); final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext, stubWindowManager); final MenuView stubMenuView = spy(new MenuView(mContext, stubMenuViewModel, Loading packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepositoryTest.java +20 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.accessibility.floatingmenu; import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import static org.mockito.ArgumentMatchers.anyInt; Loading @@ -25,11 +26,13 @@ import static org.mockito.Mockito.verify; import android.content.Context; import android.content.res.Configuration; import android.platform.test.annotations.EnableFlags; import android.view.accessibility.AccessibilityManager; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.settingslib.bluetooth.HearingAidDeviceManager; import com.android.systemui.SysuiTestCase; import com.android.systemui.util.settings.SecureSettings; Loading @@ -45,6 +48,7 @@ import org.mockito.junit.MockitoRule; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.concurrent.Executor; /** Tests for {@link MenuInfoRepository}. */ @RunWith(AndroidJUnit4.class) Loading @@ -55,9 +59,10 @@ public class MenuInfoRepositoryTest extends SysuiTestCase { @Mock private AccessibilityManager mAccessibilityManager; @Mock private MenuInfoRepository.OnSettingsContentsChanged mMockSettingsContentsChanged; private HearingAidDeviceManager mHearingAidDeviceManager; @Mock private MenuInfoRepository.OnContentsChanged mMockSettingsContentsChanged; @Mock private SecureSettings mSecureSettings; Loading @@ -72,7 +77,7 @@ public class MenuInfoRepositoryTest extends SysuiTestCase { anyInt()); mMenuInfoRepository = new MenuInfoRepository(mContext, mAccessibilityManager, mMockSettingsContentsChanged, mSecureSettings); mMockSettingsContentsChanged, mSecureSettings, mHearingAidDeviceManager); } @After Loading Loading @@ -103,4 +108,16 @@ public class MenuInfoRepositoryTest extends SysuiTestCase { verify(mMockSettingsContentsChanged).onTargetFeaturesChanged(any()); } @Test @EnableFlags( com.android.settingslib.flags.Flags.FLAG_HEARING_DEVICE_SET_CONNECTION_STATUS_REPORT) public void registerObservers_addHearingDeviceTarget_verifyRegisterConnectionStatusListener() { mShortcutTargets.add(ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString()); mMenuInfoRepository.registerObserversAndCallbacks(); verify(mHearingAidDeviceManager).registerConnectionStatusListener( any(HearingAidDeviceManager.ConnectionStatusListener.class), any( Executor.class)); } } Loading
packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -610,6 +610,11 @@ public class CachedBluetoothDeviceManager { return mOngoingSetMemberPair != null && mOngoingSetMemberPair.equals(device); } @NonNull public HearingAidDeviceManager getHearingAidDeviceManager() { return mHearingAidDeviceManager; } private void log(String msg) { if (DEBUG) { Log.d(TAG, msg); Loading
packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java +53 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.settingslib.bluetooth; import static android.bluetooth.BluetoothDevice.BOND_BONDED; import android.annotation.CallbackExecutor; import android.bluetooth.BluetoothCsipSetCoordinator; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHapClient; Loading Loading @@ -44,7 +45,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.stream.Collectors; /** Loading @@ -59,6 +63,8 @@ public class HearingAidDeviceManager { private final LocalBluetoothManager mBtManager; private final List<CachedBluetoothDevice> mCachedDevices; private final HearingAidAudioRoutingHelper mRoutingHelper; private static final Map<ConnectionStatusListener, Executor> mConnectionStatusListeners = new ConcurrentHashMap<>(); @ConnectionStatus private int mDevicesConnectionStatus = ConnectionStatus.NO_DEVICE_BONDED; private boolean mInitialDevicesConnectionStatusUpdate = false; Loading Loading @@ -100,14 +106,60 @@ public class HearingAidDeviceManager { int CONNECTING_OR_DISCONNECTING = 2; int ACTIVE = 3; } /** * Interface for connection status listener. */ public interface ConnectionStatusListener { /** * Callback when hearing devices connection status change. * * <p>devices here means singular device or binaural device. * E.g. One of hearing device is in CONNECTED status and another is in DISCONNECTED, * it will callback CONNECTED status. * * @param status Updated {@link ConnectionStatus} */ void onDevicesConnectionStatusChanged(@ConnectionStatus int status); } /** * Registers a listener to be notified of connection status changes. * * @param listener The listener to register. * @param executor The executor on which the listener's callback will be run. */ public void registerConnectionStatusListener( @NonNull ConnectionStatusListener listener, @NonNull @CallbackExecutor Executor executor) { mConnectionStatusListeners.put(listener, executor); } /** * Unregisters a listener previously registered with * {@link #registerConnectionStatusListener(ConnectionStatusListener, Executor)}. * * @param listener The listener to unregister. */ public void unregisterConnectionStatusListener( @NonNull ConnectionStatusListener listener) { mConnectionStatusListeners.remove(listener); } private void notifyDevicesConnectionStatusChanged(int status) { mConnectionStatusListeners.forEach((listener, executor) -> executor.execute(() -> listener.onDevicesConnectionStatusChanged(status))); } /** * Updates the connection status of the hearing devices based on the currently bonded * hearing aid devices. */ synchronized void notifyDevicesConnectionStatusChanged() { final int prevVal = mDevicesConnectionStatus; updateDevicesConnectionStatus(); // TODO: b/357882387 - notify connection status changes for the callers if (mDevicesConnectionStatus != prevVal) { notifyDevicesConnectionStatusChanged(mDevicesConnectionStatus); } } private void updateDevicesConnectionStatus() { Loading
packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java +39 −1 Original line number Diff line number Diff line Loading @@ -114,7 +114,10 @@ public class HearingAidDeviceManagerTest { private BluetoothDevice mDevice1; @Mock private BluetoothDevice mDevice2; @Mock private HearingAidDeviceManager.ConnectionStatusListener mConnectionStatusListener; @Mock private HearingAidDeviceManager.ConnectionStatusListener mConnectionStatusListener2; private BluetoothClass createBtClass(int deviceClass) { Parcel p = Parcel.obtain(); Loading Loading @@ -914,6 +917,41 @@ public class HearingAidDeviceManagerTest { ConnectionStatus.NO_DEVICE_BONDED); } @Test public void notifyDevicesConnectionStatusChanged_noRegisteredListener_noCallback() { when(mCachedDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHapClientProfile, mLeAudioProfile)); when(mCachedDevice1.isConnected()).thenReturn(true); mCachedDeviceManager.mCachedDevices.add(mCachedDevice1); mHearingAidDeviceManager.registerConnectionStatusListener( mConnectionStatusListener, mContext.getMainExecutor()); mHearingAidDeviceManager.unregisterConnectionStatusListener( mConnectionStatusListener); mHearingAidDeviceManager.notifyDevicesConnectionStatusChanged(); verify(mConnectionStatusListener, never()).onDevicesConnectionStatusChanged(anyInt()); } @Test public void notifyDevicesConnectionStatusChanged_twoRegisteredListener_callbackEachConnected() { when(mCachedDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); when(mCachedDevice1.getProfiles()).thenReturn(List.of(mHapClientProfile, mLeAudioProfile)); when(mCachedDevice1.isConnected()).thenReturn(true); mCachedDeviceManager.mCachedDevices.add(mCachedDevice1); mHearingAidDeviceManager.registerConnectionStatusListener( mConnectionStatusListener, mContext.getMainExecutor()); mHearingAidDeviceManager.registerConnectionStatusListener( mConnectionStatusListener2, mContext.getMainExecutor()); mHearingAidDeviceManager.notifyDevicesConnectionStatusChanged(); verify(mConnectionStatusListener).onDevicesConnectionStatusChanged( ConnectionStatus.CONNECTED); verify(mConnectionStatusListener2).onDevicesConnectionStatusChanged( ConnectionStatus.CONNECTED); } private HearingAidInfo getLeftAshaHearingAidInfo(long hiSyncId) { return new HearingAidInfo.Builder() .setAshaDeviceSide(HearingAidInfo.DeviceSide.SIDE_LEFT) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/DragToInteractAnimationControllerTest.java +4 −1 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import android.view.accessibility.AccessibilityManager; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.settingslib.bluetooth.HearingAidDeviceManager; import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import com.android.systemui.accessibility.utils.TestUtils; Loading Loading @@ -58,13 +59,15 @@ public class DragToInteractAnimationControllerTest extends SysuiTestCase { @Mock private AccessibilityManager mAccessibilityManager; @Mock private HearingAidDeviceManager mHearingAidDeviceManager; @Before public void setUp() throws Exception { final WindowManager stubWindowManager = mContext.getSystemService(WindowManager.class); final SecureSettings mockSecureSettings = TestUtils.mockSecureSettings(); final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager, mockSecureSettings); mockSecureSettings, mHearingAidDeviceManager); final MenuViewAppearance stubMenuViewAppearance = new MenuViewAppearance(mContext, stubWindowManager); final MenuView stubMenuView = spy(new MenuView(mContext, stubMenuViewModel, Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/floatingmenu/MenuInfoRepositoryTest.java +20 −3 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.accessibility.floatingmenu; import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import static org.mockito.ArgumentMatchers.anyInt; Loading @@ -25,11 +26,13 @@ import static org.mockito.Mockito.verify; import android.content.Context; import android.content.res.Configuration; import android.platform.test.annotations.EnableFlags; import android.view.accessibility.AccessibilityManager; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.settingslib.bluetooth.HearingAidDeviceManager; import com.android.systemui.SysuiTestCase; import com.android.systemui.util.settings.SecureSettings; Loading @@ -45,6 +48,7 @@ import org.mockito.junit.MockitoRule; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.concurrent.Executor; /** Tests for {@link MenuInfoRepository}. */ @RunWith(AndroidJUnit4.class) Loading @@ -55,9 +59,10 @@ public class MenuInfoRepositoryTest extends SysuiTestCase { @Mock private AccessibilityManager mAccessibilityManager; @Mock private MenuInfoRepository.OnSettingsContentsChanged mMockSettingsContentsChanged; private HearingAidDeviceManager mHearingAidDeviceManager; @Mock private MenuInfoRepository.OnContentsChanged mMockSettingsContentsChanged; @Mock private SecureSettings mSecureSettings; Loading @@ -72,7 +77,7 @@ public class MenuInfoRepositoryTest extends SysuiTestCase { anyInt()); mMenuInfoRepository = new MenuInfoRepository(mContext, mAccessibilityManager, mMockSettingsContentsChanged, mSecureSettings); mMockSettingsContentsChanged, mSecureSettings, mHearingAidDeviceManager); } @After Loading Loading @@ -103,4 +108,16 @@ public class MenuInfoRepositoryTest extends SysuiTestCase { verify(mMockSettingsContentsChanged).onTargetFeaturesChanged(any()); } @Test @EnableFlags( com.android.settingslib.flags.Flags.FLAG_HEARING_DEVICE_SET_CONNECTION_STATUS_REPORT) public void registerObservers_addHearingDeviceTarget_verifyRegisterConnectionStatusListener() { mShortcutTargets.add(ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString()); mMenuInfoRepository.registerObserversAndCallbacks(); verify(mHearingAidDeviceManager).registerConnectionStatusListener( any(HearingAidDeviceManager.ConnectionStatusListener.class), any( Executor.class)); } }