Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d5333f28 authored by Angela Wang's avatar Angela Wang
Browse files

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
parent 6b79fe8c
Loading
Loading
Loading
Loading
+24 −22
Original line number Diff line number Diff line
@@ -19,8 +19,6 @@ package com.android.settingslib.bluetooth;
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 com.android.internal.util.FrameworkStatsLog;

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 @@ public final class HearingAidStatsLogUtils {
    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 @@ public final class HearingAidStatsLogUtils {
            }
            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 @@ public final class HearingAidStatsLogUtils {
                || 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 @@ public final class HearingAidStatsLogUtils {
     * @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) {
+80 −8
Original line number Diff line number Diff line
@@ -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.MockitoJUnit;
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 @@ public class HearingAidStatsLogUtilsTest {

    @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 @@ public class HearingAidStatsLogUtilsTest {
    }
    @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 @@ public class HearingAidStatsLogUtilsTest {
        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);
    }
}