Merge "Unify behavior of various cases of "no underlying networks"" into pi-dev
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 9e9d46a..b957e4d 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -5228,6 +5228,7 @@
 Landroid/telephony/PhoneNumberUtils;->isEmergencyNumber(Ljava/lang/String;Ljava/lang/String;)Z
 Landroid/telephony/PhoneNumberUtils;->isLocalEmergencyNumber(Landroid/content/Context;ILjava/lang/String;)Z
 Landroid/telephony/PhoneNumberUtils;->isNanp(Ljava/lang/String;)Z
+Landroid/telephony/PhoneNumberUtils;->isPotentialLocalEmergencyNumber(Landroid/content/Context;Ljava/lang/String;)Z
 Landroid/telephony/PhoneNumberUtils;->isUriNumber(Ljava/lang/String;)Z
 Landroid/telephony/PhoneNumberUtils;->isVoiceMailNumber(Landroid/content/Context;ILjava/lang/String;)Z
 Landroid/telephony/PhoneNumberUtils;->MIN_MATCH:I
@@ -8445,6 +8446,7 @@
 Ldalvik/system/DexPathList$Element;-><init>(Ldalvik/system/DexFile;Ljava/io/File;)V
 Ldalvik/system/DexPathList$Element;-><init>(Ljava/io/File;ZLjava/io/File;Ldalvik/system/DexFile;)V
 Ldalvik/system/DexPathList$Element;->dexFile:Ldalvik/system/DexFile;
+Ldalvik/system/DexPathList$Element;->path:Ljava/io/File;
 Ldalvik/system/DexPathList$NativeLibraryElement;-><init>(Ljava/io/File;)V
 Ldalvik/system/DexPathList$NativeLibraryElement;->path:Ljava/io/File;
 Ldalvik/system/DexPathList;-><init>(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)V
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index fc5ea66..30256b4 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -124,7 +124,7 @@
     /**
      * The ApkAssets we are caching and intend to hold strong references to.
      */
-    private final LruCache<ApkKey, ApkAssets> mLoadedApkAssets = new LruCache<>(15);
+    private final LruCache<ApkKey, ApkAssets> mLoadedApkAssets = new LruCache<>(3);
 
     /**
      * The ApkAssets that are being referenced in the wild that we can reuse, even if they aren't
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7bf3af1..e9f7d2a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3114,10 +3114,10 @@
 
         private static final Validator FONT_SCALE_VALIDATOR = new Validator() {
             @Override
-            public boolean validate(String value) {
+            public boolean validate(@Nullable String value) {
                 try {
                     return Float.parseFloat(value) >= 0;
-                } catch (NumberFormatException e) {
+                } catch (NumberFormatException | NullPointerException e) {
                     return false;
                 }
             }
@@ -3655,11 +3655,11 @@
         /** @hide */
         public static final Validator DATE_FORMAT_VALIDATOR = new Validator() {
             @Override
-            public boolean validate(String value) {
+            public boolean validate(@Nullable String value) {
                 try {
                     new SimpleDateFormat(value);
                     return true;
-                } catch (IllegalArgumentException e) {
+                } catch (IllegalArgumentException | NullPointerException e) {
                     return false;
                 }
             }
@@ -4066,7 +4066,7 @@
         /** @hide */
         public static final Validator EGG_MODE_VALIDATOR = new Validator() {
             @Override
-            public boolean validate(String value) {
+            public boolean validate(@Nullable String value) {
                 try {
                     return Long.parseLong(value) >= 0;
                 } catch (NumberFormatException e) {
@@ -5965,7 +5965,7 @@
         private static final Validator ACCESSIBILITY_BUTTON_TARGET_COMPONENT_VALIDATOR =
                 new Validator() {
                     @Override
-                    public boolean validate(String value) {
+                    public boolean validate(@Nullable String value) {
                         // technically either ComponentName or class name, but there's proper value
                         // validation at callsites, so allow any non-null string
                         return value != null;
@@ -6482,7 +6482,7 @@
 
         private static final Validator TTS_DEFAULT_LOCALE_VALIDATOR = new Validator() {
             @Override
-            public boolean validate(String value) {
+            public boolean validate(@Nullable String value) {
                 if (value == null || value.length() == 0) {
                     return false;
                 }
@@ -7720,7 +7720,7 @@
 
         private static final Validator QS_TILES_VALIDATOR = new Validator() {
             @Override
-            public boolean validate(String value) {
+            public boolean validate(@Nullable String value) {
                 if (value == null) {
                     return false;
                 }
@@ -7779,7 +7779,7 @@
 
         private static final Validator QS_AUTO_ADDED_TILES_VALIDATOR = new Validator() {
             @Override
-            public boolean validate(String value) {
+            public boolean validate(@Nullable String value) {
                 if (value == null) {
                     return false;
                 }
@@ -8653,7 +8653,7 @@
 
         private static final Validator STAY_ON_WHILE_PLUGGED_IN_VALIDATOR = new Validator() {
             @Override
-            public boolean validate(String value) {
+            public boolean validate(@Nullable String value) {
                 try {
                     int val = Integer.parseInt(value);
                     return (val == 0)
@@ -9687,7 +9687,7 @@
 
         private static final Validator USE_OPEN_WIFI_PACKAGE_VALIDATOR = new Validator() {
             @Override
-            public boolean validate(String value) {
+            public boolean validate(@Nullable String value) {
                 return (value == null) || PACKAGE_NAME_VALIDATOR.validate(value);
             }
         };
@@ -11382,7 +11382,7 @@
         private static final Validator ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS_VALIDATOR =
                 new Validator() {
             @Override
-            public boolean validate(String value) {
+            public boolean validate(@Nullable String value) {
                 try {
                     String[] surroundFormats = TextUtils.split(value, ",");
                     for (String format : surroundFormats) {
diff --git a/core/java/android/provider/SettingsValidators.java b/core/java/android/provider/SettingsValidators.java
index c878bba..b53b0f0 100644
--- a/core/java/android/provider/SettingsValidators.java
+++ b/core/java/android/provider/SettingsValidators.java
@@ -16,6 +16,7 @@
 
 package android.provider;
 
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.net.Uri;
 
@@ -36,14 +37,14 @@
 
     public static final Validator ANY_STRING_VALIDATOR = new Validator() {
         @Override
-        public boolean validate(String value) {
+        public boolean validate(@Nullable String value) {
             return true;
         }
     };
 
     public static final Validator NON_NEGATIVE_INTEGER_VALIDATOR = new Validator() {
         @Override
-        public boolean validate(String value) {
+        public boolean validate(@Nullable String value) {
             try {
                 return Integer.parseInt(value) >= 0;
             } catch (NumberFormatException e) {
@@ -54,7 +55,7 @@
 
     public static final Validator ANY_INTEGER_VALIDATOR = new Validator() {
         @Override
-        public boolean validate(String value) {
+        public boolean validate(@Nullable String value) {
             try {
                 Integer.parseInt(value);
                 return true;
@@ -66,7 +67,7 @@
 
     public static final Validator URI_VALIDATOR = new Validator() {
         @Override
-        public boolean validate(String value) {
+        public boolean validate(@Nullable String value) {
             try {
                 Uri.decode(value);
                 return true;
@@ -78,14 +79,14 @@
 
     public static final Validator COMPONENT_NAME_VALIDATOR = new Validator() {
         @Override
-        public boolean validate(String value) {
+        public boolean validate(@Nullable String value) {
             return value != null && ComponentName.unflattenFromString(value) != null;
         }
     };
 
     public static final Validator PACKAGE_NAME_VALIDATOR = new Validator() {
         @Override
-        public boolean validate(String value) {
+        public boolean validate(@Nullable String value) {
             return value != null && isStringPackageName(value);
         }
 
@@ -122,7 +123,7 @@
         private static final int MAX_IPV6_LENGTH = 45;
 
         @Override
-        public boolean validate(String value) {
+        public boolean validate(@Nullable String value) {
             if (value == null) {
                 return false;
             }
@@ -132,7 +133,7 @@
 
     public static final Validator LOCALE_VALIDATOR = new Validator() {
         @Override
-        public boolean validate(String value) {
+        public boolean validate(@Nullable String value) {
             if (value == null) {
                 return false;
             }
@@ -147,7 +148,11 @@
     };
 
     public interface Validator {
-        boolean validate(String value);
+        /**
+         * Returns whether the input value is valid. Subclasses should handle the case where the
+         * input value is {@code null}.
+         */
+        boolean validate(@Nullable String value);
     }
 
     public static final class DiscreteValueValidator implements Validator {
@@ -158,7 +163,7 @@
         }
 
         @Override
-        public boolean validate(String value) {
+        public boolean validate(@Nullable String value) {
             return ArrayUtils.contains(mValues, value);
         }
     }
@@ -173,7 +178,7 @@
         }
 
         @Override
-        public boolean validate(String value) {
+        public boolean validate(@Nullable String value) {
             try {
                 final int intValue = Integer.parseInt(value);
                 return intValue >= mMin && intValue <= mMax;
@@ -193,11 +198,11 @@
         }
 
         @Override
-        public boolean validate(String value) {
+        public boolean validate(@Nullable String value) {
             try {
                 final float floatValue = Float.parseFloat(value);
                 return floatValue >= mMin && floatValue <= mMax;
-            } catch (NumberFormatException e) {
+            } catch (NumberFormatException | NullPointerException e) {
                 return false;
             }
         }
@@ -211,7 +216,7 @@
         }
 
         @Override
-        public boolean validate(String value) {
+        public boolean validate(@Nullable String value) {
             if (value == null) {
                 return false;
             }
@@ -233,7 +238,7 @@
         }
 
         @Override
-        public boolean validate(String value) {
+        public boolean validate(@Nullable String value) {
             if (value == null) {
                 return false;
             }
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 8f1f1ab..275ef57 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -284,7 +284,12 @@
             @Nullable SelectionResult result) {
         final Layout layout = mTextView.getLayout();
 
-        final Runnable onAnimationEndCallback = () -> startSelectionActionMode(result);
+        final Runnable onAnimationEndCallback = () -> {
+            if (result.mStart >= 0 && result.mEnd <= getText(mTextView).length()
+                    && result.mStart <= result.mEnd) {
+                startSelectionActionMode(result);
+            }
+        };
         // TODO do not trigger the animation if the change included only non-printable characters
         final boolean didSelectionChange =
                 result != null && (mTextView.getSelectionStart() != result.mStart
diff --git a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
index c4d5b0c..50f24d3 100644
--- a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
@@ -48,6 +48,11 @@
     }
 
     @Test
+    public void testNonNegativeIntegerValidator_onNullValue_returnsFalse() {
+        assertFalse(SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR.validate(null));
+    }
+
+    @Test
     public void testAnyIntegerValidator() {
         assertTrue(SettingsValidators.ANY_INTEGER_VALIDATOR.validate("1"));
         assertTrue(SettingsValidators.ANY_INTEGER_VALIDATOR.validate("0"));
@@ -56,6 +61,16 @@
     }
 
     @Test
+    public void testAnyIntegerValidator_onNullValue_returnsFalse() {
+        assertFalse(SettingsValidators.ANY_INTEGER_VALIDATOR.validate(null));
+    }
+
+    @Test
+    public void testUriValidator_onNullValue_returnsTrue() {
+        assertTrue(SettingsValidators.URI_VALIDATOR.validate(null));
+    }
+
+    @Test
     public void testComponentNameValidator() {
         assertTrue(SettingsValidators.COMPONENT_NAME_VALIDATOR.validate(
                 "android/com.android.internal.backup.LocalTransport"));
@@ -63,11 +78,16 @@
     }
 
     @Test
-    public void testComponentNameValidator_onNullValue_doesNotThrow() {
+    public void testComponentNameValidator_onNullValue_returnsFalse() {
         assertFalse(SettingsValidators.COMPONENT_NAME_VALIDATOR.validate(null));
     }
 
     @Test
+    public void testLenientIpAddressValidator_onNullValue_returnsFalse() {
+        assertFalse(SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR.validate(null));
+    }
+
+    @Test
     public void testLocaleValidator() {
         assertTrue(SettingsValidators.LOCALE_VALIDATOR.validate("en_US"));
         assertTrue(SettingsValidators.LOCALE_VALIDATOR.validate("es"));
@@ -75,6 +95,11 @@
     }
 
     @Test
+    public void testLocaleValidator_onNullValue_returnsFalse() {
+        assertFalse(SettingsValidators.LOCALE_VALIDATOR.validate(null));
+    }
+
+    @Test
     public void testPackageNameValidator() {
         assertTrue(SettingsValidators.PACKAGE_NAME_VALIDATOR.validate(
                 "com.google.android"));
@@ -84,6 +109,11 @@
     }
 
     @Test
+    public void testPackageNameValidator_onNullValue_returnsFalse() {
+        assertFalse(SettingsValidators.PACKAGE_NAME_VALIDATOR.validate(null));
+    }
+
+    @Test
     public void testDiscreteValueValidator() {
         String[] beerTypes = new String[]{"Ale", "American IPA", "Stout"};
         Validator v = new SettingsValidators.DiscreteValueValidator(beerTypes);
@@ -94,6 +124,14 @@
     }
 
     @Test
+    public void testDiscreteValueValidator_onNullValue_returnsFalse() {
+        String[] discreteTypes = new String[]{"Type1", "Type2"};
+        Validator v = new SettingsValidators.DiscreteValueValidator(discreteTypes);
+
+        assertFalse(v.validate(null));
+    }
+
+    @Test
     public void testInclusiveIntegerRangeValidator() {
         Validator v = new SettingsValidators.InclusiveIntegerRangeValidator(0, 5);
         assertTrue(v.validate("0"));
@@ -104,6 +142,13 @@
     }
 
     @Test
+    public void testInclusiveIntegerRangeValidator_onNullValue_returnsFalse() {
+        Validator v = new SettingsValidators.InclusiveIntegerRangeValidator(0, 5);
+
+        assertFalse(v.validate(null));
+    }
+
+    @Test
     public void testInclusiveFloatRangeValidator() {
         Validator v = new SettingsValidators.InclusiveFloatRangeValidator(0.0f, 5.0f);
         assertTrue(v.validate("0.0"));
@@ -114,6 +159,13 @@
     }
 
     @Test
+    public void testInclusiveFloatRangeValidator_onNullValue_returnsFalse() {
+        Validator v = new SettingsValidators.InclusiveFloatRangeValidator(0.0f, 5.0f);
+
+        assertFalse(v.validate(null));
+    }
+
+    @Test
     public void testComponentNameListValidator() {
         Validator v = new SettingsValidators.ComponentNameListValidator(",");
         assertTrue(v.validate("android/com.android.internal.backup.LocalTransport,"
@@ -122,12 +174,30 @@
     }
 
     @Test
+    public void testComponentNameListValidator_onNullValue_returnsFalse() {
+        Validator v = new SettingsValidators.ComponentNameListValidator(",");
+
+        assertFalse(v.validate(null));
+    }
+
+    @Test
     public void testPackageNameListValidator() {
         Validator v = new SettingsValidators.PackageNameListValidator(",");
         assertTrue(v.validate("com.android.internal.backup.LocalTransport,com.google.android.gms"));
         assertFalse(v.validate("5com.android.internal.backup.LocalTransport,android"));
     }
 
+    @Test
+    public void testPackageNameListValidator_onNullValue_returnsFalse() {
+        Validator v = new SettingsValidators.PackageNameListValidator(",");
+
+        assertFalse(v.validate(null));
+    }
+
+    @Test
+    public void dateFormatValidator_onNullValue_returnsFalse() {
+        assertFalse(Settings.System.DATE_FORMAT_VALIDATOR.validate(null));
+    }
 
     @Test
     public void ensureAllBackedUpSystemSettingsHaveValidators() {