Loading packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java +71 −53 Original line number Diff line number Diff line Loading @@ -50,6 +50,8 @@ public final class HearingAidStatsLogUtils { "bt_hearing_aids_paired_history"; private static final String BT_HEARING_DEVICES_CONNECTED_HISTORY = "bt_hearing_aids_connected_history"; private static final String BT_LE_HEARING_DEVICES_CONNECTED_HISTORY = "bt_le_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. Loading @@ -57,19 +59,25 @@ public final class HearingAidStatsLogUtils { "bt_hearing_devices_paired_history"; private static final String BT_HEARABLE_DEVICES_CONNECTED_HISTORY = "bt_hearing_devices_connected_history"; private static final String BT_LE_HEARABLE_DEVICES_CONNECTED_HISTORY = "bt_le_hearing_devices_connected_history"; private static final String HISTORY_RECORD_DELIMITER = ","; 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_LE_HEARING_DEVICES = "A11yLeHearingAidsUser"; static final String CATEGORY_NEW_LE_HEARING_DEVICES = "A11yNewLeHearingAidsUser"; // 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. static final String CATEGORY_HEARABLE_DEVICES = "A11yHearingDevicesUser"; static final String CATEGORY_NEW_HEARABLE_DEVICES = "A11yNewHearingDevicesUser"; static final String CATEGORY_LE_HEARABLE_DEVICES = "A11yLeHearingDevicesUser"; static final String CATEGORY_NEW_LE_HEARABLE_DEVICES = "A11yNewLeHearingDevicesUser"; static final int PAIRED_HISTORY_EXPIRED_DAY = 30; static final int CONNECTED_HISTORY_EXPIRED_DAY = 7; private static final int VALID_PAIRED_EVENT_COUNT = 1; private static final int VALID_CONNECTED_EVENT_COUNT = 7; /** Loading @@ -81,13 +89,18 @@ public final class HearingAidStatsLogUtils { HistoryType.TYPE_HEARING_DEVICES_PAIRED, HistoryType.TYPE_HEARING_DEVICES_CONNECTED, HistoryType.TYPE_HEARABLE_DEVICES_PAIRED, HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED}) HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED, HistoryType.TYPE_LE_HEARING_CONNECTED, HistoryType.TYPE_LE_HEARABLE_CONNECTED, }) public @interface HistoryType { int TYPE_UNKNOWN = -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; int TYPE_LE_HEARING_CONNECTED = 4; int TYPE_LE_HEARABLE_CONNECTED = 5; } private static final HashMap<String, Integer> sDeviceAddressToBondEntryMap = new HashMap<>(); Loading Loading @@ -148,71 +161,56 @@ public final class HearingAidStatsLogUtils { if (isJustBonded(cachedDevice.getAddress())) { // Saves bonded timestamp as the source for judging whether to display the survey if (isHearingDevice(cachedDevice)) { HearingAidStatsLogUtils.addCurrentTimeToHistory(context, HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_PAIRED); addCurrentTimeToHistory(context, HistoryType.TYPE_HEARING_DEVICES_PAIRED); } else if (isHearableDevice(cachedDevice)) { HearingAidStatsLogUtils.addCurrentTimeToHistory(context, HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_PAIRED); addCurrentTimeToHistory(context, HistoryType.TYPE_HEARABLE_DEVICES_PAIRED); } removeFromJustBonded(cachedDevice.getAddress()); } if (profileState == BluetoothProfile.STATE_CONNECTED) { // Saves connected timestamp as the source for judging whether to display the survey if (isHearingProfile(profile)) { HearingAidStatsLogUtils.addCurrentTimeToHistory(context, 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); if (profile instanceof LeAudioProfile) { if (isHearingDevice(cachedDevice)) { addCurrentTimeToHistory(context, HistoryType.TYPE_LE_HEARING_CONNECTED); } else { addCurrentTimeToHistory(context, HistoryType.TYPE_LE_HEARABLE_CONNECTED); } } else if (isHearingProfile(profile)) { addCurrentTimeToHistory(context, HistoryType.TYPE_HEARING_DEVICES_CONNECTED); } else if (isHearableProfile(profile)) { addCurrentTimeToHistory(context, HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED); } } } /** * 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_DEVICES}, * {@link #CATEGORY_NEW_HEARING_DEVICES}, {@link #CATEGORY_HEARABLE_DEVICES}, and * {@link #CATEGORY_NEW_HEARABLE_DEVICES}. * Returns the user category based on different histories. * * @param context the request context * @return the category which user belongs to */ public static synchronized String getUserCategory(Context context) { LinkedList<Long> hearingAidsConnectedHistory = getHistory(context, HistoryType.TYPE_HEARING_DEVICES_CONNECTED); if (hearingAidsConnectedHistory != null && hearingAidsConnectedHistory.size() >= VALID_CONNECTED_EVENT_COUNT) { LinkedList<Long> hearingAidsPairedHistory = getHistory(context, boolean isNewPairedHearingUser = hasSufficientData(context, 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_DEVICES; } else { return CATEGORY_HEARING_DEVICES; boolean isNewPairedHearableUser = hasSufficientData(context, HistoryType.TYPE_HEARABLE_DEVICES_PAIRED); if (hasSufficientData(context, HistoryType.TYPE_LE_HEARING_CONNECTED)) { return isNewPairedHearingUser ? CATEGORY_NEW_LE_HEARING_DEVICES : CATEGORY_LE_HEARING_DEVICES; } if (hasSufficientData(context, HistoryType.TYPE_HEARING_DEVICES_CONNECTED)) { return isNewPairedHearingUser ? CATEGORY_NEW_HEARING_DEVICES : CATEGORY_HEARING_DEVICES; } LinkedList<Long> hearableDevicesConnectedHistory = getHistory(context, HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED); if (hearableDevicesConnectedHistory != null && hearableDevicesConnectedHistory.size() >= VALID_CONNECTED_EVENT_COUNT) { LinkedList<Long> hearableDevicesPairedHistory = getHistory(context, HistoryType.TYPE_HEARABLE_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_HEARABLE_DEVICES. Otherwise, the // user will be categorized as CATEGORY_HEARABLE_DEVICES. if (hearableDevicesPairedHistory != null && hearableDevicesPairedHistory.size() >= VALID_PAIRED_EVENT_COUNT) { return CATEGORY_NEW_HEARABLE_DEVICES; } else { return CATEGORY_HEARABLE_DEVICES; if (hasSufficientData(context, HistoryType.TYPE_LE_HEARABLE_CONNECTED)) { return isNewPairedHearableUser ? CATEGORY_NEW_LE_HEARABLE_DEVICES : CATEGORY_LE_HEARABLE_DEVICES; } if (hasSufficientData(context, HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED)) { return isNewPairedHearableUser ? CATEGORY_NEW_HEARABLE_DEVICES : CATEGORY_HEARABLE_DEVICES; } return ""; } Loading Loading @@ -265,7 +263,7 @@ public final class HearingAidStatsLogUtils { } if (history.peekLast() != null && isSameDay(timestamp, history.peekLast())) { if (DEBUG) { Log.w(TAG, "Skip this record, it's same day record"); Log.w(TAG, "Skip record of history type=" + type + ", it's same day record"); } return; } Loading @@ -285,7 +283,9 @@ public final class HearingAidStatsLogUtils { removeRecordsBeforeDay(history, PAIRED_HISTORY_EXPIRED_DAY); return history; } else if (BT_HEARING_DEVICES_CONNECTED_HISTORY.equals(spName) || BT_HEARABLE_DEVICES_CONNECTED_HISTORY.equals(spName)) { || BT_HEARABLE_DEVICES_CONNECTED_HISTORY.equals(spName) || BT_LE_HEARING_DEVICES_CONNECTED_HISTORY.equals(spName) || BT_LE_HEARABLE_DEVICES_CONNECTED_HISTORY.equals(spName)) { LinkedList<Long> history = convertToHistoryList( getSharedPreferences(context).getString(spName, "")); removeRecordsBeforeDay(history, CONNECTED_HISTORY_EXPIRED_DAY); Loading Loading @@ -357,6 +357,20 @@ public final class HearingAidStatsLogUtils { || profile instanceof LeAudioProfile; } private static boolean hasSufficientData(Context context, @HistoryType int historyType) { LinkedList<Long> history = getHistory(context, historyType); if (history == null) { return false; } if (historyType == HistoryType.TYPE_HEARING_DEVICES_PAIRED || historyType == HistoryType.TYPE_HEARABLE_DEVICES_PAIRED) { return !history.isEmpty(); } else { return history.size() >= VALID_CONNECTED_EVENT_COUNT; } } private static SharedPreferences getSharedPreferences(Context context) { return context.getSharedPreferences(ACCESSIBILITY_PREFERENCE, Context.MODE_PRIVATE); } Loading @@ -372,6 +386,10 @@ public final class HearingAidStatsLogUtils { 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); HISTORY_TYPE_TO_SP_NAME_MAPPING.put( HistoryType.TYPE_LE_HEARING_CONNECTED, BT_LE_HEARING_DEVICES_CONNECTED_HISTORY); HISTORY_TYPE_TO_SP_NAME_MAPPING.put( HistoryType.TYPE_LE_HEARABLE_CONNECTED, BT_LE_HEARABLE_DEVICES_CONNECTED_HISTORY); } private HearingAidStatsLogUtils() {} Loading packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java +64 −41 Original line number Diff line number Diff line Loading @@ -17,6 +17,12 @@ package com.android.settingslib.bluetooth; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.CONNECTED_HISTORY_EXPIRED_DAY; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_PAIRED; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_PAIRED; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.HistoryType.TYPE_LE_HEARABLE_CONNECTED; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.HistoryType.TYPE_LE_HEARING_CONNECTED; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.PAIRED_HISTORY_EXPIRED_DAY; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -52,8 +58,7 @@ import java.util.concurrent.TimeUnit; 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_DEVICES_CONNECTED; private static final int TEST_HISTORY_TYPE = TYPE_HEARING_DEVICES_CONNECTED; @Rule public final MockitoRule mockito = MockitoJUnit.rule(); Loading Loading @@ -132,43 +137,63 @@ public class HearingAidStatsLogUtilsTest { } @Test public void getUserCategory_hearingDevicesUser() { prepareHearingDevicesUserHistory(); public void getUserCategory_hearingDevices() { prepareConnectedHistory(TYPE_HEARING_DEVICES_CONNECTED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_HEARING_DEVICES); } @Test public void getUserCategory_newHearingDevicesUser() { prepareHearingDevicesUserHistory(); prepareNewUserHistory(); preparePairedHistory(TYPE_HEARING_DEVICES_PAIRED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_NEW_HEARING_DEVICES); } @Test public void getUserCategory_hearableDevicesUser() { prepareHearableDevicesUserHistory(); public void getUserCategory_hearableDevices() { prepareConnectedHistory(TYPE_HEARABLE_DEVICES_CONNECTED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_HEARABLE_DEVICES); preparePairedHistory(TYPE_HEARABLE_DEVICES_PAIRED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_NEW_HEARABLE_DEVICES); } @Test public void getUserCategory_newHearableDevicesUser() { prepareHearableDevicesUserHistory(); prepareNewUserHistory(); public void getUserCategory_leHearingDevices() { prepareConnectedHistory(TYPE_HEARING_DEVICES_CONNECTED); prepareConnectedHistory(TYPE_LE_HEARING_CONNECTED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_NEW_HEARABLE_DEVICES); HearingAidStatsLogUtils.CATEGORY_LE_HEARING_DEVICES); preparePairedHistory(TYPE_HEARING_DEVICES_PAIRED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_NEW_LE_HEARING_DEVICES); } @Test public void getUserCategory_leHearableDevices() { prepareConnectedHistory(TYPE_HEARABLE_DEVICES_CONNECTED); prepareConnectedHistory(TYPE_LE_HEARABLE_CONNECTED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_LE_HEARABLE_DEVICES); preparePairedHistory(TYPE_HEARABLE_DEVICES_PAIRED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_NEW_LE_HEARABLE_DEVICES); } @Test public void getUserCategory_bothHearingAndHearableDevicesUser_returnHearingDevicesUser() { prepareHearingDevicesUserHistory(); prepareHearableDevicesUserHistory(); public void getUserCategory_bothHearingAndHearableDevices_returnHearingDevicesUser() { prepareConnectedHistory(TYPE_HEARING_DEVICES_CONNECTED); prepareConnectedHistory(TYPE_HEARABLE_DEVICES_CONNECTED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_HEARING_DEVICES); Loading @@ -179,10 +204,10 @@ public class HearingAidStatsLogUtilsTest { prepareAshaHearingDevice(); HearingAidProfile ashaProfile = mock(HearingAidProfile.class); HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, ashaProfile, BluetoothProfile.STATE_CONNECTED); HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, ashaProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED, 1); assertHistorySize(TYPE_HEARING_DEVICES_CONNECTED, 1); } @Test Loading @@ -193,7 +218,7 @@ public class HearingAidStatsLogUtilsTest { HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, hapClientProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED, 1); assertHistorySize(TYPE_HEARING_DEVICES_CONNECTED, 1); } @Test Loading @@ -204,7 +229,18 @@ public class HearingAidStatsLogUtilsTest { HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, leAudioProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED, 0); assertHistorySize(TYPE_LE_HEARING_CONNECTED, 1); } @Test public void updateHistoryIfNeeded_hearableDevice_a2dpConnected_historyCorrect() { prepareHearableDevice(); A2dpProfile a2dpProfile = mock(A2dpProfile.class); HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, a2dpProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(TYPE_HEARABLE_DEVICES_CONNECTED, 1); } @Test Loading @@ -215,7 +251,7 @@ public class HearingAidStatsLogUtilsTest { HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, leAudioProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED, 1); assertHistorySize(TYPE_LE_HEARABLE_CONNECTED, 1); } private long convertToStartOfDayTime(long timestamp) { Loading @@ -224,31 +260,18 @@ public class HearingAidStatsLogUtilsTest { return date.atStartOfDay(zoneId).toInstant().toEpochMilli(); } 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_DEVICES_CONNECTED, data); } } private void prepareHearableDevicesUserHistory() { private void prepareConnectedHistory(int historyType) { 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_HEARABLE_DEVICES_CONNECTED, data); HearingAidStatsLogUtils.addToHistory(mContext, historyType, data); } } private void prepareNewUserHistory() { private void preparePairedHistory(int historyType) { 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_DEVICES_PAIRED, data); HearingAidStatsLogUtils.addToHistory(mContext, HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_PAIRED, data); HearingAidStatsLogUtils.addToHistory(mContext, historyType, data); } private void prepareAshaHearingDevice() { Loading Loading
packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java +71 −53 Original line number Diff line number Diff line Loading @@ -50,6 +50,8 @@ public final class HearingAidStatsLogUtils { "bt_hearing_aids_paired_history"; private static final String BT_HEARING_DEVICES_CONNECTED_HISTORY = "bt_hearing_aids_connected_history"; private static final String BT_LE_HEARING_DEVICES_CONNECTED_HISTORY = "bt_le_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. Loading @@ -57,19 +59,25 @@ public final class HearingAidStatsLogUtils { "bt_hearing_devices_paired_history"; private static final String BT_HEARABLE_DEVICES_CONNECTED_HISTORY = "bt_hearing_devices_connected_history"; private static final String BT_LE_HEARABLE_DEVICES_CONNECTED_HISTORY = "bt_le_hearing_devices_connected_history"; private static final String HISTORY_RECORD_DELIMITER = ","; 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_LE_HEARING_DEVICES = "A11yLeHearingAidsUser"; static final String CATEGORY_NEW_LE_HEARING_DEVICES = "A11yNewLeHearingAidsUser"; // 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. static final String CATEGORY_HEARABLE_DEVICES = "A11yHearingDevicesUser"; static final String CATEGORY_NEW_HEARABLE_DEVICES = "A11yNewHearingDevicesUser"; static final String CATEGORY_LE_HEARABLE_DEVICES = "A11yLeHearingDevicesUser"; static final String CATEGORY_NEW_LE_HEARABLE_DEVICES = "A11yNewLeHearingDevicesUser"; static final int PAIRED_HISTORY_EXPIRED_DAY = 30; static final int CONNECTED_HISTORY_EXPIRED_DAY = 7; private static final int VALID_PAIRED_EVENT_COUNT = 1; private static final int VALID_CONNECTED_EVENT_COUNT = 7; /** Loading @@ -81,13 +89,18 @@ public final class HearingAidStatsLogUtils { HistoryType.TYPE_HEARING_DEVICES_PAIRED, HistoryType.TYPE_HEARING_DEVICES_CONNECTED, HistoryType.TYPE_HEARABLE_DEVICES_PAIRED, HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED}) HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED, HistoryType.TYPE_LE_HEARING_CONNECTED, HistoryType.TYPE_LE_HEARABLE_CONNECTED, }) public @interface HistoryType { int TYPE_UNKNOWN = -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; int TYPE_LE_HEARING_CONNECTED = 4; int TYPE_LE_HEARABLE_CONNECTED = 5; } private static final HashMap<String, Integer> sDeviceAddressToBondEntryMap = new HashMap<>(); Loading Loading @@ -148,71 +161,56 @@ public final class HearingAidStatsLogUtils { if (isJustBonded(cachedDevice.getAddress())) { // Saves bonded timestamp as the source for judging whether to display the survey if (isHearingDevice(cachedDevice)) { HearingAidStatsLogUtils.addCurrentTimeToHistory(context, HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_PAIRED); addCurrentTimeToHistory(context, HistoryType.TYPE_HEARING_DEVICES_PAIRED); } else if (isHearableDevice(cachedDevice)) { HearingAidStatsLogUtils.addCurrentTimeToHistory(context, HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_PAIRED); addCurrentTimeToHistory(context, HistoryType.TYPE_HEARABLE_DEVICES_PAIRED); } removeFromJustBonded(cachedDevice.getAddress()); } if (profileState == BluetoothProfile.STATE_CONNECTED) { // Saves connected timestamp as the source for judging whether to display the survey if (isHearingProfile(profile)) { HearingAidStatsLogUtils.addCurrentTimeToHistory(context, 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); if (profile instanceof LeAudioProfile) { if (isHearingDevice(cachedDevice)) { addCurrentTimeToHistory(context, HistoryType.TYPE_LE_HEARING_CONNECTED); } else { addCurrentTimeToHistory(context, HistoryType.TYPE_LE_HEARABLE_CONNECTED); } } else if (isHearingProfile(profile)) { addCurrentTimeToHistory(context, HistoryType.TYPE_HEARING_DEVICES_CONNECTED); } else if (isHearableProfile(profile)) { addCurrentTimeToHistory(context, HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED); } } } /** * 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_DEVICES}, * {@link #CATEGORY_NEW_HEARING_DEVICES}, {@link #CATEGORY_HEARABLE_DEVICES}, and * {@link #CATEGORY_NEW_HEARABLE_DEVICES}. * Returns the user category based on different histories. * * @param context the request context * @return the category which user belongs to */ public static synchronized String getUserCategory(Context context) { LinkedList<Long> hearingAidsConnectedHistory = getHistory(context, HistoryType.TYPE_HEARING_DEVICES_CONNECTED); if (hearingAidsConnectedHistory != null && hearingAidsConnectedHistory.size() >= VALID_CONNECTED_EVENT_COUNT) { LinkedList<Long> hearingAidsPairedHistory = getHistory(context, boolean isNewPairedHearingUser = hasSufficientData(context, 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_DEVICES; } else { return CATEGORY_HEARING_DEVICES; boolean isNewPairedHearableUser = hasSufficientData(context, HistoryType.TYPE_HEARABLE_DEVICES_PAIRED); if (hasSufficientData(context, HistoryType.TYPE_LE_HEARING_CONNECTED)) { return isNewPairedHearingUser ? CATEGORY_NEW_LE_HEARING_DEVICES : CATEGORY_LE_HEARING_DEVICES; } if (hasSufficientData(context, HistoryType.TYPE_HEARING_DEVICES_CONNECTED)) { return isNewPairedHearingUser ? CATEGORY_NEW_HEARING_DEVICES : CATEGORY_HEARING_DEVICES; } LinkedList<Long> hearableDevicesConnectedHistory = getHistory(context, HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED); if (hearableDevicesConnectedHistory != null && hearableDevicesConnectedHistory.size() >= VALID_CONNECTED_EVENT_COUNT) { LinkedList<Long> hearableDevicesPairedHistory = getHistory(context, HistoryType.TYPE_HEARABLE_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_HEARABLE_DEVICES. Otherwise, the // user will be categorized as CATEGORY_HEARABLE_DEVICES. if (hearableDevicesPairedHistory != null && hearableDevicesPairedHistory.size() >= VALID_PAIRED_EVENT_COUNT) { return CATEGORY_NEW_HEARABLE_DEVICES; } else { return CATEGORY_HEARABLE_DEVICES; if (hasSufficientData(context, HistoryType.TYPE_LE_HEARABLE_CONNECTED)) { return isNewPairedHearableUser ? CATEGORY_NEW_LE_HEARABLE_DEVICES : CATEGORY_LE_HEARABLE_DEVICES; } if (hasSufficientData(context, HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED)) { return isNewPairedHearableUser ? CATEGORY_NEW_HEARABLE_DEVICES : CATEGORY_HEARABLE_DEVICES; } return ""; } Loading Loading @@ -265,7 +263,7 @@ public final class HearingAidStatsLogUtils { } if (history.peekLast() != null && isSameDay(timestamp, history.peekLast())) { if (DEBUG) { Log.w(TAG, "Skip this record, it's same day record"); Log.w(TAG, "Skip record of history type=" + type + ", it's same day record"); } return; } Loading @@ -285,7 +283,9 @@ public final class HearingAidStatsLogUtils { removeRecordsBeforeDay(history, PAIRED_HISTORY_EXPIRED_DAY); return history; } else if (BT_HEARING_DEVICES_CONNECTED_HISTORY.equals(spName) || BT_HEARABLE_DEVICES_CONNECTED_HISTORY.equals(spName)) { || BT_HEARABLE_DEVICES_CONNECTED_HISTORY.equals(spName) || BT_LE_HEARING_DEVICES_CONNECTED_HISTORY.equals(spName) || BT_LE_HEARABLE_DEVICES_CONNECTED_HISTORY.equals(spName)) { LinkedList<Long> history = convertToHistoryList( getSharedPreferences(context).getString(spName, "")); removeRecordsBeforeDay(history, CONNECTED_HISTORY_EXPIRED_DAY); Loading Loading @@ -357,6 +357,20 @@ public final class HearingAidStatsLogUtils { || profile instanceof LeAudioProfile; } private static boolean hasSufficientData(Context context, @HistoryType int historyType) { LinkedList<Long> history = getHistory(context, historyType); if (history == null) { return false; } if (historyType == HistoryType.TYPE_HEARING_DEVICES_PAIRED || historyType == HistoryType.TYPE_HEARABLE_DEVICES_PAIRED) { return !history.isEmpty(); } else { return history.size() >= VALID_CONNECTED_EVENT_COUNT; } } private static SharedPreferences getSharedPreferences(Context context) { return context.getSharedPreferences(ACCESSIBILITY_PREFERENCE, Context.MODE_PRIVATE); } Loading @@ -372,6 +386,10 @@ public final class HearingAidStatsLogUtils { 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); HISTORY_TYPE_TO_SP_NAME_MAPPING.put( HistoryType.TYPE_LE_HEARING_CONNECTED, BT_LE_HEARING_DEVICES_CONNECTED_HISTORY); HISTORY_TYPE_TO_SP_NAME_MAPPING.put( HistoryType.TYPE_LE_HEARABLE_CONNECTED, BT_LE_HEARABLE_DEVICES_CONNECTED_HISTORY); } private HearingAidStatsLogUtils() {} Loading
packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java +64 −41 Original line number Diff line number Diff line Loading @@ -17,6 +17,12 @@ package com.android.settingslib.bluetooth; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.CONNECTED_HISTORY_EXPIRED_DAY; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_PAIRED; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_PAIRED; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.HistoryType.TYPE_LE_HEARABLE_CONNECTED; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.HistoryType.TYPE_LE_HEARING_CONNECTED; import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.PAIRED_HISTORY_EXPIRED_DAY; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -52,8 +58,7 @@ import java.util.concurrent.TimeUnit; 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_DEVICES_CONNECTED; private static final int TEST_HISTORY_TYPE = TYPE_HEARING_DEVICES_CONNECTED; @Rule public final MockitoRule mockito = MockitoJUnit.rule(); Loading Loading @@ -132,43 +137,63 @@ public class HearingAidStatsLogUtilsTest { } @Test public void getUserCategory_hearingDevicesUser() { prepareHearingDevicesUserHistory(); public void getUserCategory_hearingDevices() { prepareConnectedHistory(TYPE_HEARING_DEVICES_CONNECTED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_HEARING_DEVICES); } @Test public void getUserCategory_newHearingDevicesUser() { prepareHearingDevicesUserHistory(); prepareNewUserHistory(); preparePairedHistory(TYPE_HEARING_DEVICES_PAIRED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_NEW_HEARING_DEVICES); } @Test public void getUserCategory_hearableDevicesUser() { prepareHearableDevicesUserHistory(); public void getUserCategory_hearableDevices() { prepareConnectedHistory(TYPE_HEARABLE_DEVICES_CONNECTED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_HEARABLE_DEVICES); preparePairedHistory(TYPE_HEARABLE_DEVICES_PAIRED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_NEW_HEARABLE_DEVICES); } @Test public void getUserCategory_newHearableDevicesUser() { prepareHearableDevicesUserHistory(); prepareNewUserHistory(); public void getUserCategory_leHearingDevices() { prepareConnectedHistory(TYPE_HEARING_DEVICES_CONNECTED); prepareConnectedHistory(TYPE_LE_HEARING_CONNECTED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_NEW_HEARABLE_DEVICES); HearingAidStatsLogUtils.CATEGORY_LE_HEARING_DEVICES); preparePairedHistory(TYPE_HEARING_DEVICES_PAIRED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_NEW_LE_HEARING_DEVICES); } @Test public void getUserCategory_leHearableDevices() { prepareConnectedHistory(TYPE_HEARABLE_DEVICES_CONNECTED); prepareConnectedHistory(TYPE_LE_HEARABLE_CONNECTED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_LE_HEARABLE_DEVICES); preparePairedHistory(TYPE_HEARABLE_DEVICES_PAIRED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_NEW_LE_HEARABLE_DEVICES); } @Test public void getUserCategory_bothHearingAndHearableDevicesUser_returnHearingDevicesUser() { prepareHearingDevicesUserHistory(); prepareHearableDevicesUserHistory(); public void getUserCategory_bothHearingAndHearableDevices_returnHearingDevicesUser() { prepareConnectedHistory(TYPE_HEARING_DEVICES_CONNECTED); prepareConnectedHistory(TYPE_HEARABLE_DEVICES_CONNECTED); assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo( HearingAidStatsLogUtils.CATEGORY_HEARING_DEVICES); Loading @@ -179,10 +204,10 @@ public class HearingAidStatsLogUtilsTest { prepareAshaHearingDevice(); HearingAidProfile ashaProfile = mock(HearingAidProfile.class); HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, ashaProfile, BluetoothProfile.STATE_CONNECTED); HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, ashaProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED, 1); assertHistorySize(TYPE_HEARING_DEVICES_CONNECTED, 1); } @Test Loading @@ -193,7 +218,7 @@ public class HearingAidStatsLogUtilsTest { HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, hapClientProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_CONNECTED, 1); assertHistorySize(TYPE_HEARING_DEVICES_CONNECTED, 1); } @Test Loading @@ -204,7 +229,18 @@ public class HearingAidStatsLogUtilsTest { HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, leAudioProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED, 0); assertHistorySize(TYPE_LE_HEARING_CONNECTED, 1); } @Test public void updateHistoryIfNeeded_hearableDevice_a2dpConnected_historyCorrect() { prepareHearableDevice(); A2dpProfile a2dpProfile = mock(A2dpProfile.class); HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, a2dpProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(TYPE_HEARABLE_DEVICES_CONNECTED, 1); } @Test Loading @@ -215,7 +251,7 @@ public class HearingAidStatsLogUtilsTest { HearingAidStatsLogUtils.updateHistoryIfNeeded(mContext, mCachedBluetoothDevice, leAudioProfile, BluetoothProfile.STATE_CONNECTED); assertHistorySize(HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_CONNECTED, 1); assertHistorySize(TYPE_LE_HEARABLE_CONNECTED, 1); } private long convertToStartOfDayTime(long timestamp) { Loading @@ -224,31 +260,18 @@ public class HearingAidStatsLogUtilsTest { return date.atStartOfDay(zoneId).toInstant().toEpochMilli(); } 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_DEVICES_CONNECTED, data); } } private void prepareHearableDevicesUserHistory() { private void prepareConnectedHistory(int historyType) { 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_HEARABLE_DEVICES_CONNECTED, data); HearingAidStatsLogUtils.addToHistory(mContext, historyType, data); } } private void prepareNewUserHistory() { private void preparePairedHistory(int historyType) { 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_DEVICES_PAIRED, data); HearingAidStatsLogUtils.addToHistory(mContext, HearingAidStatsLogUtils.HistoryType.TYPE_HEARABLE_DEVICES_PAIRED, data); HearingAidStatsLogUtils.addToHistory(mContext, historyType, data); } private void prepareAshaHearingDevice() { Loading