Loading packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java +55 −30 Original line number Diff line number Diff line Loading @@ -45,16 +45,25 @@ public final class HearingAidStatsLogUtils { private static final String TAG = "HearingAidStatsLogUtils"; private static final boolean DEBUG = true; private static final String ACCESSIBILITY_PREFERENCE = "accessibility_prefs"; private static final String BT_HEARING_AIDS_PAIRED_HISTORY = "bt_hearing_aids_paired_history"; private static final String BT_HEARING_AIDS_CONNECTED_HISTORY = private static final String BT_HEARING_DEVICES_PAIRED_HISTORY = "bt_hearing_aids_paired_history"; private static final String BT_HEARING_DEVICES_CONNECTED_HISTORY = "bt_hearing_aids_connected_history"; // The values here actually represent Bluetooth hearable devices, but were mistyped // as hearing devices in the string value previously. Keep the string values to ensure record // persistence. private static final String BT_HEARABLE_DEVICES_PAIRED_HISTORY = "bt_hearing_devices_paired_history"; private static final String BT_HEARABLE_DEVICES_CONNECTED_HISTORY = "bt_hearing_devices_connected_history"; private static final String HISTORY_RECORD_DELIMITER = ","; static final String CATEGORY_HEARING_AIDS = "A11yHearingAidsUser"; static final String CATEGORY_NEW_HEARING_AIDS = "A11yNewHearingAidsUser"; static final String CATEGORY_HEARING_DEVICES = "A11yHearingAidsUser"; static final String CATEGORY_NEW_HEARING_DEVICES = "A11yNewHearingAidsUser"; // Previously, 'hearable device' was incorrectly entered as 'hearing device'. These string // values are maintained to ensure records persistence. static final String CATEGORY_HEARABLE_DEVICES = "A11yHearingDevicesUser"; static final String CATEGORY_NEW_HEARABLE_DEVICES = "A11yNewHearingDevicesUser"; Loading @@ -69,14 +78,14 @@ public final class HearingAidStatsLogUtils { @Retention(RetentionPolicy.SOURCE) @IntDef({ HistoryType.TYPE_UNKNOWN, HistoryType.TYPE_HEARING_AIDS_PAIRED, HistoryType.TYPE_HEARING_AIDS_CONNECTED, HistoryType.TYPE_HEARING_DEVICES_PAIRED, HistoryType.TYPE_HEARING_DEVICES_CONNECTED, HistoryType.TYPE_HEARABLE_DEVICES_PAIRED, HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED}) public @interface HistoryType { int TYPE_UNKNOWN = -1; int TYPE_HEARING_AIDS_PAIRED = 0; int TYPE_HEARING_AIDS_CONNECTED = 1; int TYPE_HEARING_DEVICES_PAIRED = 0; int TYPE_HEARING_DEVICES_CONNECTED = 1; int TYPE_HEARABLE_DEVICES_PAIRED = 2; int TYPE_HEARABLE_DEVICES_CONNECTED = 3; } Loading Loading @@ -137,27 +146,25 @@ public final class HearingAidStatsLogUtils { LocalBluetoothProfile profile, int profileState) { if (isJustBonded(cachedDevice.getAddress())) { // Saves bonded timestamp as the source for judging whether to display // the survey if (cachedDevice.getProfiles().stream().anyMatch( p -> (p instanceof HearingAidProfile || p instanceof HapClientProfile))) { // Saves bonded timestamp as the source for judging whether to display the survey if (isHearingDevice(cachedDevice)) { HearingAidStatsLogUtils.addCurrentTimeToHistory(context, HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_AIDS_PAIRED); } else if (cachedDevice.getProfiles().stream().anyMatch( p -> (p instanceof A2dpSinkProfile || p instanceof HeadsetProfile))) { HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_PAIRED); } else if (isHearableDevice(cachedDevice)) { HearingAidStatsLogUtils.addCurrentTimeToHistory(context, HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_PAIRED); } removeFromJustBonded(cachedDevice.getAddress()); } // Saves connected timestamp as the source for judging whether to display // the survey if (profileState == BluetoothProfile.STATE_CONNECTED) { if (profile instanceof HearingAidProfile || profile instanceof HapClientProfile) { // Saves connected timestamp as the source for judging whether to display the survey if (isHearingProfile(profile)) { HearingAidStatsLogUtils.addCurrentTimeToHistory(context, HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_AIDS_CONNECTED); } else if (profile instanceof A2dpSinkProfile || profile instanceof HeadsetProfile) { HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED); } else if (isHearableProfile(profile) && !isHearingDevice(cachedDevice)) { // Hearing devices may contain some hearable profiles as well, make sure to exclude // these cases when update hearable connected history. HearingAidStatsLogUtils.addCurrentTimeToHistory(context, HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED); } Loading @@ -166,8 +173,8 @@ public final class HearingAidStatsLogUtils { /** * Returns the user category if the user is already categorized. Otherwise, checks the * history and sees if the user is categorized as one of {@link #CATEGORY_HEARING_AIDS}, * {@link #CATEGORY_NEW_HEARING_AIDS}, {@link #CATEGORY_HEARABLE_DEVICES}, and * history and sees if the user is categorized as one of {@link #CATEGORY_HEARING_DEVICES}, * {@link #CATEGORY_NEW_HEARING_DEVICES}, {@link #CATEGORY_HEARABLE_DEVICES}, and * {@link #CATEGORY_NEW_HEARABLE_DEVICES}. * * @param context the request context Loading @@ -175,19 +182,19 @@ public final class HearingAidStatsLogUtils { */ public static synchronized String getUserCategory(Context context) { LinkedList<Long> hearingAidsConnectedHistory = getHistory(context, HistoryType.TYPE_HEARING_AIDS_CONNECTED); HistoryType.TYPE_HEARING_DEVICES_CONNECTED); if (hearingAidsConnectedHistory != null && hearingAidsConnectedHistory.size() >= VALID_CONNECTED_EVENT_COUNT) { LinkedList<Long> hearingAidsPairedHistory = getHistory(context, HistoryType.TYPE_HEARING_AIDS_PAIRED); HistoryType.TYPE_HEARING_DEVICES_PAIRED); // Since paired history will be cleared after 30 days. If there's any record within 30 // days, the user will be categorized as CATEGORY_NEW_HEARING_AIDS. Otherwise, the user // will be categorized as CATEGORY_HEARING_AIDS. if (hearingAidsPairedHistory != null && hearingAidsPairedHistory.size() >= VALID_PAIRED_EVENT_COUNT) { return CATEGORY_NEW_HEARING_AIDS; return CATEGORY_NEW_HEARING_DEVICES; } else { return CATEGORY_HEARING_AIDS; return CATEGORY_HEARING_DEVICES; } } Loading Loading @@ -271,13 +278,13 @@ public final class HearingAidStatsLogUtils { @Nullable static synchronized LinkedList<Long> getHistory(Context context, @HistoryType int type) { String spName = HISTORY_TYPE_TO_SP_NAME_MAPPING.get(type); if (BT_HEARING_AIDS_PAIRED_HISTORY.equals(spName) if (BT_HEARING_DEVICES_PAIRED_HISTORY.equals(spName) || BT_HEARABLE_DEVICES_PAIRED_HISTORY.equals(spName)) { LinkedList<Long> history = convertToHistoryList( getSharedPreferences(context).getString(spName, "")); removeRecordsBeforeDay(history, PAIRED_HISTORY_EXPIRED_DAY); return history; } else if (BT_HEARING_AIDS_CONNECTED_HISTORY.equals(spName) } else if (BT_HEARING_DEVICES_CONNECTED_HISTORY.equals(spName) || BT_HEARABLE_DEVICES_CONNECTED_HISTORY.equals(spName)) { LinkedList<Long> history = convertToHistoryList( getSharedPreferences(context).getString(spName, "")); Loading Loading @@ -333,6 +340,23 @@ public final class HearingAidStatsLogUtils { return Math.abs(ChronoUnit.DAYS.between(date1, date2)); } private static boolean isHearingDevice(CachedBluetoothDevice device) { return device.getProfiles().stream().anyMatch(HearingAidStatsLogUtils::isHearingProfile); } private static boolean isHearingProfile(LocalBluetoothProfile profile) { return profile instanceof HearingAidProfile || profile instanceof HapClientProfile; } private static boolean isHearableDevice(CachedBluetoothDevice device) { return device.getProfiles().stream().anyMatch(HearingAidStatsLogUtils::isHearableProfile); } private static boolean isHearableProfile(LocalBluetoothProfile profile) { return profile instanceof A2dpProfile || profile instanceof HeadsetProfile || profile instanceof LeAudioProfile; } private static SharedPreferences getSharedPreferences(Context context) { return context.getSharedPreferences(ACCESSIBILITY_PREFERENCE, Context.MODE_PRIVATE); } Loading @@ -341,13 +365,14 @@ public final class HearingAidStatsLogUtils { static { HISTORY_TYPE_TO_SP_NAME_MAPPING = new HashMap<>(); HISTORY_TYPE_TO_SP_NAME_MAPPING.put( HistoryType.TYPE_HEARING_AIDS_PAIRED, BT_HEARING_AIDS_PAIRED_HISTORY); HistoryType.TYPE_HEARING_DEVICES_PAIRED, BT_HEARING_DEVICES_PAIRED_HISTORY); HISTORY_TYPE_TO_SP_NAME_MAPPING.put( HistoryType.TYPE_HEARING_AIDS_CONNECTED, BT_HEARING_AIDS_CONNECTED_HISTORY); HistoryType.TYPE_HEARING_DEVICES_CONNECTED, BT_HEARING_DEVICES_CONNECTED_HISTORY); HISTORY_TYPE_TO_SP_NAME_MAPPING.put( HistoryType.TYPE_HEARABLE_DEVICES_PAIRED, BT_HEARABLE_DEVICES_PAIRED_HISTORY); HISTORY_TYPE_TO_SP_NAME_MAPPING.put( HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED, BT_HEARABLE_DEVICES_CONNECTED_HISTORY); } private HearingAidStatsLogUtils() {} } packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java +81 −13 Original line number Diff line number Diff line Loading @@ -21,8 +21,11 @@ import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.PAIRED_H import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.bluetooth.BluetoothProfile; import android.content.Context; import androidx.test.core.app.ApplicationProvider; Loading @@ -42,6 +45,7 @@ import java.time.LocalDate; import java.time.ZoneId; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; @RunWith(RobolectricTestRunner.class) Loading @@ -49,7 +53,7 @@ public class HearingAidStatsLogUtilsTest { private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1"; private static final int TEST_HISTORY_TYPE = HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_AIDS_CONNECTED; HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED; @Rule public final MockitoRule mockito = MockitoJUnit.rule(); Loading Loading @@ -128,20 +132,20 @@ public class HearingAidStatsLogUtilsTest { } @Test public void getUserCategory_hearingAidsUser() { prepareHearingAidsUserHistory(); public void getUserCategory_hearingDevicesUser() { prepareHearingDevicesUserHistory(); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_HEARING_AIDS); HearingAidStatsLogUtils.CATEGORY_HEARING_DEVICES); } @Test public void getUserCategory_newHearingAidsUser() { prepareHearingAidsUserHistory(); public void getUserCategory_newHearingDevicesUser() { prepareHearingDevicesUserHistory(); prepareNewUserHistory(); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_NEW_HEARING_AIDS); HearingAidStatsLogUtils.CATEGORY_NEW_HEARING_DEVICES); } @Test Loading @@ -162,12 +166,56 @@ public class HearingAidStatsLogUtilsTest { } @Test public void getUserCategory_bothHearingAidsAndHearableDevicesUser_returnHearingAidsUser() { prepareHearingAidsUserHistory(); public void getUserCategory_bothHearingAndHearableDevicesUser_returnHearingDevicesUser() { prepareHearingDevicesUserHistory(); prepareHearableDevicesUserHistory(); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_HEARING_AIDS); HearingAidStatsLogUtils.CATEGORY_HEARING_DEVICES); } @Test public void updateHistoryIfNeeded_ashaHearingDevice_ashaConnected_historyCorrect() { prepareAshaHearingDevice(); HearingAidProfile ashaProfile = mock(HearingAidProfile.class); HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, ashaProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED, 1); } @Test public void updateHistoryIfNeeded_leAudioHearingDevice_hapClientConnected_historyCorrect() { prepareLeAudioHearingDevice(); HapClientProfile hapClientProfile = mock(HapClientProfile.class); HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, hapClientProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED, 1); } @Test public void updateHistoryIfNeeded_leAudioHearingDevice_leAudioConnected_historyCorrect() { prepareLeAudioHearingDevice(); LeAudioProfile leAudioProfile = mock(LeAudioProfile.class); HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, leAudioProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED, 0); } @Test public void updateHistoryIfNeeded_hearableDevice_leAudioConnected_historyCorrect() { prepareHearableDevice(); LeAudioProfile leAudioProfile = mock(LeAudioProfile.class); HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, leAudioProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED, 1); } private long convertToStartOfDayTime(long timestamp) { Loading @@ -176,12 +224,12 @@ public class HearingAidStatsLogUtilsTest { return date.atStartOfDay(zoneId).toInstant().toEpochMilli(); } private void prepareHearingAidsUserHistory() { private void prepareHearingDevicesUserHistory() { final long todayStartOfDay = convertToStartOfDayTime(System.currentTimeMillis()); for (int i = CONNECTED_HISTORY_EXPIRED_DAY - 1; i >= 0; i--) { final long data = todayStartOfDay - TimeUnit.DAYS.toMillis(i); HearingAidStatsLogUtils.addToHistory(mContext, HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_AIDS_CONNECTED, data); HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED, data); } } Loading @@ -198,8 +246,28 @@ public class HearingAidStatsLogUtilsTest { final long todayStartOfDay = convertToStartOfDayTime(System.currentTimeMillis()); final long data = todayStartOfDay - TimeUnit.DAYS.toMillis(PAIRED_HISTORY_EXPIRED_DAY - 1); HearingAidStatsLogUtils.addToHistory(mContext, HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_AIDS_PAIRED, data); HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_PAIRED, data); HearingAidStatsLogUtils.addToHistory(mContext, HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_PAIRED, data); } private void prepareAshaHearingDevice() { doReturn(List.of(mock(HearingAidProfile.class))).when(mCachedBluetoothDevice).getProfiles(); } private void prepareLeAudioHearingDevice() { doReturn(List.of(mock(HapClientProfile.class), mock(LeAudioProfile.class))).when( mCachedBluetoothDevice).getProfiles(); } private void prepareHearableDevice() { doReturn(List.of(mock(A2dpProfile.class), mock(HeadsetProfile.class), mock(LeAudioProfile.class))).when(mCachedBluetoothDevice).getProfiles(); } private void assertHistorySize(int type, int size) { LinkedList<Long> history = HearingAidStatsLogUtils.getHistory(mContext, type); assertThat(history).isNotNull(); assertThat(history.size()).isEqualTo(size); } } Loading
packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java +55 −30 Original line number Diff line number Diff line Loading @@ -45,16 +45,25 @@ public final class HearingAidStatsLogUtils { private static final String TAG = "HearingAidStatsLogUtils"; private static final boolean DEBUG = true; private static final String ACCESSIBILITY_PREFERENCE = "accessibility_prefs"; private static final String BT_HEARING_AIDS_PAIRED_HISTORY = "bt_hearing_aids_paired_history"; private static final String BT_HEARING_AIDS_CONNECTED_HISTORY = private static final String BT_HEARING_DEVICES_PAIRED_HISTORY = "bt_hearing_aids_paired_history"; private static final String BT_HEARING_DEVICES_CONNECTED_HISTORY = "bt_hearing_aids_connected_history"; // The values here actually represent Bluetooth hearable devices, but were mistyped // as hearing devices in the string value previously. Keep the string values to ensure record // persistence. private static final String BT_HEARABLE_DEVICES_PAIRED_HISTORY = "bt_hearing_devices_paired_history"; private static final String BT_HEARABLE_DEVICES_CONNECTED_HISTORY = "bt_hearing_devices_connected_history"; private static final String HISTORY_RECORD_DELIMITER = ","; static final String CATEGORY_HEARING_AIDS = "A11yHearingAidsUser"; static final String CATEGORY_NEW_HEARING_AIDS = "A11yNewHearingAidsUser"; static final String CATEGORY_HEARING_DEVICES = "A11yHearingAidsUser"; static final String CATEGORY_NEW_HEARING_DEVICES = "A11yNewHearingAidsUser"; // Previously, 'hearable device' was incorrectly entered as 'hearing device'. These string // values are maintained to ensure records persistence. static final String CATEGORY_HEARABLE_DEVICES = "A11yHearingDevicesUser"; static final String CATEGORY_NEW_HEARABLE_DEVICES = "A11yNewHearingDevicesUser"; Loading @@ -69,14 +78,14 @@ public final class HearingAidStatsLogUtils { @Retention(RetentionPolicy.SOURCE) @IntDef({ HistoryType.TYPE_UNKNOWN, HistoryType.TYPE_HEARING_AIDS_PAIRED, HistoryType.TYPE_HEARING_AIDS_CONNECTED, HistoryType.TYPE_HEARING_DEVICES_PAIRED, HistoryType.TYPE_HEARING_DEVICES_CONNECTED, HistoryType.TYPE_HEARABLE_DEVICES_PAIRED, HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED}) public @interface HistoryType { int TYPE_UNKNOWN = -1; int TYPE_HEARING_AIDS_PAIRED = 0; int TYPE_HEARING_AIDS_CONNECTED = 1; int TYPE_HEARING_DEVICES_PAIRED = 0; int TYPE_HEARING_DEVICES_CONNECTED = 1; int TYPE_HEARABLE_DEVICES_PAIRED = 2; int TYPE_HEARABLE_DEVICES_CONNECTED = 3; } Loading Loading @@ -137,27 +146,25 @@ public final class HearingAidStatsLogUtils { LocalBluetoothProfile profile, int profileState) { if (isJustBonded(cachedDevice.getAddress())) { // Saves bonded timestamp as the source for judging whether to display // the survey if (cachedDevice.getProfiles().stream().anyMatch( p -> (p instanceof HearingAidProfile || p instanceof HapClientProfile))) { // Saves bonded timestamp as the source for judging whether to display the survey if (isHearingDevice(cachedDevice)) { HearingAidStatsLogUtils.addCurrentTimeToHistory(context, HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_AIDS_PAIRED); } else if (cachedDevice.getProfiles().stream().anyMatch( p -> (p instanceof A2dpSinkProfile || p instanceof HeadsetProfile))) { HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_PAIRED); } else if (isHearableDevice(cachedDevice)) { HearingAidStatsLogUtils.addCurrentTimeToHistory(context, HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_PAIRED); } removeFromJustBonded(cachedDevice.getAddress()); } // Saves connected timestamp as the source for judging whether to display // the survey if (profileState == BluetoothProfile.STATE_CONNECTED) { if (profile instanceof HearingAidProfile || profile instanceof HapClientProfile) { // Saves connected timestamp as the source for judging whether to display the survey if (isHearingProfile(profile)) { HearingAidStatsLogUtils.addCurrentTimeToHistory(context, HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_AIDS_CONNECTED); } else if (profile instanceof A2dpSinkProfile || profile instanceof HeadsetProfile) { HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED); } else if (isHearableProfile(profile) && !isHearingDevice(cachedDevice)) { // Hearing devices may contain some hearable profiles as well, make sure to exclude // these cases when update hearable connected history. HearingAidStatsLogUtils.addCurrentTimeToHistory(context, HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED); } Loading @@ -166,8 +173,8 @@ public final class HearingAidStatsLogUtils { /** * Returns the user category if the user is already categorized. Otherwise, checks the * history and sees if the user is categorized as one of {@link #CATEGORY_HEARING_AIDS}, * {@link #CATEGORY_NEW_HEARING_AIDS}, {@link #CATEGORY_HEARABLE_DEVICES}, and * history and sees if the user is categorized as one of {@link #CATEGORY_HEARING_DEVICES}, * {@link #CATEGORY_NEW_HEARING_DEVICES}, {@link #CATEGORY_HEARABLE_DEVICES}, and * {@link #CATEGORY_NEW_HEARABLE_DEVICES}. * * @param context the request context Loading @@ -175,19 +182,19 @@ public final class HearingAidStatsLogUtils { */ public static synchronized String getUserCategory(Context context) { LinkedList<Long> hearingAidsConnectedHistory = getHistory(context, HistoryType.TYPE_HEARING_AIDS_CONNECTED); HistoryType.TYPE_HEARING_DEVICES_CONNECTED); if (hearingAidsConnectedHistory != null && hearingAidsConnectedHistory.size() >= VALID_CONNECTED_EVENT_COUNT) { LinkedList<Long> hearingAidsPairedHistory = getHistory(context, HistoryType.TYPE_HEARING_AIDS_PAIRED); HistoryType.TYPE_HEARING_DEVICES_PAIRED); // Since paired history will be cleared after 30 days. If there's any record within 30 // days, the user will be categorized as CATEGORY_NEW_HEARING_AIDS. Otherwise, the user // will be categorized as CATEGORY_HEARING_AIDS. if (hearingAidsPairedHistory != null && hearingAidsPairedHistory.size() >= VALID_PAIRED_EVENT_COUNT) { return CATEGORY_NEW_HEARING_AIDS; return CATEGORY_NEW_HEARING_DEVICES; } else { return CATEGORY_HEARING_AIDS; return CATEGORY_HEARING_DEVICES; } } Loading Loading @@ -271,13 +278,13 @@ public final class HearingAidStatsLogUtils { @Nullable static synchronized LinkedList<Long> getHistory(Context context, @HistoryType int type) { String spName = HISTORY_TYPE_TO_SP_NAME_MAPPING.get(type); if (BT_HEARING_AIDS_PAIRED_HISTORY.equals(spName) if (BT_HEARING_DEVICES_PAIRED_HISTORY.equals(spName) || BT_HEARABLE_DEVICES_PAIRED_HISTORY.equals(spName)) { LinkedList<Long> history = convertToHistoryList( getSharedPreferences(context).getString(spName, "")); removeRecordsBeforeDay(history, PAIRED_HISTORY_EXPIRED_DAY); return history; } else if (BT_HEARING_AIDS_CONNECTED_HISTORY.equals(spName) } else if (BT_HEARING_DEVICES_CONNECTED_HISTORY.equals(spName) || BT_HEARABLE_DEVICES_CONNECTED_HISTORY.equals(spName)) { LinkedList<Long> history = convertToHistoryList( getSharedPreferences(context).getString(spName, "")); Loading Loading @@ -333,6 +340,23 @@ public final class HearingAidStatsLogUtils { return Math.abs(ChronoUnit.DAYS.between(date1, date2)); } private static boolean isHearingDevice(CachedBluetoothDevice device) { return device.getProfiles().stream().anyMatch(HearingAidStatsLogUtils::isHearingProfile); } private static boolean isHearingProfile(LocalBluetoothProfile profile) { return profile instanceof HearingAidProfile || profile instanceof HapClientProfile; } private static boolean isHearableDevice(CachedBluetoothDevice device) { return device.getProfiles().stream().anyMatch(HearingAidStatsLogUtils::isHearableProfile); } private static boolean isHearableProfile(LocalBluetoothProfile profile) { return profile instanceof A2dpProfile || profile instanceof HeadsetProfile || profile instanceof LeAudioProfile; } private static SharedPreferences getSharedPreferences(Context context) { return context.getSharedPreferences(ACCESSIBILITY_PREFERENCE, Context.MODE_PRIVATE); } Loading @@ -341,13 +365,14 @@ public final class HearingAidStatsLogUtils { static { HISTORY_TYPE_TO_SP_NAME_MAPPING = new HashMap<>(); HISTORY_TYPE_TO_SP_NAME_MAPPING.put( HistoryType.TYPE_HEARING_AIDS_PAIRED, BT_HEARING_AIDS_PAIRED_HISTORY); HistoryType.TYPE_HEARING_DEVICES_PAIRED, BT_HEARING_DEVICES_PAIRED_HISTORY); HISTORY_TYPE_TO_SP_NAME_MAPPING.put( HistoryType.TYPE_HEARING_AIDS_CONNECTED, BT_HEARING_AIDS_CONNECTED_HISTORY); HistoryType.TYPE_HEARING_DEVICES_CONNECTED, BT_HEARING_DEVICES_CONNECTED_HISTORY); HISTORY_TYPE_TO_SP_NAME_MAPPING.put( HistoryType.TYPE_HEARABLE_DEVICES_PAIRED, BT_HEARABLE_DEVICES_PAIRED_HISTORY); HISTORY_TYPE_TO_SP_NAME_MAPPING.put( HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED, BT_HEARABLE_DEVICES_CONNECTED_HISTORY); } private HearingAidStatsLogUtils() {} }
packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java +81 −13 Original line number Diff line number Diff line Loading @@ -21,8 +21,11 @@ import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.PAIRED_H import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.bluetooth.BluetoothProfile; import android.content.Context; import androidx.test.core.app.ApplicationProvider; Loading @@ -42,6 +45,7 @@ import java.time.LocalDate; import java.time.ZoneId; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; @RunWith(RobolectricTestRunner.class) Loading @@ -49,7 +53,7 @@ public class HearingAidStatsLogUtilsTest { private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1"; private static final int TEST_HISTORY_TYPE = HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_AIDS_CONNECTED; HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED; @Rule public final MockitoRule mockito = MockitoJUnit.rule(); Loading Loading @@ -128,20 +132,20 @@ public class HearingAidStatsLogUtilsTest { } @Test public void getUserCategory_hearingAidsUser() { prepareHearingAidsUserHistory(); public void getUserCategory_hearingDevicesUser() { prepareHearingDevicesUserHistory(); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_HEARING_AIDS); HearingAidStatsLogUtils.CATEGORY_HEARING_DEVICES); } @Test public void getUserCategory_newHearingAidsUser() { prepareHearingAidsUserHistory(); public void getUserCategory_newHearingDevicesUser() { prepareHearingDevicesUserHistory(); prepareNewUserHistory(); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_NEW_HEARING_AIDS); HearingAidStatsLogUtils.CATEGORY_NEW_HEARING_DEVICES); } @Test Loading @@ -162,12 +166,56 @@ public class HearingAidStatsLogUtilsTest { } @Test public void getUserCategory_bothHearingAidsAndHearableDevicesUser_returnHearingAidsUser() { prepareHearingAidsUserHistory(); public void getUserCategory_bothHearingAndHearableDevicesUser_returnHearingDevicesUser() { prepareHearingDevicesUserHistory(); prepareHearableDevicesUserHistory(); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_HEARING_AIDS); HearingAidStatsLogUtils.CATEGORY_HEARING_DEVICES); } @Test public void updateHistoryIfNeeded_ashaHearingDevice_ashaConnected_historyCorrect() { prepareAshaHearingDevice(); HearingAidProfile ashaProfile = mock(HearingAidProfile.class); HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, ashaProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED, 1); } @Test public void updateHistoryIfNeeded_leAudioHearingDevice_hapClientConnected_historyCorrect() { prepareLeAudioHearingDevice(); HapClientProfile hapClientProfile = mock(HapClientProfile.class); HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, hapClientProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED, 1); } @Test public void updateHistoryIfNeeded_leAudioHearingDevice_leAudioConnected_historyCorrect() { prepareLeAudioHearingDevice(); LeAudioProfile leAudioProfile = mock(LeAudioProfile.class); HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, leAudioProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED, 0); } @Test public void updateHistoryIfNeeded_hearableDevice_leAudioConnected_historyCorrect() { prepareHearableDevice(); LeAudioProfile leAudioProfile = mock(LeAudioProfile.class); HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, leAudioProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED, 1); } private long convertToStartOfDayTime(long timestamp) { Loading @@ -176,12 +224,12 @@ public class HearingAidStatsLogUtilsTest { return date.atStartOfDay(zoneId).toInstant().toEpochMilli(); } private void prepareHearingAidsUserHistory() { private void prepareHearingDevicesUserHistory() { final long todayStartOfDay = convertToStartOfDayTime(System.currentTimeMillis()); for (int i = CONNECTED_HISTORY_EXPIRED_DAY - 1; i >= 0; i--) { final long data = todayStartOfDay - TimeUnit.DAYS.toMillis(i); HearingAidStatsLogUtils.addToHistory(mContext, HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_AIDS_CONNECTED, data); HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED, data); } } Loading @@ -198,8 +246,28 @@ public class HearingAidStatsLogUtilsTest { final long todayStartOfDay = convertToStartOfDayTime(System.currentTimeMillis()); final long data = todayStartOfDay - TimeUnit.DAYS.toMillis(PAIRED_HISTORY_EXPIRED_DAY - 1); HearingAidStatsLogUtils.addToHistory(mContext, HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_AIDS_PAIRED, data); HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_PAIRED, data); HearingAidStatsLogUtils.addToHistory(mContext, HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_PAIRED, data); } private void prepareAshaHearingDevice() { doReturn(List.of(mock(HearingAidProfile.class))).when(mCachedBluetoothDevice).getProfiles(); } private void prepareLeAudioHearingDevice() { doReturn(List.of(mock(HapClientProfile.class), mock(LeAudioProfile.class))).when( mCachedBluetoothDevice).getProfiles(); } private void prepareHearableDevice() { doReturn(List.of(mock(A2dpProfile.class), mock(HeadsetProfile.class), mock(LeAudioProfile.class))).when(mCachedBluetoothDevice).getProfiles(); } private void assertHistorySize(int type, int size) { LinkedList<Long> history = HearingAidStatsLogUtils.getHistory(mContext, type); assertThat(history).isNotNull(); assertThat(history.size()).isEqualTo(size); } }