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

Commit cefc86d2 authored by Caitlin Shkuratov's avatar Caitlin Shkuratov Committed by Android (Google) Code Review
Browse files

Merge "DateTimeView: Add additional display configuration options." into main

parents ac37f0f6 66e28940
Loading
Loading
Loading
Loading
+9 −1
Original line number Original line Diff line number Diff line
@@ -143,3 +143,11 @@ flag {
    bug: "294922229"
    bug: "294922229"
    is_fixed_read_only: true
    is_fixed_read_only: true
}
}

flag {
    name: "date_time_view_relative_time_display_configs"
    namespace: "systemui"
    description: "Enables DateTimeView to use additional display configurations for relative time"
    bug: "364653005"
    is_fixed_read_only: true
}
+198 −29
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.YEAR_IN_MILLIS;
import static android.text.format.DateUtils.YEAR_IN_MILLIS;


import android.annotation.IntDef;
import android.app.ActivityThread;
import android.app.ActivityThread;
import android.compat.annotation.UnsupportedAppUsage;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
import android.content.BroadcastReceiver;
@@ -41,6 +42,8 @@ import android.widget.RemoteViews.RemoteView;


import com.android.internal.R;
import com.android.internal.R;


import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.text.DateFormat;
import java.text.DateFormat;
import java.time.Instant;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDate;
@@ -70,6 +73,23 @@ public class DateTimeView extends TextView {
    private static final int SHOW_TIME = 0;
    private static final int SHOW_TIME = 0;
    private static final int SHOW_MONTH_DAY_YEAR = 1;
    private static final int SHOW_MONTH_DAY_YEAR = 1;


    /** @hide */
    @IntDef(value = {UNIT_DISPLAY_LENGTH_SHORTEST, UNIT_DISPLAY_LENGTH_MEDIUM})
    @Retention(RetentionPolicy.SOURCE)
    public @interface UnitDisplayLength {}
    public static final int UNIT_DISPLAY_LENGTH_SHORTEST = 0;
    public static final int UNIT_DISPLAY_LENGTH_MEDIUM = 1;

    /** @hide */
    @IntDef(flag = true, value = {DISAMBIGUATION_TEXT_PAST, DISAMBIGUATION_TEXT_FUTURE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface DisambiguationTextMask {}
    public static final int DISAMBIGUATION_TEXT_PAST = 0x01;
    public static final int DISAMBIGUATION_TEXT_FUTURE = 0x02;

    private final boolean mCanUseRelativeTimeDisplayConfigs =
            android.view.flags.Flags.dateTimeViewRelativeTimeDisplayConfigs();

    private long mTimeMillis;
    private long mTimeMillis;
    // The LocalDateTime equivalent of mTimeMillis but truncated to minute, i.e. no seconds / nanos.
    // The LocalDateTime equivalent of mTimeMillis but truncated to minute, i.e. no seconds / nanos.
    private LocalDateTime mLocalTime;
    private LocalDateTime mLocalTime;
@@ -81,6 +101,8 @@ public class DateTimeView extends TextView {
    private static final ThreadLocal<ReceiverInfo> sReceiverInfo = new ThreadLocal<ReceiverInfo>();
    private static final ThreadLocal<ReceiverInfo> sReceiverInfo = new ThreadLocal<ReceiverInfo>();
    private String mNowText;
    private String mNowText;
    private boolean mShowRelativeTime;
    private boolean mShowRelativeTime;
    private int mRelativeTimeDisambiguationTextMask;
    private int mRelativeTimeUnitDisplayLength = UNIT_DISPLAY_LENGTH_SHORTEST;


    public DateTimeView(Context context) {
    public DateTimeView(Context context) {
        this(context, null);
        this(context, null);
@@ -89,20 +111,23 @@ public class DateTimeView extends TextView {
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public DateTimeView(Context context, AttributeSet attrs) {
    public DateTimeView(Context context, AttributeSet attrs) {
        super(context, attrs);
        super(context, attrs);
        final TypedArray a = context.obtainStyledAttributes(attrs,
        final TypedArray a = context.obtainStyledAttributes(
                com.android.internal.R.styleable.DateTimeView, 0,
                attrs, R.styleable.DateTimeView, 0, 0);
                0);


        setShowRelativeTime(a.getBoolean(R.styleable.DateTimeView_showRelative, false));
        final int N = a.getIndexCount();
        if (mCanUseRelativeTimeDisplayConfigs) {
        for (int i = 0; i < N; i++) {
            setRelativeTimeDisambiguationTextMask(
            int attr = a.getIndex(i);
                    a.getInt(
            switch (attr) {
                            R.styleable.DateTimeView_relativeTimeDisambiguationText,
                case R.styleable.DateTimeView_showRelative:
                            // The original implementation showed disambiguation text for future
                    boolean relative = a.getBoolean(i, false);
                            // times only, so continue with that default.
                    setShowRelativeTime(relative);
                            DISAMBIGUATION_TEXT_FUTURE));
                    break;
            setRelativeTimeUnitDisplayLength(
            }
                    a.getInt(
                            R.styleable.DateTimeView_relativeTimeUnitDisplayLength,
                            UNIT_DISPLAY_LENGTH_SHORTEST));
        }
        }

        a.recycle();
        a.recycle();
    }
    }


@@ -150,6 +175,29 @@ public class DateTimeView extends TextView {
        update();
        update();
    }
    }


    /** See {@link R.styleable.DateTimeView_relativeTimeDisambiguationText}. */
    @android.view.RemotableViewMethod
    public void setRelativeTimeDisambiguationTextMask(
            @DisambiguationTextMask int disambiguationTextMask) {
        if (!mCanUseRelativeTimeDisplayConfigs) {
            return;
        }
        mRelativeTimeDisambiguationTextMask = disambiguationTextMask;
        updateNowText();
        update();
    }

    /** See {@link R.styleable.DateTimeView_relativeTimeUnitDisplayLength}. */
    @android.view.RemotableViewMethod
    public void setRelativeTimeUnitDisplayLength(@UnitDisplayLength int unitDisplayLength) {
        if (!mCanUseRelativeTimeDisplayConfigs) {
            return;
        }
        mRelativeTimeUnitDisplayLength = unitDisplayLength;
        updateNowText();
        update();
    }

    /**
    /**
     * Returns whether this view shows relative time
     * Returns whether this view shows relative time
     *
     *
@@ -264,17 +312,11 @@ public class DateTimeView extends TextView {
            return;
            return;
        } else if (duration < HOUR_IN_MILLIS) {
        } else if (duration < HOUR_IN_MILLIS) {
            count = (int)(duration / MINUTE_IN_MILLIS);
            count = (int)(duration / MINUTE_IN_MILLIS);
            result = getContext().getResources().getString(past
            result = getContext().getResources().getString(getMinutesStringId(past), count);
                    ? com.android.internal.R.string.duration_minutes_shortest
                    : com.android.internal.R.string.duration_minutes_shortest_future,
                    count);
            millisIncrease = MINUTE_IN_MILLIS;
            millisIncrease = MINUTE_IN_MILLIS;
        } else if (duration < DAY_IN_MILLIS) {
        } else if (duration < DAY_IN_MILLIS) {
            count = (int)(duration / HOUR_IN_MILLIS);
            count = (int)(duration / HOUR_IN_MILLIS);
            result = getContext().getResources().getString(past
            result = getContext().getResources().getString(getHoursStringId(past), count);
                            ? com.android.internal.R.string.duration_hours_shortest
                            : com.android.internal.R.string.duration_hours_shortest_future,
                            count);
            millisIncrease = HOUR_IN_MILLIS;
            millisIncrease = HOUR_IN_MILLIS;
        } else if (duration < YEAR_IN_MILLIS) {
        } else if (duration < YEAR_IN_MILLIS) {
            // In weird cases it can become 0 because of daylight savings
            // In weird cases it can become 0 because of daylight savings
@@ -283,10 +325,7 @@ public class DateTimeView extends TextView {
            LocalDateTime localNow = toLocalDateTime(now, zoneId);
            LocalDateTime localNow = toLocalDateTime(now, zoneId);


            count = Math.max(Math.abs(dayDistance(localDateTime, localNow)), 1);
            count = Math.max(Math.abs(dayDistance(localDateTime, localNow)), 1);
            result = getContext().getResources().getString(past
            result = getContext().getResources().getString(getDaysStringId(past), count);
                    ? com.android.internal.R.string.duration_days_shortest
                    : com.android.internal.R.string.duration_days_shortest_future,
                    count);
            if (past || count != 1) {
            if (past || count != 1) {
                mUpdateTimeMillis = computeNextMidnight(localNow, zoneId);
                mUpdateTimeMillis = computeNextMidnight(localNow, zoneId);
                millisIncrease = -1;
                millisIncrease = -1;
@@ -296,10 +335,7 @@ public class DateTimeView extends TextView {


        } else {
        } else {
            count = (int)(duration / YEAR_IN_MILLIS);
            count = (int)(duration / YEAR_IN_MILLIS);
            result = getContext().getResources().getString(past
            result = getContext().getResources().getString(getYearsStringId(past), count);
                    ? com.android.internal.R.string.duration_years_shortest
                    : com.android.internal.R.string.duration_years_shortest_future,
                    count);
            millisIncrease = YEAR_IN_MILLIS;
            millisIncrease = YEAR_IN_MILLIS;
        }
        }
        if (millisIncrease != -1) {
        if (millisIncrease != -1) {
@@ -312,6 +348,139 @@ public class DateTimeView extends TextView {
        maybeSetText(result);
        maybeSetText(result);
    }
    }


    private int getMinutesStringId(boolean past) {
        if (!mCanUseRelativeTimeDisplayConfigs) {
            return past
                    ? com.android.internal.R.string.duration_minutes_shortest
                    : com.android.internal.R.string.duration_minutes_shortest_future;
        }

        if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) {
            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
                // "1m ago"
                return com.android.internal.R.string.duration_minutes_shortest_past;
            } else if (!past
                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
                // "in 1m"
                return com.android.internal.R.string.duration_minutes_shortest_future;
            } else {
                // "1m"
                return com.android.internal.R.string.duration_minutes_shortest;
            }
        } else { // UNIT_DISPLAY_LENGTH_MEDIUM
            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
                // "1min ago"
                return com.android.internal.R.string.duration_minutes_medium_past;
            } else if (!past
                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
                // "in 1min"
                return com.android.internal.R.string.duration_minutes_medium_future;
            } else {
                // "1min"
                return com.android.internal.R.string.duration_minutes_medium;
            }
        }
    }

    private int getHoursStringId(boolean past) {
        if (!mCanUseRelativeTimeDisplayConfigs) {
            return past
                    ? com.android.internal.R.string.duration_hours_shortest
                    : com.android.internal.R.string.duration_hours_shortest_future;
        }
        if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) {
            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
                // "1h ago"
                return com.android.internal.R.string.duration_hours_shortest_past;
            } else if (!past
                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
                // "in 1h"
                return com.android.internal.R.string.duration_hours_shortest_future;
            } else {
                // "1h"
                return com.android.internal.R.string.duration_hours_shortest;
            }
        } else { // UNIT_DISPLAY_LENGTH_MEDIUM
            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
                // "1hr ago"
                return com.android.internal.R.string.duration_hours_medium_past;
            } else if (!past
                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
                // "in 1hr"
                return com.android.internal.R.string.duration_hours_medium_future;
            } else {
                // "1hr"
                return com.android.internal.R.string.duration_hours_medium;
            }
        }
    }

    private int getDaysStringId(boolean past) {
        if (!mCanUseRelativeTimeDisplayConfigs) {
            return past
                    ? com.android.internal.R.string.duration_days_shortest
                    : com.android.internal.R.string.duration_days_shortest_future;
        }
        if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) {
            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
                // "1d ago"
                return com.android.internal.R.string.duration_days_shortest_past;
            } else if (!past
                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
                // "in 1d"
                return com.android.internal.R.string.duration_days_shortest_future;
            } else {
                // "1d"
                return com.android.internal.R.string.duration_days_shortest;
            }
        } else { // UNIT_DISPLAY_LENGTH_MEDIUM
            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
                // "1d ago"
                return com.android.internal.R.string.duration_days_medium_past;
            } else if (!past
                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
                // "in 1d"
                return com.android.internal.R.string.duration_days_medium_future;
            } else {
                // "1d"
                return com.android.internal.R.string.duration_days_medium;
            }
        }
    }

    private int getYearsStringId(boolean past) {
        if (!mCanUseRelativeTimeDisplayConfigs) {
            return past
                    ? com.android.internal.R.string.duration_years_shortest
                    : com.android.internal.R.string.duration_years_shortest_future;
        }
        if (mRelativeTimeUnitDisplayLength == UNIT_DISPLAY_LENGTH_SHORTEST) {
            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
                // "1y ago"
                return com.android.internal.R.string.duration_years_shortest_past;
            } else if (!past
                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
                // "in 1y"
                return com.android.internal.R.string.duration_years_shortest_future;
            } else {
                // "1y"
                return com.android.internal.R.string.duration_years_shortest;
            }
        } else { // UNIT_DISPLAY_LENGTH_MEDIUM
            if (past && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_PAST) != 0) {
                // "1y ago"
                return com.android.internal.R.string.duration_years_medium_past;
            } else if (!past
                    && (mRelativeTimeDisambiguationTextMask & DISAMBIGUATION_TEXT_FUTURE) != 0) {
                // "in 1y"
                return com.android.internal.R.string.duration_years_medium_future;
            } else {
                // "1y"
                return com.android.internal.R.string.duration_years_medium;
            }
        }
    }

    /**
    /**
     * Sets text only if the text has actually changed. This prevents needles relayouts of this
     * Sets text only if the text has actually changed. This prevents needles relayouts of this
     * view when set to wrap_content.
     * view when set to wrap_content.
+26 −0
Original line number Original line Diff line number Diff line
@@ -10570,6 +10570,32 @@
    <declare-styleable name="DateTimeView">
    <declare-styleable name="DateTimeView">
        <attr name="showRelative" format="boolean" />
        <attr name="showRelative" format="boolean" />
        <!-- For relative times, controls what kinds of times get disambiguation text.
             The default value is "future".
             Does nothing if showRelative=false.
             -->
        <attr name="relativeTimeDisambiguationText">
            <!-- Times in the past will have extra clarifying text indicating that the time is in
                 the past. For example, 1 minute ago is represented as "1m ago". If this flag is not
                 set, times in the past are represented as just "1m". -->
            <flag name="past" value="0x01" />
            <!-- Times in the future will have extra clarifying text indicating that the time is in
                 the future. For example, 1 minute in the future is represented as "in 1m". If this
                 flag is not set, times in the future are represented as just "1m". -->
            <flag name="future" value="0x02" />
        </attr>
        <!-- For relative times, sets the length of the time unit displayed (minutes, hours, etc.).
             Does nothing if showRelative=false.
             -->
        <attr name="relativeTimeUnitDisplayLength">
            <!-- The time unit will be shown as a short as possible (1 character if possible). -->
            <enum name="shortest" value="0" />
            <!-- The time unit will be shortened to a medium length (2-3 characters in general). -->
            <enum name="medium" value="1" />
        </attr>
    </declare-styleable>
    </declare-styleable>
    <declare-styleable name="ResolverDrawerLayout_LayoutParams">
    <declare-styleable name="ResolverDrawerLayout_LayoutParams">
+80 −0
Original line number Original line Diff line number Diff line
@@ -3135,6 +3135,86 @@
        in <xliff:g id="count">%d</xliff:g>y
        in <xliff:g id="count">%d</xliff:g>y
    </string>
    </string>
    <!-- Phrase describing a time duration using minutes that is as short as possible, preferrably one character. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
    <string name="duration_minutes_shortest_past">
        <xliff:g id="count">%d</xliff:g>m ago
    </string>
    <!-- Phrase describing a time duration using hours that is as short as possible, preferrably one character. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
    <string name="duration_hours_shortest_past">
        <xliff:g id="count">%d</xliff:g>h ago
    </string>
    <!-- Phrase describing a time duration using days that is as short as possible, preferrably one character. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
    <string name="duration_days_shortest_past">
        <xliff:g example="1" id="count">%d</xliff:g>d ago
    </string>
    <!-- Phrase describing a time duration using years that is as short as possible, preferrably one character. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
    <string name="duration_years_shortest_past">
        <xliff:g id="count">%d</xliff:g>y ago
    </string>
    <!-- Phrase describing a time duration using minutes that is a medium length, preferrably two or three characters. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=8] -->
    <string name="duration_minutes_medium">
        <xliff:g id="count">%d</xliff:g>min
    </string>
    <!-- Phrase describing a time duration using hours that is a medium length, preferrably two or three characters. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=8] -->
    <string name="duration_hours_medium">
        <xliff:g id="count">%d</xliff:g>hr
    </string>
    <!-- Phrase describing a time duration using days that is a medium length, preferrably two or three characters. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=8] -->
    <string name="duration_days_medium">
       <xliff:g id="count">%d</xliff:g>d
    </string>
    <!-- Phrase describing a time duration using years that is a medium length, preferrably two or three characters. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=8] -->
    <string name="duration_years_medium">
        <xliff:g id="count">%d</xliff:g>yr
    </string>
    <!-- Phrase describing a time duration using minutes that is a medium length, preferrably two or three characters. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
    <string name="duration_minutes_medium_future">
        in <xliff:g id="count">%d</xliff:g>min
    </string>
    <!-- Phrase describing a time duration using hours that is a medium length, preferrably two or three characters. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
    <string name="duration_hours_medium_future">
        in <xliff:g id="count">%d</xliff:g>hr
    </string>
    <!-- Phrase describing a time duration using days that is a medium length, preferrably two or three characters. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
    <string name="duration_days_medium_future">
        in <xliff:g example="1" id="count">%d</xliff:g>d
    </string>
    <!-- Phrase describing a time duration using years that is a medium length, preferrably two or three characters. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
    <string name="duration_years_medium_future">
        in <xliff:g id="count">%d</xliff:g>yr
    </string>
    <!-- Phrase describing a time duration using minutes that is a medium length, preferrably two or three characters. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
    <string name="duration_minutes_medium_past">
        <xliff:g id="count">%d</xliff:g>min ago
    </string>
    <!-- Phrase describing a time duration using hours that is a medium length, preferrably two or three characters. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
    <string name="duration_hours_medium_past">
        <xliff:g id="count">%d</xliff:g>hr ago
    </string>
    <!-- Phrase describing a time duration using days that is a medium length, preferrably two or three characters. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
    <string name="duration_days_medium_past">
        <xliff:g example="1" id="count">%d</xliff:g>d ago
    </string>
    <!-- Phrase describing a time duration using years that is a medium length, preferrably two or three characters. This version should be a past point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=18] -->
    <string name="duration_years_medium_past">
        <xliff:g id="count">%d</xliff:g>yr ago
    </string>
    <!-- Phrase describing a relative time using minutes in the past that is not shown on the screen but used for accessibility. [CHAR LIMIT=NONE] -->
    <!-- Phrase describing a relative time using minutes in the past that is not shown on the screen but used for accessibility. [CHAR LIMIT=NONE] -->
    <string name="duration_minutes_relative">{count, plural,
    <string name="duration_minutes_relative">{count, plural,
        =1 {# minute ago}
        =1 {# minute ago}
+17 −0
Original line number Original line Diff line number Diff line
@@ -3367,6 +3367,23 @@
  <java-symbol type="string" name="duration_hours_shortest_future" />
  <java-symbol type="string" name="duration_hours_shortest_future" />
  <java-symbol type="string" name="duration_days_shortest_future" />
  <java-symbol type="string" name="duration_days_shortest_future" />
  <java-symbol type="string" name="duration_years_shortest_future" />
  <java-symbol type="string" name="duration_years_shortest_future" />
  <java-symbol type="string" name="duration_minutes_shortest_past" />
  <java-symbol type="string" name="duration_hours_shortest_past" />
  <java-symbol type="string" name="duration_days_shortest_past" />
  <java-symbol type="string" name="duration_years_shortest_past" />

  <java-symbol type="string" name="duration_minutes_medium" />
  <java-symbol type="string" name="duration_hours_medium" />
  <java-symbol type="string" name="duration_days_medium" />
  <java-symbol type="string" name="duration_years_medium" />
  <java-symbol type="string" name="duration_minutes_medium_future" />
  <java-symbol type="string" name="duration_hours_medium_future" />
  <java-symbol type="string" name="duration_days_medium_future" />
  <java-symbol type="string" name="duration_years_medium_future" />
  <java-symbol type="string" name="duration_minutes_medium_past" />
  <java-symbol type="string" name="duration_hours_medium_past" />
  <java-symbol type="string" name="duration_days_medium_past" />
  <java-symbol type="string" name="duration_years_medium_past" />


  <java-symbol type="string" name="duration_minutes_relative" />
  <java-symbol type="string" name="duration_minutes_relative" />
  <java-symbol type="string" name="duration_hours_relative" />
  <java-symbol type="string" name="duration_hours_relative" />
Loading