Define Utils.formatRelativeTime() and use it
Previously, relative times were formatted using formatElapsedTime()
(appending translations of "ago" to them), sometimes resulting in
grammatically hard-to-understand or unnatural localizations. Now we
use ICU's RelativeDateTimeFormatter, which uses grammatically correct
and natural localizations from CLDR data.
Bug: 64507689
Bug: 64605781
Bug: 64556849
Bug: 64550172
Test: make -j RunSettingsRoboTests
Change-Id: Ia2d098b190ab99e7748ef6f03b919f5c6174ba7d
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 417ac0f..fa61cec 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -52,8 +52,11 @@
import android.graphics.BitmapFactory;
import android.hardware.fingerprint.FingerprintManager;
import android.icu.text.MeasureFormat;
+import android.icu.text.RelativeDateTimeFormatter;
+import android.icu.text.RelativeDateTimeFormatter.RelativeUnit;
import android.icu.util.Measure;
import android.icu.util.MeasureUnit;
+import android.icu.util.ULocale;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.Network;
@@ -861,6 +864,48 @@
}
/**
+ * Returns relative time for the given millis in the past, in a short format such as "2 days
+ * ago", "5 hr. ago", "40 min. ago", or "29 sec. ago".
+ *
+ * <p>The unit is chosen to have good information value while only using one unit. So 27 hours
+ * and 50 minutes would be formatted as "28 hr. ago", while 50 hours would be formatted as
+ * "2 days ago".
+ *
+ * @param context the application context
+ * @param millis the elapsed time in milli seconds
+ * @param withSeconds include seconds?
+ * @return the formatted elapsed time
+ */
+ public static CharSequence formatRelativeTime(Context context, double millis,
+ boolean withSeconds) {
+ final int seconds = (int) Math.floor(millis / 1000);
+ final RelativeUnit unit;
+ final int value;
+ if (withSeconds && seconds < 2 * SECONDS_PER_MINUTE) {
+ unit = RelativeUnit.SECONDS;
+ value = seconds;
+ } else if (seconds < 2 * SECONDS_PER_HOUR) {
+ unit = RelativeUnit.MINUTES;
+ value = (seconds + SECONDS_PER_MINUTE / 2) / SECONDS_PER_MINUTE;
+ } else if (seconds < 2 * SECONDS_PER_DAY) {
+ unit = RelativeUnit.HOURS;
+ value = (seconds + SECONDS_PER_HOUR / 2) / SECONDS_PER_HOUR;
+ } else {
+ unit = RelativeUnit.DAYS;
+ value = (seconds + SECONDS_PER_DAY / 2) / SECONDS_PER_DAY;
+ }
+
+ final Locale locale = context.getResources().getConfiguration().locale;
+ final RelativeDateTimeFormatter formatter = RelativeDateTimeFormatter.getInstance(
+ ULocale.forLocale(locale),
+ null /* default NumberFormat */,
+ RelativeDateTimeFormatter.Style.SHORT,
+ android.icu.text.DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE);
+
+ return formatter.format(value, RelativeDateTimeFormatter.Direction.LAST, unit);
+ }
+
+ /**
* Queries for the UserInfo of a user. Returns null if the user doesn't exist (was removed).
* @param userManager Instance of UserManager
* @param checkUser The user to check the existence of.