Use date difference to remove the expired data

Previously we use absolute milliseconds difference to remove the data
and it's not aligned with the assumption we made. Update to use the date
difference when removing the expired data.

Also, add more test cases for getUserCategory() method.

Test: atest HearingAidStatsLogUtilsTest
Bug: 325699522
Change-Id: I20fd2774c732cdc7fa16f81ff554e30a146d08f9
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java
index 200f49f..8e3df8b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtils.java
@@ -19,8 +19,6 @@
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
 import android.content.SharedPreferences;
-import android.icu.text.SimpleDateFormat;
-import android.icu.util.TimeZone;
 import android.util.Log;
 
 import androidx.annotation.IntDef;
@@ -31,12 +29,14 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.temporal.ChronoUnit;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
-import java.util.Locale;
 import java.util.Set;
-import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 /** Utils class to report hearing aid metrics to statsd */
@@ -55,13 +55,13 @@
     private static final String BT_HEARING_USER_CATEGORY = "bt_hearing_user_category";
 
     private static final String HISTORY_RECORD_DELIMITER = ",";
-    private static final String CATEGORY_HEARING_AIDS = "A11yHearingAidsUser";
-    private static final String CATEGORY_NEW_HEARING_AIDS = "A11yNewHearingAidsUser";
-    private static final String CATEGORY_HEARING_DEVICES = "A11yHearingDevicesUser";
-    private static final String CATEGORY_NEW_HEARING_DEVICES = "A11yNewHearingDevicesUser";
+    static final String CATEGORY_HEARING_AIDS = "A11yHearingAidsUser";
+    static final String CATEGORY_NEW_HEARING_AIDS = "A11yNewHearingAidsUser";
+    static final String CATEGORY_HEARING_DEVICES = "A11yHearingDevicesUser";
+    static final String CATEGORY_NEW_HEARING_DEVICES = "A11yNewHearingDevicesUser";
 
-    private static final long PAIRED_HISTORY_EXPIRED_TIME = TimeUnit.DAYS.toMillis(30);
-    private static final long CONNECTED_HISTORY_EXPIRED_TIME = TimeUnit.DAYS.toMillis(7);
+    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;
 
@@ -263,7 +263,7 @@
             }
             return;
         }
-        if (history.peekLast() != null && isSameDay(history.peekLast(), timestamp)) {
+        if (history.peekLast() != null && isSameDay(timestamp, history.peekLast())) {
             if (DEBUG) {
                 Log.w(TAG, "Skip this record, it's same day record");
             }
@@ -282,25 +282,25 @@
                 || BT_HEARING_DEVICES_PAIRED_HISTORY.equals(spName)) {
             LinkedList<Long> history = convertToHistoryList(
                     getSharedPreferences(context).getString(spName, ""));
-            removeRecordsBeforeTime(history, PAIRED_HISTORY_EXPIRED_TIME);
+            removeRecordsBeforeDay(history, PAIRED_HISTORY_EXPIRED_DAY);
             return history;
         } else if (BT_HEARING_AIDS_CONNECTED_HISTORY.equals(spName)
                 || BT_HEARING_DEVICES_CONNECTED_HISTORY.equals(spName)) {
             LinkedList<Long> history = convertToHistoryList(
                     getSharedPreferences(context).getString(spName, ""));
-            removeRecordsBeforeTime(history, CONNECTED_HISTORY_EXPIRED_TIME);
+            removeRecordsBeforeDay(history, CONNECTED_HISTORY_EXPIRED_DAY);
             return history;
         }
         return null;
     }
 
-    private static void removeRecordsBeforeTime(LinkedList<Long> history, long time) {
-        if (history == null) {
+    private static void removeRecordsBeforeDay(LinkedList<Long> history, int day) {
+        if (history == null || history.isEmpty()) {
             return;
         }
-        Long currentTime = System.currentTimeMillis();
+        long currentTime = System.currentTimeMillis();
         while (history.peekFirst() != null
-                && currentTime - history.peekFirst() > time) {
+                && dayDifference(currentTime, history.peekFirst()) >= day) {
             history.poll();
         }
     }
@@ -331,11 +331,13 @@
      * @return {@code true} if two timestamps are on the same day
      */
     private static boolean isSameDay(long t1, long t2) {
-        final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
-        sdf.setTimeZone(TimeZone.getDefault());
-        String dateString1 = sdf.format(t1);
-        String dateString2 = sdf.format(t2);
-        return dateString1.equals(dateString2);
+        return dayDifference(t1, t2) == 0;
+    }
+    private static long dayDifference(long t1, long t2) {
+        ZoneId zoneId = ZoneId.systemDefault();
+        LocalDate date1 = Instant.ofEpochMilli(t1).atZone(zoneId).toLocalDate();
+        LocalDate date2 = Instant.ofEpochMilli(t2).atZone(zoneId).toLocalDate();
+        return Math.abs(ChronoUnit.DAYS.between(date1, date2));
     }
 
     private static SharedPreferences getSharedPreferences(Context context) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java
index 8a75bdc..bd5a022 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidStatsLogUtilsTest.java
@@ -16,6 +16,9 @@
 
 package com.android.settingslib.bluetooth;
 
+import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.CONNECTED_HISTORY_EXPIRED_DAY;
+import static com.android.settingslib.bluetooth.HearingAidStatsLogUtils.PAIRED_HISTORY_EXPIRED_DAY;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.when;
@@ -34,6 +37,9 @@
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
 
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneId;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.concurrent.TimeUnit;
@@ -84,8 +90,8 @@
 
     @Test
     public void addCurrentTimeToHistory_addNewData() {
-        final long currentTime = System.currentTimeMillis();
-        final long lastData = currentTime - TimeUnit.DAYS.toMillis(2);
+        final long todayStartOfDay = convertToStartOfDayTime(System.currentTimeMillis());
+        final long lastData = todayStartOfDay - TimeUnit.DAYS.toMillis(6);
         HearingAidStatsLogUtils.addToHistory(mContext, TEST_HISTORY_TYPE, lastData);
 
         HearingAidStatsLogUtils.addCurrentTimeToHistory(mContext, TEST_HISTORY_TYPE);
@@ -96,22 +102,21 @@
     }
     @Test
     public void addCurrentTimeToHistory_skipSameDateData() {
-        final long currentTime = System.currentTimeMillis();
-        final long lastData = currentTime - 1;
-        HearingAidStatsLogUtils.addToHistory(mContext, TEST_HISTORY_TYPE, lastData);
+        final long todayStartOfDay = convertToStartOfDayTime(System.currentTimeMillis());
+        HearingAidStatsLogUtils.addToHistory(mContext, TEST_HISTORY_TYPE, todayStartOfDay);
 
         HearingAidStatsLogUtils.addCurrentTimeToHistory(mContext, TEST_HISTORY_TYPE);
 
         LinkedList<Long> history = HearingAidStatsLogUtils.getHistory(mContext, TEST_HISTORY_TYPE);
         assertThat(history).isNotNull();
         assertThat(history.size()).isEqualTo(1);
-        assertThat(history.getFirst()).isEqualTo(lastData);
+        assertThat(history.getFirst()).isEqualTo(todayStartOfDay);
     }
 
     @Test
     public void addCurrentTimeToHistory_cleanUpExpiredData() {
-        final long currentTime = System.currentTimeMillis();
-        final long expiredData = currentTime - TimeUnit.DAYS.toMillis(10);
+        final long todayStartOfDay = convertToStartOfDayTime(System.currentTimeMillis());
+        final long expiredData = todayStartOfDay - TimeUnit.DAYS.toMillis(6) - 1;
         HearingAidStatsLogUtils.addToHistory(mContext, TEST_HISTORY_TYPE, expiredData);
 
         HearingAidStatsLogUtils.addCurrentTimeToHistory(mContext, TEST_HISTORY_TYPE);
@@ -121,4 +126,71 @@
         assertThat(history.size()).isEqualTo(1);
         assertThat(history.getFirst()).isNotEqualTo(expiredData);
     }
+
+    @Test
+    public void getUserCategory_hearingAidsUser() {
+        prepareHearingAidsUserHistory();
+
+        assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo(
+                HearingAidStatsLogUtils.CATEGORY_HEARING_AIDS);
+    }
+
+    @Test
+    public void getUserCategory_newHearingAidsUser() {
+        prepareHearingAidsUserHistory();
+        prepareNewUserHistory();
+
+        assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo(
+                HearingAidStatsLogUtils.CATEGORY_NEW_HEARING_AIDS);
+    }
+
+    @Test
+    public void getUserCategory_hearingDevicesUser() {
+        prepareHearingDevicesUserHistory();
+
+        assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo(
+                HearingAidStatsLogUtils.CATEGORY_HEARING_DEVICES);
+    }
+
+    @Test
+    public void getUserCategory_newHearingDevicesUser() {
+        prepareHearingDevicesUserHistory();
+        prepareNewUserHistory();
+
+        assertThat(HearingAidStatsLogUtils.getUserCategory(mContext)).isEqualTo(
+                HearingAidStatsLogUtils.CATEGORY_NEW_HEARING_DEVICES);
+    }
+
+    private long convertToStartOfDayTime(long timestamp) {
+        ZoneId zoneId = ZoneId.systemDefault();
+        LocalDate date = Instant.ofEpochMilli(timestamp).atZone(zoneId).toLocalDate();
+        return date.atStartOfDay(zoneId).toInstant().toEpochMilli();
+    }
+
+    private void prepareHearingAidsUserHistory() {
+        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);
+        }
+    }
+
+    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 prepareNewUserHistory() {
+        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.addToHistory(mContext,
+                HearingAidStatsLogUtils.HistoryType.TYPE_HEARING_DEVICES_PAIRED, data);
+    }
 }