Merge "Add KEYCODE_CAPTIONS mapping to LKC KEY_SUBTITLE"
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..03af56d
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+
+AccessModifierOffset: -4
+AlignOperands: false
+AllowShortFunctionsOnASingleLine: Inline
+AlwaysBreakBeforeMultilineStrings: false
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ConstructorInitializerIndentWidth: 6
+ContinuationIndentWidth: 8
+IndentWidth: 4
+PenaltyBreakBeforeFirstCallParameter: 100000
+SpacesBeforeTrailingComments: 1
diff --git a/Android.mk b/Android.mk
index d853248..46529eb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -32,10 +32,6 @@
 # ============================================================
 include $(CLEAR_VARS)
 
-# This is used by ide.mk as the list of source files that are
-# always included.
-INTERNAL_SDK_SOURCE_DIRS := $(addprefix $(LOCAL_PATH)/,$(dirs_to_document))
-
 # sdk.atree needs to copy the whole dir: $(OUT_DOCS)/offline-sdk to the final zip.
 # So keep offline-sdk-timestamp target here, and unzip offline-sdk-docs.zip to
 # $(OUT_DOCS)/offline-sdk.
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 6831117..9abb308 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,3 +1,15 @@
+[Builtin Hooks]
+clang_format = true
+
+[Builtin Hooks Options]
+# Only turn on clang-format check for the following subfolders.
+clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+               cmds/hid/
+               cmds/input/
+               core/jni/
+               libs/input/
+               services/core/jni/
+
 [Hook Scripts]
 checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
 
diff --git a/api/current.txt b/api/current.txt
index f1338f0..8dd7af8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -41088,6 +41088,7 @@
     field public static final String EXTRA_KEY_ALIAS = "android.security.extra.KEY_ALIAS";
     field public static final String EXTRA_NAME = "name";
     field public static final String EXTRA_PKCS12 = "PKCS12";
+    field public static final String KEY_ALIAS_SELECTION_DENIED = "android:alias-selection-denied";
   }
 
   public interface KeyChainAliasCallback {
diff --git a/core/java/android/app/admin/DelegatedAdminReceiver.java b/core/java/android/app/admin/DelegatedAdminReceiver.java
index f66de8d..25b8eab 100644
--- a/core/java/android/app/admin/DelegatedAdminReceiver.java
+++ b/core/java/android/app/admin/DelegatedAdminReceiver.java
@@ -63,6 +63,10 @@
      * Allows this receiver to select the alias for a private key and certificate pair for
      * authentication.  If this method returns null, the default {@link android.app.Activity} will
      * be shown that lets the user pick a private key and certificate pair.
+     * If this method returns {@link KeyChain#KEY_ALIAS_SELECTION_DENIED},
+     * the default {@link android.app.Activity} will not be shown and the user will not be allowed
+     * to pick anything. And the app, that called {@link KeyChain#choosePrivateKeyAlias}, will
+     * receive {@code null} back.
      *
      * <p> This callback is only applicable if the delegated app has
      * {@link DevicePolicyManager#DELEGATION_CERT_SELECTION} capability. Additionally, it must
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 4771fd8..e3a49f3 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -791,6 +791,10 @@
      * Allows this receiver to select the alias for a private key and certificate pair for
      * authentication. If this method returns null, the default {@link android.app.Activity} will be
      * shown that lets the user pick a private key and certificate pair.
+     * If this method returns {@link KeyChain#KEY_ALIAS_SELECTION_DENIED},
+     * the default {@link android.app.Activity} will not be shown and the user will not be allowed
+     * to pick anything. And the app, that called {@link KeyChain#choosePrivateKeyAlias}, will
+     * receive {@code null} back.
      *
      * @param context The running context as per {@link #onReceive}.
      * @param intent The received intent as per {@link #onReceive}.
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index ffe9ae9..a32b41f 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -127,18 +127,6 @@
     }
 
     /**
-     * Create a ProxyProperties that points at a PAC URL.
-     * @hide
-     */
-    public ProxyInfo(String pacFileUrl) {
-        mHost = LOCAL_HOST;
-        mPort = LOCAL_PORT;
-        mExclusionList = LOCAL_EXCL_LIST;
-        mParsedExclusionList = parseExclusionList(mExclusionList);
-        mPacFileUrl = Uri.parse(pacFileUrl);
-    }
-
-    /**
      * Only used in PacManager after Local Proxy is bound.
      * @hide
      */
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 683c747..4fe6752 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
+import android.icu.text.DateFormatSymbols;
 import android.icu.text.DateTimePatternGenerator;
 import android.provider.Settings;
 import android.text.SpannableStringBuilder;
@@ -475,6 +476,8 @@
         int count;
 
         LocaleData localeData = LocaleData.get(Locale.getDefault());
+        DateFormatSymbols dfs = getIcuDateFormatSymbols(Locale.getDefault());
+        String[] amPm = dfs.getAmPmStrings();
 
         int len = inFormat.length();
 
@@ -496,7 +499,7 @@
             switch (c) {
                 case 'A':
                 case 'a':
-                    replacement = localeData.amPm[inDate.get(Calendar.AM_PM) - Calendar.AM];
+                    replacement = amPm[inDate.get(Calendar.AM_PM) - Calendar.AM];
                     break;
                 case 'd':
                     replacement = zeroPad(inDate.get(Calendar.DATE), count);
@@ -678,4 +681,16 @@
     private static String zeroPad(int inValue, int inMinDigits) {
         return String.format(Locale.getDefault(), "%0" + inMinDigits + "d", inValue);
     }
+
+    /**
+     * We use Gregorian calendar for date formats in android.text.format and various UI widget
+     * historically. It's a utility method to get an {@link DateFormatSymbols} instance. Note that
+     * {@link DateFormatSymbols} has cache, and external cache is not needed unless same instance is
+     * requested repeatedly in the performance critical code.
+     *
+     * @hide
+     */
+    public static DateFormatSymbols getIcuDateFormatSymbols(Locale locale) {
+        return new DateFormatSymbols(android.icu.util.GregorianCalendar.class, locale);
+    }
 }
diff --git a/core/java/android/text/format/DateIntervalFormat.java b/core/java/android/text/format/DateIntervalFormat.java
new file mode 100644
index 0000000..de9ec7a
--- /dev/null
+++ b/core/java/android/text/format/DateIntervalFormat.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.format;
+
+import static android.text.format.DateUtils.FORMAT_SHOW_TIME;
+import static android.text.format.DateUtils.FORMAT_UTC;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
+import android.icu.util.Calendar;
+import android.icu.util.ULocale;
+import android.util.LruCache;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.text.FieldPosition;
+import java.util.TimeZone;
+
+/**
+ * A wrapper of {@link android.icu.text.DateIntervalFormat} used by {@link DateUtilsBridge}.
+ *
+ * @hide
+ */
+@VisibleForTesting(visibility = PACKAGE)
+public final class DateIntervalFormat {
+
+    private static final LruCache<String, android.icu.text.DateIntervalFormat> CACHED_FORMATTERS =
+            new LruCache<>(8);
+
+    private DateIntervalFormat() {
+    }
+
+    /**
+     * Format a date range.
+     */
+    @VisibleForTesting(visibility = PACKAGE)
+    public static String formatDateRange(long startMs, long endMs, int flags, String olsonId) {
+        if ((flags & FORMAT_UTC) != 0) {
+            olsonId = "UTC";
+        }
+        // We create a java.util.TimeZone here to use libcore's data and libcore's olson ID /
+        // pseudo-tz logic.
+        TimeZone tz = (olsonId != null) ? TimeZone.getTimeZone(olsonId) : TimeZone.getDefault();
+        android.icu.util.TimeZone icuTimeZone = DateUtilsBridge.icuTimeZone(tz);
+        ULocale icuLocale = ULocale.getDefault();
+        return formatDateRange(icuLocale, icuTimeZone, startMs, endMs, flags);
+    }
+
+    /**
+     * Format a date range. This is our slightly more sensible internal API.
+     * A truly sane replacement would take a skeleton instead of int flags.
+     */
+    @VisibleForTesting(visibility = PACKAGE)
+    public static String formatDateRange(ULocale icuLocale, android.icu.util.TimeZone icuTimeZone,
+            long startMs, long endMs, int flags) {
+        Calendar startCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, startMs);
+        Calendar endCalendar;
+        if (startMs == endMs) {
+            endCalendar = startCalendar;
+        } else {
+            endCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, endMs);
+        }
+
+        // Special handling when the range ends at midnight:
+        // - If we're not showing times, and the range is non-empty, we fudge the end date so we
+        // don't count the day that's about to start.
+        // - If we are showing times, and the range ends at exactly 00:00 of the day following
+        // its start (which can be thought of as 24:00 the same day), we fudge the end date so we
+        // don't show the dates --- unless the start is anything displayed as 00:00, in which case
+        // we include both dates to disambiguate.
+        // This is not the behavior of icu4j's DateIntervalFormat, but it's the required behavior
+        // of Android's DateUtils.formatDateRange.
+        if (isExactlyMidnight(endCalendar)) {
+            boolean showTime = (flags & FORMAT_SHOW_TIME) == FORMAT_SHOW_TIME;
+            boolean endsDayAfterStart = DateUtilsBridge.dayDistance(startCalendar, endCalendar)
+                    == 1;
+            if ((!showTime && startMs != endMs)
+                    || (endsDayAfterStart
+                    && !DateUtilsBridge.isDisplayMidnightUsingSkeleton(startCalendar))) {
+                endCalendar.add(Calendar.DAY_OF_MONTH, -1);
+            }
+        }
+
+        String skeleton = DateUtilsBridge.toSkeleton(startCalendar, endCalendar, flags);
+        synchronized (CACHED_FORMATTERS) {
+            android.icu.text.DateIntervalFormat formatter =
+                    getFormatter(skeleton, icuLocale, icuTimeZone);
+            return formatter.format(startCalendar, endCalendar, new StringBuffer(),
+                    new FieldPosition(0)).toString();
+        }
+    }
+
+    private static android.icu.text.DateIntervalFormat getFormatter(String skeleton, ULocale locale,
+            android.icu.util.TimeZone icuTimeZone) {
+        String key = skeleton + "\t" + locale + "\t" + icuTimeZone;
+        android.icu.text.DateIntervalFormat formatter = CACHED_FORMATTERS.get(key);
+        if (formatter != null) {
+            return formatter;
+        }
+        formatter = android.icu.text.DateIntervalFormat.getInstance(skeleton, locale);
+        formatter.setTimeZone(icuTimeZone);
+        CACHED_FORMATTERS.put(key, formatter);
+        return formatter;
+    }
+
+    private static boolean isExactlyMidnight(Calendar c) {
+        return c.get(Calendar.HOUR_OF_DAY) == 0
+                && c.get(Calendar.MINUTE) == 0
+                && c.get(Calendar.SECOND) == 0
+                && c.get(Calendar.MILLISECOND) == 0;
+    }
+}
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index b0253a0..f313fae 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -27,7 +27,6 @@
 
 import com.android.internal.R;
 
-import libcore.icu.DateIntervalFormat;
 import libcore.icu.LocaleData;
 
 import java.io.IOException;
@@ -223,7 +222,8 @@
      */
     @Deprecated
     public static String getAMPMString(int ampm) {
-        return LocaleData.get(Locale.getDefault()).amPm[ampm - Calendar.AM];
+        String[] amPm = DateFormat.getIcuDateFormatSymbols(Locale.getDefault()).getAmPmStrings();
+        return amPm[ampm - Calendar.AM];
     }
 
     /**
diff --git a/core/java/android/text/format/DateUtilsBridge.java b/core/java/android/text/format/DateUtilsBridge.java
index 370d999..92ec9cf 100644
--- a/core/java/android/text/format/DateUtilsBridge.java
+++ b/core/java/android/text/format/DateUtilsBridge.java
@@ -16,6 +16,20 @@
 
 package android.text.format;
 
+import static android.text.format.DateUtils.FORMAT_12HOUR;
+import static android.text.format.DateUtils.FORMAT_24HOUR;
+import static android.text.format.DateUtils.FORMAT_ABBREV_ALL;
+import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
+import static android.text.format.DateUtils.FORMAT_ABBREV_TIME;
+import static android.text.format.DateUtils.FORMAT_ABBREV_WEEKDAY;
+import static android.text.format.DateUtils.FORMAT_NO_MONTH_DAY;
+import static android.text.format.DateUtils.FORMAT_NO_YEAR;
+import static android.text.format.DateUtils.FORMAT_NUMERIC_DATE;
+import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
+import static android.text.format.DateUtils.FORMAT_SHOW_TIME;
+import static android.text.format.DateUtils.FORMAT_SHOW_WEEKDAY;
+import static android.text.format.DateUtils.FORMAT_SHOW_YEAR;
+
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
 
 import android.icu.util.Calendar;
@@ -33,24 +47,6 @@
  */
 @VisibleForTesting(visibility = PACKAGE)
 public final class DateUtilsBridge {
-    // These are all public API in DateUtils. There are others, but they're either for use with
-    // other methods (like FORMAT_ABBREV_RELATIVE), don't internationalize (like FORMAT_CAP_AMPM),
-    // or have never been implemented anyway.
-    public static final int FORMAT_SHOW_TIME = 0x00001;
-    public static final int FORMAT_SHOW_WEEKDAY = 0x00002;
-    public static final int FORMAT_SHOW_YEAR = 0x00004;
-    public static final int FORMAT_NO_YEAR = 0x00008;
-    public static final int FORMAT_SHOW_DATE = 0x00010;
-    public static final int FORMAT_NO_MONTH_DAY = 0x00020;
-    public static final int FORMAT_12HOUR = 0x00040;
-    public static final int FORMAT_24HOUR = 0x00080;
-    public static final int FORMAT_UTC = 0x02000;
-    public static final int FORMAT_ABBREV_TIME = 0x04000;
-    public static final int FORMAT_ABBREV_WEEKDAY = 0x08000;
-    public static final int FORMAT_ABBREV_MONTH = 0x10000;
-    public static final int FORMAT_NUMERIC_DATE = 0x20000;
-    public static final int FORMAT_ABBREV_RELATIVE = 0x40000;
-    public static final int FORMAT_ABBREV_ALL = 0x80000;
 
     /**
      * Creates an immutable ICU timezone backed by the specified libcore timezone data. At the time
diff --git a/core/java/android/text/format/RelativeDateTimeFormatter.java b/core/java/android/text/format/RelativeDateTimeFormatter.java
index c5bca17..9096469 100644
--- a/core/java/android/text/format/RelativeDateTimeFormatter.java
+++ b/core/java/android/text/format/RelativeDateTimeFormatter.java
@@ -16,14 +16,14 @@
 
 package android.text.format;
 
-import static android.text.format.DateUtilsBridge.FORMAT_ABBREV_ALL;
-import static android.text.format.DateUtilsBridge.FORMAT_ABBREV_MONTH;
-import static android.text.format.DateUtilsBridge.FORMAT_ABBREV_RELATIVE;
-import static android.text.format.DateUtilsBridge.FORMAT_NO_YEAR;
-import static android.text.format.DateUtilsBridge.FORMAT_NUMERIC_DATE;
-import static android.text.format.DateUtilsBridge.FORMAT_SHOW_DATE;
-import static android.text.format.DateUtilsBridge.FORMAT_SHOW_TIME;
-import static android.text.format.DateUtilsBridge.FORMAT_SHOW_YEAR;
+import static android.text.format.DateUtils.FORMAT_ABBREV_ALL;
+import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
+import static android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE;
+import static android.text.format.DateUtils.FORMAT_NO_YEAR;
+import static android.text.format.DateUtils.FORMAT_NUMERIC_DATE;
+import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
+import static android.text.format.DateUtils.FORMAT_SHOW_TIME;
+import static android.text.format.DateUtils.FORMAT_SHOW_YEAR;
 
 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
 
diff --git a/core/java/android/text/format/TimeFormatter.java b/core/java/android/text/format/TimeFormatter.java
index cd541f2..9393f36 100644
--- a/core/java/android/text/format/TimeFormatter.java
+++ b/core/java/android/text/format/TimeFormatter.java
@@ -21,6 +21,7 @@
 package android.text.format;
 
 import android.content.res.Resources;
+import android.icu.text.DateFormatSymbols;
 
 import com.android.i18n.timezone.ZoneInfoData;
 
@@ -55,11 +56,13 @@
      * The Locale for which the cached LocaleData and formats have been loaded.
      */
     private static Locale sLocale;
+    private static DateFormatSymbols sDateFormatSymbols;
     private static LocaleData sLocaleData;
     private static String sTimeOnlyFormat;
     private static String sDateOnlyFormat;
     private static String sDateTimeFormat;
 
+    private final DateFormatSymbols dateFormatSymbols;
     private final LocaleData localeData;
     private final String dateTimeFormat;
     private final String timeOnlyFormat;
@@ -74,6 +77,7 @@
 
             if (sLocale == null || !(locale.equals(sLocale))) {
                 sLocale = locale;
+                sDateFormatSymbols = DateFormat.getIcuDateFormatSymbols(locale);
                 sLocaleData = LocaleData.get(locale);
 
                 Resources r = Resources.getSystem();
@@ -82,6 +86,7 @@
                 sDateTimeFormat = r.getString(com.android.internal.R.string.date_and_time);
             }
 
+            this.dateFormatSymbols = sDateFormatSymbols;
             this.dateTimeFormat = sDateTimeFormat;
             this.timeOnlyFormat = sTimeOnlyFormat;
             this.dateOnlyFormat = sDateOnlyFormat;
@@ -310,12 +315,14 @@
                     outputBuilder.append('\n');
                     return false;
                 case 'p':
-                    modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1]
-                            : localeData.amPm[0], modifier);
+                    modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2))
+                            ? dateFormatSymbols.getAmPmStrings()[1]
+                            : dateFormatSymbols.getAmPmStrings()[0], modifier);
                     return false;
                 case 'P':
-                    modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1]
-                            : localeData.amPm[0], FORCE_LOWER_CASE);
+                    modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2))
+                            ? dateFormatSymbols.getAmPmStrings()[1]
+                            : dateFormatSymbols.getAmPmStrings()[0], FORCE_LOWER_CASE);
                     return false;
                 case 'R':
                     formatInternal("%H:%M", wallTime, zoneInfoData);
diff --git a/core/java/android/text/method/NumberKeyListener.java b/core/java/android/text/method/NumberKeyListener.java
index d40015ee..2b038dd 100644
--- a/core/java/android/text/method/NumberKeyListener.java
+++ b/core/java/android/text/method/NumberKeyListener.java
@@ -29,8 +29,6 @@
 import android.view.KeyEvent;
 import android.view.View;
 
-import libcore.icu.LocaleData;
-
 import java.util.Collection;
 import java.util.Locale;
 
@@ -228,7 +226,7 @@
         if (locale == null) {
             return false;
         }
-        final String[] amPm = LocaleData.get(locale).amPm;
+        final String[] amPm = DateFormat.getIcuDateFormatSymbols(locale).getAmPmStrings();
         for (int i = 0; i < amPm.length; i++) {
             for (int j = 0; j < amPm[i].length(); j++) {
                 final char ch = amPm[i].charAt(j);
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 51b1847..1c219eb 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -24,9 +24,11 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.icu.text.DateFormatSymbols;
 import android.icu.util.Calendar;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.format.DateFormat;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.MathUtils;
@@ -39,8 +41,6 @@
 
 import com.android.internal.R;
 
-import libcore.icu.LocaleData;
-
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Locale;
@@ -421,11 +421,13 @@
 
     static String[] getAmPmStrings(Context context) {
         final Locale locale = context.getResources().getConfiguration().locale;
-        final LocaleData d = LocaleData.get(locale);
+        DateFormatSymbols dfs = DateFormat.getIcuDateFormatSymbols(locale);
+        String[] amPm = dfs.getAmPmStrings();
+        String[] narrowAmPm = dfs.getAmpmNarrowStrings();
 
         final String[] result = new String[2];
-        result[0] = d.amPm[0].length() > 4 ? d.narrowAm : d.amPm[0];
-        result[1] = d.amPm[1].length() > 4 ? d.narrowPm : d.amPm[1];
+        result[0] = amPm[0].length() > 4 ? narrowAmPm[0] : amPm[0];
+        result[1] = amPm[1].length() > 4 ? narrowAmPm[1] : amPm[1];
         return result;
     }
 
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 83c86d5..bd2fa59 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -35,8 +35,6 @@
 
 import com.android.internal.R;
 
-import libcore.icu.LocaleData;
-
 import java.util.Calendar;
 
 /**
@@ -143,7 +141,7 @@
         mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
 
         // Get the localized am/pm strings and use them in the spinner.
-        mAmPmStrings = getAmPmStrings(context);
+        mAmPmStrings = TimePicker.getAmPmStrings(context);
 
         // am/pm
         final View amPmView = mDelegator.findViewById(R.id.amPm);
@@ -574,12 +572,4 @@
             target.setContentDescription(mContext.getString(contDescResId));
         }
     }
-
-    public static String[] getAmPmStrings(Context context) {
-        String[] result = new String[2];
-        LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
-        result[0] = d.amPm[0].length() > 4 ? d.narrowAm : d.amPm[0];
-        result[1] = d.amPm[1].length() > 4 ? d.narrowPm : d.amPm[1];
-        return result;
-    }
 }
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 8ea5aa8..b472749 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -21,6 +21,7 @@
 import android.net.Ikev2VpnProfile;
 import android.net.PlatformVpnProfile;
 import android.net.ProxyInfo;
+import android.net.Uri;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -287,7 +288,7 @@
                     profile.proxy = new ProxyInfo(host, port.isEmpty() ?
                             0 : Integer.parseInt(port), exclList);
                 } else if (!pacFileUrl.isEmpty()) {
-                    profile.proxy = new ProxyInfo(pacFileUrl);
+                    profile.proxy = new ProxyInfo(Uri.parse(pacFileUrl));
                 }
             } // else profile.proxy = null
 
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 3736511..bcb0460 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -371,7 +371,7 @@
                 }
                 if (haveLast) {
                     canvas.drawLine(lastX, lastY, x, y, mPathPaint);
-                    final Paint paint = ps.mTraceCurrent[i] ? mCurrentPointPaint : mPaint;
+                    final Paint paint = ps.mTraceCurrent[i - 1] ? mCurrentPointPaint : mPaint;
                     canvas.drawPoint(lastX, lastY, paint);
                     drawn = true;
                 }
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 18be374..fbb35e0 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -95,6 +95,19 @@
 
 #include "nativebridge/native_bridge.h"
 
+/* Functions in the callchain during the fork shall not be protected with
+   Armv8.3-A Pointer Authentication, otherwise child will not be able to return. */
+#ifdef __ARM_FEATURE_PAC_DEFAULT
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+#define NO_PAC_FUNC __attribute__((target("branch-protection=bti")))
+#else
+#define NO_PAC_FUNC __attribute__((target("branch-protection=none")))
+#endif /* __ARM_FEATURE_BTI_DEFAULT */
+#else /* !__ARM_FEATURE_PAC_DEFAULT */
+#define NO_PAC_FUNC
+#endif /* __ARM_FEATURE_PAC_DEFAULT */
+
+
 namespace {
 
 // TODO (chriswailes): Add a function to initialize native Zygote data.
@@ -985,7 +998,23 @@
   gUsapPoolCount = 0;
 }
 
+NO_PAC_FUNC
+static void PAuthKeyChange(JNIEnv* env) {
+#ifdef __aarch64__
+  unsigned long int hwcaps = getauxval(AT_HWCAP);
+  if (hwcaps & HWCAP_PACA) {
+    const unsigned long key_mask = PR_PAC_APIAKEY | PR_PAC_APIBKEY |
+                                   PR_PAC_APDAKEY | PR_PAC_APDBKEY | PR_PAC_APGAKEY;
+    if (prctl(PR_PAC_RESET_KEYS, key_mask, 0, 0, 0) != 0) {
+      ALOGE("Failed to change the PAC keys: %s", strerror(errno));
+      RuntimeAbort(env, __LINE__, "PAC key change failed.");
+    }
+  }
+#endif
+}
+
 // Utility routine to fork a process from the zygote.
+NO_PAC_FUNC
 static pid_t ForkCommon(JNIEnv* env, bool is_system_server,
                         const std::vector<int>& fds_to_close,
                         const std::vector<int>& fds_to_ignore,
@@ -1036,6 +1065,7 @@
     }
 
     // The child process.
+    PAuthKeyChange(env);
     PreApplicationInit();
 
     // Clean up any descriptors which must be closed immediately
@@ -1486,6 +1516,7 @@
   PreApplicationInit();
 }
 
+NO_PAC_FUNC
 static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
         JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
         jint runtime_flags, jobjectArray rlimits,
@@ -1533,6 +1564,7 @@
     return pid;
 }
 
+NO_PAC_FUNC
 static jint com_android_internal_os_Zygote_nativeForkSystemServer(
         JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
         jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
@@ -1600,6 +1632,7 @@
  * @param is_priority_fork  Controls the nice level assigned to the newly created process
  * @return
  */
+NO_PAC_FUNC
 static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env,
                                                           jclass,
                                                           jint read_pipe_fd,
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 59797f7..51266de 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2422,6 +2422,11 @@
     // OS: Q
     SETTINGS_GESTURE_TAP = 1751;
 
+    // OPEN: Settings > Security & screen lock -> Encryption & credentials > Install a certificate
+    // CATEGORY: SETTINGS
+    // OS: R
+    INSTALL_CERTIFICATE_FROM_STORAGE = 1803;
+
     // OPEN: Settings > Developer Options > Platform Compat
     // CATEGORY: SETTINGS
     // OS: R
diff --git a/core/tests/coretests/src/android/text/format/DateFormatTest.java b/core/tests/coretests/src/android/text/format/DateFormatTest.java
index fa1d56f..a3434e8 100644
--- a/core/tests/coretests/src/android/text/format/DateFormatTest.java
+++ b/core/tests/coretests/src/android/text/format/DateFormatTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.icu.text.DateFormatSymbols;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
@@ -60,6 +61,15 @@
     }
 
     @Test
+    public void testgetIcuDateFormatSymbols() {
+        DateFormatSymbols dfs = DateFormat.getIcuDateFormatSymbols(Locale.US);
+        assertEquals("AM", dfs.getAmPmStrings()[0]);
+        assertEquals("PM", dfs.getAmPmStrings()[1]);
+        assertEquals("a", dfs.getAmpmNarrowStrings()[0]);
+        assertEquals("p", dfs.getAmpmNarrowStrings()[1]);
+    }
+
+    @Test
     public void testGetDateFormatOrder() {
         // lv and fa use differing orders depending on whether you're using numeric or
         // textual months.
diff --git a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
new file mode 100644
index 0000000..0f17d27
--- /dev/null
+++ b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
@@ -0,0 +1,671 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.format;
+
+import static android.icu.util.TimeZone.GMT_ZONE;
+import static android.icu.util.ULocale.ENGLISH;
+import static android.text.format.DateIntervalFormat.formatDateRange;
+import static android.text.format.DateUtils.FORMAT_12HOUR;
+import static android.text.format.DateUtils.FORMAT_24HOUR;
+import static android.text.format.DateUtils.FORMAT_ABBREV_ALL;
+import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
+import static android.text.format.DateUtils.FORMAT_ABBREV_TIME;
+import static android.text.format.DateUtils.FORMAT_ABBREV_WEEKDAY;
+import static android.text.format.DateUtils.FORMAT_NO_MONTH_DAY;
+import static android.text.format.DateUtils.FORMAT_NO_YEAR;
+import static android.text.format.DateUtils.FORMAT_NUMERIC_DATE;
+import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
+import static android.text.format.DateUtils.FORMAT_SHOW_TIME;
+import static android.text.format.DateUtils.FORMAT_SHOW_WEEKDAY;
+import static android.text.format.DateUtils.FORMAT_SHOW_YEAR;
+import static android.text.format.DateUtils.FORMAT_UTC;
+
+import static org.junit.Assert.assertEquals;
+
+import android.icu.util.Calendar;
+import android.icu.util.TimeZone;
+import android.icu.util.ULocale;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.function.BiFunction;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DateIntervalFormatTest {
+    private static final long MINUTE = 60 * 1000;
+    private static final long HOUR = 60 * MINUTE;
+    private static final long DAY = 24 * HOUR;
+    private static final long MONTH = 31 * DAY;
+    private static final long YEAR = 12 * MONTH;
+
+    // These are the old CTS tests for DateIntervalFormat.formatDateRange.
+    @Test
+    public void test_formatDateInterval() throws Exception {
+        TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+
+        Calendar c = Calendar.getInstance(tz, ULocale.US);
+        c.set(Calendar.MONTH, Calendar.JANUARY);
+        c.set(Calendar.DAY_OF_MONTH, 19);
+        c.set(Calendar.HOUR_OF_DAY, 3);
+        c.set(Calendar.MINUTE, 30);
+        c.set(Calendar.SECOND, 15);
+        c.set(Calendar.MILLISECOND, 0);
+        long timeWithCurrentYear = c.getTimeInMillis();
+
+        c.set(Calendar.YEAR, 2009);
+        long fixedTime = c.getTimeInMillis();
+
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+        long onTheHour = c.getTimeInMillis();
+
+        long noonDuration = (8 * 60 + 30) * 60 * 1000 - 15 * 1000;
+        long midnightDuration = (3 * 60 + 30) * 60 * 1000 + 15 * 1000;
+
+        ULocale de_DE = new ULocale("de", "DE");
+        ULocale en_US = new ULocale("en", "US");
+        ULocale es_ES = new ULocale("es", "ES");
+        ULocale es_US = new ULocale("es", "US");
+
+        assertEquals("Monday",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_WEEKDAY));
+        assertEquals("January 19",
+                formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR,
+                        FORMAT_SHOW_DATE));
+        assertEquals("3:30 AM", formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_SHOW_TIME));
+        assertEquals("January 19, 2009",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, FORMAT_SHOW_YEAR));
+        assertEquals("January 19",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR, FORMAT_NO_YEAR));
+        assertEquals("January",
+                formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR,
+                        FORMAT_NO_MONTH_DAY));
+        assertEquals("3:30 AM",
+                formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_12HOUR | FORMAT_SHOW_TIME));
+        assertEquals("03:30",
+                formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_24HOUR | FORMAT_SHOW_TIME));
+        assertEquals("3:30 AM", formatDateRange(en_US, tz, fixedTime, fixedTime,
+                FORMAT_12HOUR /*| FORMAT_CAP_AMPM*/ | FORMAT_SHOW_TIME));
+        assertEquals("12:00 PM",
+                formatDateRange(en_US, tz, fixedTime + noonDuration, fixedTime + noonDuration,
+                        FORMAT_12HOUR | FORMAT_SHOW_TIME));
+        assertEquals("12:00 PM",
+                formatDateRange(en_US, tz, fixedTime + noonDuration, fixedTime + noonDuration,
+                        FORMAT_12HOUR | FORMAT_SHOW_TIME /*| FORMAT_CAP_NOON*/));
+        assertEquals("12:00 PM",
+                formatDateRange(en_US, tz, fixedTime + noonDuration, fixedTime + noonDuration,
+                        FORMAT_12HOUR /*| FORMAT_NO_NOON*/ | FORMAT_SHOW_TIME));
+        assertEquals("12:00 AM", formatDateRange(en_US, tz, fixedTime - midnightDuration,
+                fixedTime - midnightDuration,
+                FORMAT_12HOUR | FORMAT_SHOW_TIME /*| FORMAT_NO_MIDNIGHT*/));
+        assertEquals("3:30 AM",
+                formatDateRange(en_US, tz, fixedTime, fixedTime, FORMAT_SHOW_TIME | FORMAT_UTC));
+        assertEquals("3 AM", formatDateRange(en_US, tz, onTheHour, onTheHour,
+                FORMAT_SHOW_TIME | FORMAT_ABBREV_TIME));
+        assertEquals("Mon", formatDateRange(en_US, tz, fixedTime, fixedTime + HOUR,
+                FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_WEEKDAY));
+        assertEquals("Jan 19",
+                formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR,
+                        FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH));
+        assertEquals("Jan 19",
+                formatDateRange(en_US, tz, timeWithCurrentYear, timeWithCurrentYear + HOUR,
+                        FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+
+        assertEquals("1/19/2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * HOUR,
+                FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+        assertEquals("1/19/2009 – 1/22/2009",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY,
+                        FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+        assertEquals("1/19/2009 – 4/22/2009",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH,
+                        FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+        assertEquals("1/19/2009 – 2/9/2012",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR,
+                        FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+
+        assertEquals("19.1.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + HOUR,
+                FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+        assertEquals("19.–22.01.2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY,
+                FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+        assertEquals("19.01. – 22.04.2009",
+                formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH,
+                        FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+        assertEquals("19.01.2009 – 09.02.2012",
+                formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR,
+                        FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+
+        assertEquals("19/1/2009", formatDateRange(es_US, tz, fixedTime, fixedTime + HOUR,
+                FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+        assertEquals("19/1/2009–22/1/2009",
+                formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
+                        FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+        assertEquals("19/1/2009–22/4/2009",
+                formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
+                        FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+        assertEquals("19/1/2009–9/2/2012",
+                formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR,
+                        FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+
+        assertEquals("19/1/2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + HOUR,
+                FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+        assertEquals("19/1/2009–22/1/2009",
+                formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
+                        FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+        assertEquals("19/1/2009–22/4/2009",
+                formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
+                        FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+        assertEquals("19/1/2009–9/2/2012",
+                formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
+                        FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE));
+
+        // These are some random other test cases I came up with.
+
+        assertEquals("January 19 – 22, 2009",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY, 0));
+        assertEquals("Jan 19 – 22, 2009", formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY,
+                FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+        assertEquals("Mon, Jan 19 – Thu, Jan 22, 2009",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY,
+                        FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+        assertEquals("Monday, January 19 – Thursday, January 22, 2009",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
+
+        assertEquals("January 19 – April 22, 2009",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH, 0));
+        assertEquals("Jan 19 – Apr 22, 2009",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH,
+                        FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+        assertEquals("Mon, Jan 19 – Wed, Apr 22, 2009",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH,
+                        FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+        assertEquals("January – April 2009",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
+
+        assertEquals("Jan 19, 2009 – Feb 9, 2012",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR,
+                        FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+        assertEquals("Jan 2009 – Feb 2012",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR,
+                        FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
+        assertEquals("January 19, 2009 – February 9, 2012",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, 0));
+        assertEquals("Monday, January 19, 2009 – Thursday, February 9, 2012",
+                formatDateRange(en_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
+
+        // The same tests but for de_DE.
+
+        assertEquals("19.–22. Januar 2009",
+                formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, 0));
+        assertEquals("19.–22. Jan. 2009", formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY,
+                FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+        assertEquals("Mo., 19. – Do., 22. Jan. 2009",
+                formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY,
+                        FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+        assertEquals("Montag, 19. – Donnerstag, 22. Januar 2009",
+                formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
+
+        assertEquals("19. Januar – 22. April 2009",
+                formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, 0));
+        assertEquals("19. Jan. – 22. Apr. 2009",
+                formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH,
+                        FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+        assertEquals("Mo., 19. Jan. – Mi., 22. Apr. 2009",
+                formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH,
+                        FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+        assertEquals("Januar–April 2009",
+                formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
+
+        assertEquals("19. Jan. 2009 – 9. Feb. 2012",
+                formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR,
+                        FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+        assertEquals("Jan. 2009 – Feb. 2012",
+                formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR,
+                        FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
+        assertEquals("19. Januar 2009 – 9. Februar 2012",
+                formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, 0));
+        assertEquals("Montag, 19. Januar 2009 – Donnerstag, 9. Februar 2012",
+                formatDateRange(de_DE, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
+
+        // The same tests but for es_US.
+
+        assertEquals("19–22 de enero de 2009",
+                formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, 0));
+        assertEquals("19–22 de ene. de 2009",
+                formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
+                        FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+        assertEquals("lun., 19 de ene. – jue., 22 de ene. de 2009",
+                formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
+                        FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+        assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009",
+                formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
+
+        assertEquals("19 de enero–22 de abril de 2009",
+                formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, 0));
+        assertEquals("19 de ene. – 22 de abr. 2009",
+                formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
+                        FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+        assertEquals("lun., 19 de ene. – mié., 22 de abr. de 2009",
+                formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
+                        FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+        assertEquals("enero–abril de 2009",
+                formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
+
+        assertEquals("19 de ene. de 2009 – 9 de feb. de 2012",
+                formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR,
+                        FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+        assertEquals("ene. de 2009 – feb. de 2012",
+                formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR,
+                        FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
+        assertEquals("19 de enero de 2009–9 de febrero de 2012",
+                formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, 0));
+        assertEquals("lunes, 19 de enero de 2009–jueves, 9 de febrero de 2012",
+                formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
+
+        // The same tests but for es_ES.
+
+        assertEquals("19–22 de enero de 2009",
+                formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, 0));
+        assertEquals("19–22 ene. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
+                FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+        assertEquals("lun., 19 ene. – jue., 22 ene. 2009",
+                formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
+                        FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+        assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009",
+                formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, FORMAT_SHOW_WEEKDAY));
+
+        assertEquals("19 de enero–22 de abril de 2009",
+                formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, 0));
+        assertEquals("19 ene. – 22 abr. 2009",
+                formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
+                        FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+        assertEquals("lun., 19 ene. – mié., 22 abr. 2009",
+                formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
+                        FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
+        assertEquals("enero–abril de 2009",
+                formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
+
+        assertEquals("19 ene. 2009 – 9 feb. 2012",
+                formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
+                        FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
+        assertEquals("ene. 2009 – feb. 2012",
+                formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
+                        FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
+        assertEquals("19 de enero de 2009–9 de febrero de 2012",
+                formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, 0));
+        assertEquals("lunes, 19 de enero de 2009–jueves, 9 de febrero de 2012",
+                formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR, FORMAT_SHOW_WEEKDAY));
+    }
+
+    // http://b/8862241 - we should be able to format dates past 2038.
+    // See also http://code.google.com/p/android/issues/detail?id=13050.
+    @Test
+    public void test8862241() throws Exception {
+        ULocale l = ULocale.US;
+        TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+        Calendar c = Calendar.getInstance(tz, l);
+        c.clear();
+        c.set(2042, Calendar.JANUARY, 19, 3, 30);
+        long jan_19_2042 = c.getTimeInMillis();
+        c.set(2046, Calendar.OCTOBER, 4, 3, 30);
+        long oct_4_2046 = c.getTimeInMillis();
+        int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL;
+        assertEquals("Jan 19, 2042 – Oct 4, 2046",
+                formatDateRange(l, tz, jan_19_2042, oct_4_2046, flags));
+    }
+
+    // http://b/10089890 - we should take the given time zone into account.
+    @Test
+    public void test10089890() throws Exception {
+        ULocale l = ULocale.US;
+        TimeZone utc = TimeZone.getTimeZone("UTC");
+        TimeZone pacific = TimeZone.getTimeZone("America/Los_Angeles");
+        int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL | FORMAT_SHOW_TIME | FORMAT_24HOUR;
+
+        // The Unix epoch is UTC, so 0 is 1970-01-01T00:00Z...
+        assertEquals("Jan 1, 1970, 00:00 – Jan 2, 1970, 00:00",
+                formatDateRange(l, utc, 0, DAY + 1, flags));
+        // But MTV is hours behind, so 0 was still the afternoon of the previous day...
+        assertEquals("Dec 31, 1969, 16:00 – Jan 1, 1970, 16:00",
+                formatDateRange(l, pacific, 0, DAY, flags));
+    }
+
+    // http://b/10318326 - we can drop the minutes in a 12-hour time if they're zero,
+    // but not if we're using the 24-hour clock. That is: "4 PM" is reasonable, "16" is not.
+    @Test
+    public void test10318326() throws Exception {
+        long midnight = 0;
+        long teaTime = 16 * HOUR;
+
+        int time12 = FORMAT_12HOUR | FORMAT_SHOW_TIME;
+        int time24 = FORMAT_24HOUR | FORMAT_SHOW_TIME;
+        int abbr12 = time12 | FORMAT_ABBREV_ALL;
+        int abbr24 = time24 | FORMAT_ABBREV_ALL;
+
+        ULocale l = ULocale.US;
+        TimeZone utc = TimeZone.getTimeZone("UTC");
+
+        // Full length on-the-hour times.
+        assertEquals("00:00", formatDateRange(l, utc, midnight, midnight, time24));
+        assertEquals("12:00 AM", formatDateRange(l, utc, midnight, midnight, time12));
+        assertEquals("16:00", formatDateRange(l, utc, teaTime, teaTime, time24));
+        assertEquals("4:00 PM", formatDateRange(l, utc, teaTime, teaTime, time12));
+
+        // Abbreviated on-the-hour times.
+        assertEquals("00:00", formatDateRange(l, utc, midnight, midnight, abbr24));
+        assertEquals("12 AM", formatDateRange(l, utc, midnight, midnight, abbr12));
+        assertEquals("16:00", formatDateRange(l, utc, teaTime, teaTime, abbr24));
+        assertEquals("4 PM", formatDateRange(l, utc, teaTime, teaTime, abbr12));
+
+        // Abbreviated on-the-hour ranges.
+        assertEquals("00:00 – 16:00", formatDateRange(l, utc, midnight, teaTime, abbr24));
+        assertEquals("12 AM – 4 PM", formatDateRange(l, utc, midnight, teaTime, abbr12));
+
+        // Abbreviated mixed ranges.
+        assertEquals("00:00 – 16:01", formatDateRange(l, utc, midnight, teaTime + MINUTE, abbr24));
+        assertEquals("12:00 AM – 4:01 PM",
+                formatDateRange(l, utc, midnight, teaTime + MINUTE, abbr12));
+    }
+
+    // http://b/10560853 - when the time is not displayed, an end time 0 ms into the next day is
+    // considered to belong to the previous day.
+    @Test
+    public void test10560853_when_time_not_displayed() throws Exception {
+        ULocale l = ULocale.US;
+        TimeZone utc = TimeZone.getTimeZone("UTC");
+
+        long midnight = 0;
+        long midnightNext = 1 * DAY;
+
+        int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY;
+
+        // An all-day event runs until 0 milliseconds into the next day, but is formatted as if it's
+        // just the first day.
+        assertEquals("Thursday, January 1, 1970",
+                formatDateRange(l, utc, midnight, midnightNext, flags));
+
+        // Run one millisecond over, though, and you're into the next day.
+        long nextMorning = 1 * DAY + 1;
+        assertEquals("Thursday, January 1 – Friday, January 2, 1970",
+                formatDateRange(l, utc, midnight, nextMorning, flags));
+
+        // But the same reasoning applies for that day.
+        long nextMidnight = 2 * DAY;
+        assertEquals("Thursday, January 1 – Friday, January 2, 1970",
+                formatDateRange(l, utc, midnight, nextMidnight, flags));
+    }
+
+    // http://b/10560853 - when the start and end times are otherwise on the same day,
+    // an end time 0 ms into the next day is considered to belong to the previous day.
+    @Test
+    public void test10560853_for_single_day_events() throws Exception {
+        ULocale l = ULocale.US;
+        TimeZone utc = TimeZone.getTimeZone("UTC");
+
+        int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE;
+
+        assertEquals("January 1, 1970, 22:00 – 00:00",
+                formatDateRange(l, utc, 22 * HOUR, 24 * HOUR, flags));
+        assertEquals("January 1, 1970, 22:00 – January 2, 1970, 00:30",
+                formatDateRange(l, utc, 22 * HOUR, 24 * HOUR + 30 * MINUTE, flags));
+    }
+
+    // The fix for http://b/10560853 didn't work except for the day around the epoch, which was
+    // all the unit test checked!
+    @Test
+    public void test_single_day_events_later_than_epoch() throws Exception {
+        ULocale l = ULocale.US;
+        TimeZone utc = TimeZone.getTimeZone("UTC");
+
+        int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE;
+
+        Calendar c = Calendar.getInstance(utc, l);
+        c.clear();
+        c.set(1980, Calendar.JANUARY, 1, 0, 0);
+        long jan_1_1980 = c.getTimeInMillis();
+        assertEquals("January 1, 1980, 22:00 – 00:00",
+                formatDateRange(l, utc, jan_1_1980 + 22 * HOUR, jan_1_1980 + 24 * HOUR, flags));
+        assertEquals("January 1, 1980, 22:00 – January 2, 1980, 00:30",
+                formatDateRange(l, utc, jan_1_1980 + 22 * HOUR,
+                        jan_1_1980 + 24 * HOUR + 30 * MINUTE, flags));
+    }
+
+    // The fix for http://b/10560853 didn't work except for UTC, which was
+    // all the unit test checked!
+    @Test
+    public void test_single_day_events_not_in_UTC() throws Exception {
+        ULocale l = ULocale.US;
+        TimeZone pacific = TimeZone.getTimeZone("America/Los_Angeles");
+
+        int flags = FORMAT_SHOW_TIME | FORMAT_24HOUR | FORMAT_SHOW_DATE;
+
+        Calendar c = Calendar.getInstance(pacific, l);
+        c.clear();
+        c.set(1980, Calendar.JANUARY, 1, 0, 0);
+        long jan_1_1980 = c.getTimeInMillis();
+        assertEquals("January 1, 1980, 22:00 – 00:00",
+                formatDateRange(l, pacific, jan_1_1980 + 22 * HOUR, jan_1_1980 + 24 * HOUR, flags));
+
+        c.set(1980, Calendar.JULY, 1, 0, 0);
+        long jul_1_1980 = c.getTimeInMillis();
+        assertEquals("July 1, 1980, 22:00 – 00:00",
+                formatDateRange(l, pacific, jul_1_1980 + 22 * HOUR, jul_1_1980 + 24 * HOUR, flags));
+    }
+
+    // http://b/10209343 - even if the caller didn't explicitly ask us to include the year,
+    // we should do so for years other than the current year.
+    @Test
+    public void test10209343_when_not_this_year() {
+        ULocale l = ULocale.US;
+        TimeZone utc = TimeZone.getTimeZone("UTC");
+
+        int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_TIME | FORMAT_24HOUR;
+
+        assertEquals("Thursday, January 1, 1970, 00:00", formatDateRange(l, utc, 0L, 0L, flags));
+
+        long t1833 = ((long) Integer.MIN_VALUE + Integer.MIN_VALUE) * 1000L;
+        assertEquals("Sunday, November 24, 1833, 17:31",
+                formatDateRange(l, utc, t1833, t1833, flags));
+
+        long t1901 = Integer.MIN_VALUE * 1000L;
+        assertEquals("Friday, December 13, 1901, 20:45",
+                formatDateRange(l, utc, t1901, t1901, flags));
+
+        long t2038 = Integer.MAX_VALUE * 1000L;
+        assertEquals("Tuesday, January 19, 2038, 03:14",
+                formatDateRange(l, utc, t2038, t2038, flags));
+
+        long t2106 = (2L + Integer.MAX_VALUE + Integer.MAX_VALUE) * 1000L;
+        assertEquals("Sunday, February 7, 2106, 06:28",
+                formatDateRange(l, utc, t2106, t2106, flags));
+    }
+
+    // http://b/10209343 - for the current year, we should honor the FORMAT_SHOW_YEAR flags.
+    @Test
+    public void test10209343_when_this_year() {
+        // Construct a date in the current year (whenever the test happens to be run).
+        ULocale l = ULocale.US;
+        TimeZone utc = TimeZone.getTimeZone("UTC");
+        Calendar c = Calendar.getInstance(utc, l);
+        c.set(Calendar.MONTH, Calendar.FEBRUARY);
+        c.set(Calendar.DAY_OF_MONTH, 10);
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        long thisYear = c.getTimeInMillis();
+
+        // You don't get the year if it's this year...
+        assertEquals("February 10", formatDateRange(l, utc, thisYear, thisYear, FORMAT_SHOW_DATE));
+
+        // ...unless you explicitly ask for it.
+        assertEquals(String.format("February 10, %d", c.get(Calendar.YEAR)),
+                formatDateRange(l, utc, thisYear, thisYear, FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR));
+
+        // ...or it's not actually this year...
+        Calendar c2 = (Calendar) c.clone();
+        c2.set(Calendar.YEAR, 1980);
+        long oldYear = c2.getTimeInMillis();
+        assertEquals("February 10, 1980",
+                formatDateRange(l, utc, oldYear, oldYear, FORMAT_SHOW_DATE));
+
+        // (But you can disable that!)
+        assertEquals("February 10",
+                formatDateRange(l, utc, oldYear, oldYear, FORMAT_SHOW_DATE | FORMAT_NO_YEAR));
+
+        // ...or the start and end years aren't the same...
+        assertEquals(String.format("February 10, 1980 – February 10, %d", c.get(Calendar.YEAR)),
+                formatDateRange(l, utc, oldYear, thisYear, FORMAT_SHOW_DATE));
+
+        // (And you can't avoid that --- icu4c steps in and overrides you.)
+        assertEquals(String.format("February 10, 1980 – February 10, %d", c.get(Calendar.YEAR)),
+                formatDateRange(l, utc, oldYear, thisYear, FORMAT_SHOW_DATE | FORMAT_NO_YEAR));
+    }
+
+    // http://b/8467515 - yet another y2k38 bug report.
+    @Test
+    public void test8467515() throws Exception {
+        ULocale l = ULocale.US;
+        TimeZone utc = TimeZone.getTimeZone("UTC");
+        int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_YEAR | FORMAT_ABBREV_MONTH
+                | FORMAT_ABBREV_WEEKDAY;
+        long t;
+
+        Calendar calendar = Calendar.getInstance(utc, l);
+        calendar.clear();
+
+        calendar.set(2038, Calendar.JANUARY, 19, 12, 0, 0);
+        t = calendar.getTimeInMillis();
+        assertEquals("Tue, Jan 19, 2038", formatDateRange(l, utc, t, t, flags));
+
+        calendar.set(1900, Calendar.JANUARY, 1, 0, 0, 0);
+        t = calendar.getTimeInMillis();
+        assertEquals("Mon, Jan 1, 1900", formatDateRange(l, utc, t, t, flags));
+    }
+
+    // http://b/12004664
+    @Test
+    public void test12004664() throws Exception {
+        TimeZone utc = TimeZone.getTimeZone("UTC");
+        Calendar c = Calendar.getInstance(utc, ULocale.US);
+        c.clear();
+        c.set(Calendar.YEAR, 1980);
+        c.set(Calendar.MONTH, Calendar.FEBRUARY);
+        c.set(Calendar.DAY_OF_MONTH, 10);
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        long thisYear = c.getTimeInMillis();
+
+        int flags = FORMAT_SHOW_DATE | FORMAT_SHOW_WEEKDAY | FORMAT_SHOW_YEAR;
+        assertEquals("Sunday, February 10, 1980",
+                formatDateRange(new ULocale("en", "US"), utc, thisYear, thisYear, flags));
+
+        // If we supported non-Gregorian calendars, this is what that we'd expect for these
+        // ULocales.
+        // This is really the correct behavior, but since java.util.Calendar currently only supports
+        // the Gregorian calendar, we want to deliberately force icu4c to agree, otherwise we'd have
+        // a mix of calendars throughout an app's UI depending on whether Java or native code
+        // formatted
+        // the date.
+        // assertEquals("یکشنبه ۲۱ بهمن ۱۳۵۸ ه‍.ش.", formatDateRange(new ULocale("fa"), utc,
+        // thisYear, thisYear, flags));
+        // assertEquals("AP ۱۳۵۸ سلواغه ۲۱, یکشنبه", formatDateRange(new ULocale("ps"), utc,
+        // thisYear, thisYear, flags));
+        // assertEquals("วันอาทิตย์ 10 กุมภาพันธ์ 2523", formatDateRange(new ULocale("th"), utc,
+        // thisYear, thisYear, flags));
+
+        // For now, here are the localized Gregorian strings instead...
+        assertEquals("یکشنبه ۱۰ فوریهٔ ۱۹۸۰",
+                formatDateRange(new ULocale("fa"), utc, thisYear, thisYear, flags));
+        assertEquals("يونۍ د ۱۹۸۰ د فبروري ۱۰",
+                formatDateRange(new ULocale("ps"), utc, thisYear, thisYear, flags));
+        assertEquals("วันอาทิตย์ที่ 10 กุมภาพันธ์ ค.ศ. 1980",
+                formatDateRange(new ULocale("th"), utc, thisYear, thisYear, flags));
+    }
+
+    // http://b/13234532
+    @Test
+    public void test13234532() throws Exception {
+        ULocale l = ULocale.US;
+        TimeZone utc = TimeZone.getTimeZone("UTC");
+
+        int flags = FORMAT_SHOW_TIME | FORMAT_ABBREV_ALL | FORMAT_12HOUR;
+
+        assertEquals("10 – 11 AM", formatDateRange(l, utc, 10 * HOUR, 11 * HOUR, flags));
+        assertEquals("11 AM – 1 PM", formatDateRange(l, utc, 11 * HOUR, 13 * HOUR, flags));
+        assertEquals("2 – 3 PM", formatDateRange(l, utc, 14 * HOUR, 15 * HOUR, flags));
+    }
+
+    // http://b/20708022
+    @Test
+    public void testEndOfDayOnLastDayOfMonth() throws Exception {
+        final ULocale locale = new ULocale("en");
+        final TimeZone timeZone = TimeZone.getTimeZone("UTC");
+
+        assertEquals("11:00 PM – 12:00 AM", formatDateRange(locale, timeZone,
+                1430434800000L, 1430438400000L, FORMAT_SHOW_TIME));
+    }
+
+    // http://b/68847519
+    @Test
+    public void testEndAtMidnight_dateAndTime() {
+        BiFunction<Long, Long, String> fmt = (from, to) -> formatDateRange(
+                ENGLISH, GMT_ZONE, from, to, FORMAT_SHOW_DATE | FORMAT_SHOW_TIME | FORMAT_24HOUR);
+        // If we're showing times and the end-point is midnight the following day, we want the
+        // behaviour of suppressing the date for the end...
+        assertEquals("February 27, 2007, 04:00 – 00:00", fmt.apply(1172548800000L, 1172620800000L));
+        // ...unless the start-point is also midnight, in which case we need dates to disambiguate.
+        assertEquals("February 27, 2007, 00:00 – February 28, 2007, 00:00",
+                fmt.apply(1172534400000L, 1172620800000L));
+        // We want to show the date if the end-point is a millisecond after midnight the following
+        // day, or if it is exactly midnight the day after that.
+        assertEquals("February 27, 2007, 04:00 – February 28, 2007, 00:00",
+                fmt.apply(1172548800000L, 1172620800001L));
+        assertEquals("February 27, 2007, 04:00 – March 1, 2007, 00:00",
+                fmt.apply(1172548800000L, 1172707200000L));
+        // We want to show the date if the start-point is anything less than a minute after
+      // midnight,
+        // since that gets displayed as midnight...
+        assertEquals("February 27, 2007, 00:00 – February 28, 2007, 00:00",
+                fmt.apply(1172534459999L, 1172620800000L));
+        // ...but not if it is exactly one minute after midnight.
+        assertEquals("February 27, 2007, 00:01 – 00:00", fmt.apply(1172534460000L, 1172620800000L));
+    }
+
+    // http://b/68847519
+    @Test
+    public void testEndAtMidnight_dateOnly() {
+        BiFunction<Long, Long, String> fmt = (from, to) -> formatDateRange(
+                ENGLISH, GMT_ZONE, from, to, FORMAT_SHOW_DATE);
+        // If we're only showing dates and the end-point is midnight of any day, we want the
+        // behaviour of showing an end date one earlier. So if the end-point is March 2, 2007 00:00,
+        // show March 1, 2007 instead (whether the start-point is midnight or not).
+        assertEquals("February 27 – March 1, 2007", fmt.apply(1172534400000L, 1172793600000L));
+        assertEquals("February 27 – March 1, 2007", fmt.apply(1172548800000L, 1172793600000L));
+        // We want to show the true date if the end-point is a millisecond after midnight.
+        assertEquals("February 27 – March 2, 2007", fmt.apply(1172534400000L, 1172793600001L));
+
+        // 2006-02-27 00:00:00.000 GMT - 2007-03-02 00:00:00.000 GMT
+        assertEquals("February 27, 2006 – March 1, 2007",
+                fmt.apply(1140998400000L, 1172793600000L));
+
+        // Spans a leap year's Feb 29th.
+        assertEquals("February 27 – March 1, 2004", fmt.apply(1077840000000L, 1078185600000L));
+    }
+}
diff --git a/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java b/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
index d9ba8fb..4b3b573 100644
--- a/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
@@ -16,11 +16,11 @@
 
 package android.text.format;
 
-import static android.text.format.DateUtilsBridge.FORMAT_ABBREV_ALL;
-import static android.text.format.DateUtilsBridge.FORMAT_ABBREV_RELATIVE;
-import static android.text.format.DateUtilsBridge.FORMAT_NO_YEAR;
-import static android.text.format.DateUtilsBridge.FORMAT_NUMERIC_DATE;
-import static android.text.format.DateUtilsBridge.FORMAT_SHOW_YEAR;
+import static android.text.format.DateUtils.FORMAT_ABBREV_ALL;
+import static android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE;
+import static android.text.format.DateUtils.FORMAT_NO_YEAR;
+import static android.text.format.DateUtils.FORMAT_NUMERIC_DATE;
+import static android.text.format.DateUtils.FORMAT_SHOW_YEAR;
 import static android.text.format.RelativeDateTimeFormatter.DAY_IN_MILLIS;
 import static android.text.format.RelativeDateTimeFormatter.HOUR_IN_MILLIS;
 import static android.text.format.RelativeDateTimeFormatter.MINUTE_IN_MILLIS;
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 7282bcf..62194d8 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -74,6 +74,15 @@
     /** Key containing suffix of lockdown VPN profile. */
     public static final String LOCKDOWN_VPN = "LOCKDOWN_VPN";
 
+    /** Name of CA certificate usage. */
+    public static final String CERTIFICATE_USAGE_CA = "ca";
+
+    /** Name of User certificate usage. */
+    public static final String CERTIFICATE_USAGE_USER = "user";
+
+    /** Name of WIFI certificate usage. */
+    public static final String CERTIFICATE_USAGE_WIFI = "wifi";
+
     /** Data type for public keys. */
     public static final String EXTRA_PUBLIC_KEY = "KEY";
 
@@ -94,9 +103,14 @@
     public static final String EXTRA_INSTALL_AS_UID = "install_as_uid";
 
     /**
-     * Intent extra: name for the user's private key.
+     * Intent extra: type of the certificate to install
      */
-    public static final String EXTRA_USER_PRIVATE_KEY_NAME = "user_private_key_name";
+    public static final String EXTRA_CERTIFICATE_USAGE = "certificate_install_usage";
+
+    /**
+     * Intent extra: name for the user's key pair.
+     */
+    public static final String EXTRA_USER_KEY_ALIAS = "user_key_pair_name";
 
     /**
      * Intent extra: data for the user's private key in PEM-encoded PKCS#8.
@@ -104,21 +118,11 @@
     public static final String EXTRA_USER_PRIVATE_KEY_DATA = "user_private_key_data";
 
     /**
-     * Intent extra: name for the user's certificate.
-     */
-    public static final String EXTRA_USER_CERTIFICATE_NAME = "user_certificate_name";
-
-    /**
      * Intent extra: data for the user's certificate in PEM-encoded X.509.
      */
     public static final String EXTRA_USER_CERTIFICATE_DATA = "user_certificate_data";
 
     /**
-     * Intent extra: name for CA certificate chain
-     */
-    public static final String EXTRA_CA_CERTIFICATES_NAME = "ca_certificates_name";
-
-    /**
      * Intent extra: data for CA certificate chain in PEM-encoded X.509.
      */
     public static final String EXTRA_CA_CERTIFICATES_DATA = "ca_certificates_data";
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index b3cdff7..97da3cc 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -43,7 +43,8 @@
     String installCaCertificate(in byte[] caCertificate);
 
     // APIs used by DevicePolicyManager
-    boolean installKeyPair(in byte[] privateKey, in byte[] userCert, in byte[] certChain, String alias);
+    boolean installKeyPair(
+        in byte[] privateKey, in byte[] userCert, in byte[] certChain, String alias, int uid);
     boolean removeKeyPair(String alias);
 
     // APIs used by Settings
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 1829d2f..254456c 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -343,6 +343,16 @@
     public static final int KEY_ATTESTATION_FAILURE = 4;
 
     /**
+     * Used by DPC or delegated app in
+     * {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias} or
+     * {@link android.app.admin.DelegatedAdminReceiver#onChoosePrivateKeyAlias} to identify that
+     * the requesting app is not granted access to any key, and nor will the user be able to grant
+     * access manually.
+     */
+    public static final String KEY_ALIAS_SELECTION_DENIED =
+            "android:alias-selection-denied";
+
+    /**
      * Returns an {@code Intent} that can be used for credential
      * installation. The intent may be used without any extras, in
      * which case the user will be able to install credentials from
diff --git a/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp b/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp
new file mode 100644
index 0000000..77ef8df
--- /dev/null
+++ b/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_fuzz {
+    name: "resourcefile_fuzzer",
+    srcs: [
+        "resourcefile_fuzzer.cpp",
+    ],
+    host_supported: true,
+    corpus: ["corpus/*"],
+    static_libs: ["libgmock"],
+    target: {
+        android: {
+            shared_libs:[
+                "libandroidfw",
+                "libbase",
+                "libcutils",
+                "libutils",
+                "libziparchive",
+                "libui",
+            ],
+        },
+        host: {
+            static_libs: [
+                "libandroidfw",
+                "libbase",
+                "libcutils",
+                "libutils",
+                "libziparchive",
+                "liblog",
+                "libz",
+            ],
+        },
+    },
+}
diff --git a/libs/androidfw/fuzz/resourcefile_fuzzer/corpus/resources.arsc b/libs/androidfw/fuzz/resourcefile_fuzzer/corpus/resources.arsc
new file mode 100644
index 0000000..3cf2ea7
--- /dev/null
+++ b/libs/androidfw/fuzz/resourcefile_fuzzer/corpus/resources.arsc
Binary files differ
diff --git a/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp b/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp
new file mode 100644
index 0000000..96d44ab
--- /dev/null
+++ b/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <string>
+#include <memory>
+
+#include <androidfw/ApkAssets.h>
+#include <androidfw/LoadedArsc.h>
+#include <androidfw/StringPiece.h>
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+using android::ApkAssets;
+using android::LoadedArsc;
+using android::StringPiece;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+
+  std::unique_ptr<const LoadedArsc> loaded_arsc =
+      LoadedArsc::Load(StringPiece(reinterpret_cast<const char*>(data), size));
+
+  return 0;
+}
\ No newline at end of file
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index a285692..c55eeeb 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -40944,6 +40944,7 @@
     field public static final String EXTRA_KEY_ALIAS = "android.security.extra.KEY_ALIAS";
     field public static final String EXTRA_NAME = "name";
     field public static final String EXTRA_PKCS12 = "PKCS12";
+    field public static final String KEY_ALIAS_SELECTION_DENIED = "android:alias-selection-denied";
   }
 
   public interface KeyChainAliasCallback {
diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java
index 0b69963..121f549 100644
--- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java
+++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java
@@ -38,7 +38,10 @@
             "/odm/etc/NOTICE.xml.gz",
             "/oem/etc/NOTICE.xml.gz",
             "/product/etc/NOTICE.xml.gz",
-            "/product_services/etc/NOTICE.xml.gz"};
+            "/system_ext/etc/NOTICE.xml.gz",
+            "/vendor_dlkm/etc/NOTICE.xml.gz",
+            "/odm_dlkm/etc/NOTICE.xml.gz",
+    };
     static final String NOTICE_HTML_FILE_NAME = "NOTICE.html";
 
     private final Context mContext;
diff --git a/services/Android.bp b/services/Android.bp
index 581edce..dc948e9 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -143,4 +143,7 @@
     srcs: [":services-stubs.sources"],
     installable: false,
     static_libs: ["android_module_lib_stubs_current"],
+    sdk_version: "none",
+    system_modules: "none",
+    java_version: "1.8",
 }
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index f812a05..26cc3ee 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -163,7 +163,7 @@
         if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
             ProxyInfo proxyProperties;
             if (!TextUtils.isEmpty(pacFileUrl)) {
-                proxyProperties = new ProxyInfo(pacFileUrl);
+                proxyProperties = new ProxyInfo(Uri.parse(pacFileUrl));
             } else {
                 proxyProperties = new ProxyInfo(host, port, exclList);
             }
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index e3e02e3..f0bf5c0 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -24,6 +24,7 @@
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
 import android.net.StaticIpConfiguration;
+import android.net.Uri;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
@@ -372,7 +373,7 @@
                             config.httpProxy = proxyInfo;
                             break;
                         case PAC:
-                            ProxyInfo proxyPacProperties = new ProxyInfo(pacFileUrl);
+                            ProxyInfo proxyPacProperties = new ProxyInfo(Uri.parse(pacFileUrl));
                             config.proxySettings = proxySettings;
                             config.httpProxy = proxyPacProperties;
                             break;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 03e71f9..a363f9b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5672,7 +5672,7 @@
                     KeyChain.bindAsUser(mContext, UserHandle.getUserHandleForUid(callingUid));
             try {
                 IKeyChainService keyChain = keyChainConnection.getService();
-                if (!keyChain.installKeyPair(privKey, cert, chain, alias)) {
+                if (!keyChain.installKeyPair(privKey, cert, chain, alias, KeyStore.UID_SELF)) {
                     return false;
                 }
                 if (requestAccess) {