Fix bugs when dropping down edit type list in Editor.(1/2)

When dropping down the edit type list in Editor, overall number
should not be checked since the editor has already been added.

BUG 25929524
BUG 26190778

Change-Id: If44d3fb7757357d7ffd2a53b0e1c1cd817655135
diff --git a/src/com/android/contacts/common/model/RawContactModifier.java b/src/com/android/contacts/common/model/RawContactModifier.java
index 7258396..fd028e3 100644
--- a/src/com/android/contacts/common/model/RawContactModifier.java
+++ b/src/com/android/contacts/common/model/RawContactModifier.java
@@ -98,7 +98,7 @@
 
     public static boolean hasValidTypes(RawContactDelta state, DataKind kind) {
         if (RawContactModifier.hasEditTypes(kind)) {
-            return (getValidTypes(state, kind).size() > 0);
+            return (getValidTypes(state, kind, null, true, null, true).size() > 0);
         } else {
             return true;
         }
@@ -135,29 +135,6 @@
      * For the given {@link RawContactDelta} and {@link DataKind}, return the
      * list possible {@link EditType} options available based on
      * {@link AccountType}.
-     */
-    public static ArrayList<EditType> getValidTypes(RawContactDelta state, DataKind kind) {
-        return getValidTypes(state, kind, null, true, null);
-    }
-
-    /**
-     * For the given {@link RawContactDelta} and {@link DataKind}, return the
-     * list possible {@link EditType} options available based on
-     * {@link AccountType}.
-     *
-     * @param forceInclude Always include this {@link EditType} in the returned
-     *            list, even when an otherwise-invalid choice. This is useful
-     *            when showing a dialog that includes the current type.
-     */
-    public static ArrayList<EditType> getValidTypes(RawContactDelta state, DataKind kind,
-            EditType forceInclude) {
-        return getValidTypes(state, kind, forceInclude, true, null);
-    }
-
-    /**
-     * For the given {@link RawContactDelta} and {@link DataKind}, return the
-     * list possible {@link EditType} options available based on
-     * {@link AccountType}.
      *
      * @param forceInclude Always include this {@link EditType} in the returned
      *            list, even when an otherwise-invalid choice. This is useful
@@ -167,9 +144,11 @@
      * @param typeCount When provided, will be used for the frequency count of
      *            each {@link EditType}, otherwise built using
      *            {@link #getTypeFrequencies(RawContactDelta, DataKind)}.
+     * @param checkOverall If true, check if the overall number of types is under limit.
      */
-    private static ArrayList<EditType> getValidTypes(RawContactDelta state, DataKind kind,
-            EditType forceInclude, boolean includeSecondary, SparseIntArray typeCount) {
+    public static ArrayList<EditType> getValidTypes(RawContactDelta state, DataKind kind,
+            EditType forceInclude, boolean includeSecondary, SparseIntArray typeCount,
+            boolean checkOverall) {
         final ArrayList<EditType> validTypes = new ArrayList<EditType>();
 
         // Bail early if no types provided
@@ -181,12 +160,16 @@
         }
 
         // Build list of valid types
-        final int overallCount = typeCount.get(FREQUENCY_TOTAL);
-        final boolean validOverall = (kind.typeOverallMax == -1 ? true
-                : overallCount <= kind.typeOverallMax);
+        boolean validOverall = true;
+        if (checkOverall) {
+            final int overallCount = typeCount.get(FREQUENCY_TOTAL);
+            validOverall = (kind.typeOverallMax == -1 ? true
+                    : overallCount < kind.typeOverallMax);
+        }
+
         for (EditType type : kind.typeList) {
             final boolean validSpecific = (type.specificMax == -1 ? true : typeCount
-                    .get(type.rawValue) <= type.specificMax);
+                    .get(type.rawValue) < type.specificMax);
             final boolean validSecondary = (includeSecondary ? true : !type.secondary);
             final boolean forcedInclude = type.equals(forceInclude);
             if (forcedInclude || (validOverall && validSpecific && validSecondary)) {
@@ -310,7 +293,7 @@
         // Find type counts and valid primary types, bail if none
         final SparseIntArray typeCount = getTypeFrequencies(state, kind);
         final ArrayList<EditType> validTypes = getValidTypes(state, kind, null, includeSecondary,
-                typeCount);
+                typeCount, /*checkOverall=*/ true);
         if (validTypes.size() == 0) return null;
 
         // Keep track of the last valid type
diff --git a/tests/src/com/android/contacts/common/RawContactModifierTests.java b/tests/src/com/android/contacts/common/RawContactModifierTests.java
index e025691..dcb2b25 100644
--- a/tests/src/com/android/contacts/common/RawContactModifierTests.java
+++ b/tests/src/com/android/contacts/common/RawContactModifierTests.java
@@ -217,7 +217,7 @@
         RawContactModifier.insertChild(state, kindPhone, typeWork);
 
         // Expecting home, other
-        validTypes = RawContactModifier.getValidTypes(state, kindPhone, null);
+        validTypes = RawContactModifier.getValidTypes(state, kindPhone, null, true, null, true);
         assertContains(validTypes, typeHome);
         assertNotContains(validTypes, typeWork);
         assertContains(validTypes, typeOther);
@@ -226,7 +226,7 @@
         RawContactModifier.insertChild(state, kindPhone, typeHome);
 
         // Expecting other
-        validTypes = RawContactModifier.getValidTypes(state, kindPhone, null);
+        validTypes = RawContactModifier.getValidTypes(state, kindPhone, null, true, null, true);
         assertNotContains(validTypes, typeHome);
         assertNotContains(validTypes, typeWork);
         assertContains(validTypes, typeOther);
@@ -236,13 +236,50 @@
         RawContactModifier.insertChild(state, kindPhone, typeHome);
 
         // Expecting none
-        validTypes = RawContactModifier.getValidTypes(state, kindPhone, null);
+        validTypes = RawContactModifier.getValidTypes(state, kindPhone, null, true, null, true);
         assertNotContains(validTypes, typeHome);
         assertNotContains(validTypes, typeWork);
         assertNotContains(validTypes, typeOther);
     }
 
     /**
+     * Test which valid types there are when trying to update the editor type.
+     * {@link RawContactModifier#getValidTypes(RawContactDelta, DataKind, EditType, Boolean)}
+     */
+    public void testValidTypesWhenUpdating() {
+        // Build a source and pull specific types
+        final AccountType source = getAccountType();
+        final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+        final EditType typeHome = RawContactModifier.getType(kindPhone, Phone.TYPE_HOME);
+        final EditType typeWork = RawContactModifier.getType(kindPhone, Phone.TYPE_WORK);
+        final EditType typeOther = RawContactModifier.getType(kindPhone, Phone.TYPE_OTHER);
+
+        List<EditType> validTypes;
+
+        // Add first home, first work
+        final RawContactDelta state = getRawContact(TEST_ID);
+        RawContactModifier.insertChild(state, kindPhone, typeHome);
+        RawContactModifier.insertChild(state, kindPhone, typeWork);
+
+        // Update editor type for home.
+        validTypes = RawContactModifier.getValidTypes(state, kindPhone, null, true, null, false);
+        assertContains(validTypes, typeHome);
+        assertNotContains(validTypes, typeWork);
+        assertContains(validTypes, typeOther);
+
+        // Add another 3 types. Overall limit is 5.
+        RawContactModifier.insertChild(state, kindPhone, typeHome);
+        RawContactModifier.insertChild(state, kindPhone, typeOther);
+        RawContactModifier.insertChild(state, kindPhone, typeOther);
+
+        // "Other" is valid when updating the editor type.
+        validTypes = RawContactModifier.getValidTypes(state, kindPhone, null, true, null, false);
+        assertNotContains(validTypes, typeHome);
+        assertNotContains(validTypes, typeWork);
+        assertContains(validTypes, typeOther);
+    }
+
+    /**
      * Test {@link RawContactModifier#canInsert(RawContactDelta, DataKind)} by
      * inserting various rows.
      */