Merge "Update language to comply with Android's inclusive language guidance"
diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py
index de6b478..8a282e5 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists.py
@@ -13,9 +13,7 @@
 # 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.
-"""
-Generate API lists for non-SDK API enforcement.
-"""
+"""Generate API lists for non-SDK API enforcement."""
 import argparse
 from collections import defaultdict
 import functools
@@ -24,27 +22,47 @@
 import sys
 
 # Names of flags recognized by the `hiddenapi` tool.
-FLAG_WHITELIST = "whitelist"
-FLAG_GREYLIST = "greylist"
-FLAG_BLACKLIST = "blacklist"
-FLAG_GREYLIST_MAX_O = "greylist-max-o"
-FLAG_GREYLIST_MAX_P = "greylist-max-p"
-FLAG_GREYLIST_MAX_Q = "greylist-max-q"
-FLAG_GREYLIST_MAX_R = "greylist-max-r"
-FLAG_CORE_PLATFORM_API = "core-platform-api"
-FLAG_PUBLIC_API = "public-api"
-FLAG_SYSTEM_API = "system-api"
-FLAG_TEST_API = "test-api"
+FLAG_SDK = 'sdk'
+FLAG_UNSUPPORTED = 'unsupported'
+FLAG_BLOCKED = 'blocked'
+FLAG_MAX_TARGET_O = 'max-target-o'
+FLAG_MAX_TARGET_P = 'max-target-p'
+FLAG_MAX_TARGET_Q = 'max-target-q'
+FLAG_MAX_TARGET_R = 'max-target-r'
+FLAG_CORE_PLATFORM_API = 'core-platform-api'
+FLAG_PUBLIC_API = 'public-api'
+FLAG_SYSTEM_API = 'system-api'
+FLAG_TEST_API = 'test-api'
+
+OLD_FLAG_SDK = "whitelist"
+OLD_FLAG_UNSUPPORTED = "greylist"
+OLD_FLAG_BLOCKED = "blacklist"
+OLD_FLAG_MAX_TARGET_O = "greylist-max-o"
+OLD_FLAG_MAX_TARGET_P = "greylist-max-p"
+OLD_FLAG_MAX_TARGET_Q = "greylist-max-q"
+OLD_FLAG_MAX_TARGET_R = "greylist-max-r"
+
+OLD_FLAGS_TO_NEW = {
+    OLD_FLAG_SDK: FLAG_SDK,
+    OLD_FLAG_UNSUPPORTED: FLAG_UNSUPPORTED,
+    OLD_FLAG_BLOCKED: FLAG_BLOCKED,
+    OLD_FLAG_MAX_TARGET_O: FLAG_MAX_TARGET_O,
+    OLD_FLAG_MAX_TARGET_P: FLAG_MAX_TARGET_P,
+    OLD_FLAG_MAX_TARGET_Q: FLAG_MAX_TARGET_Q,
+    OLD_FLAG_MAX_TARGET_R: FLAG_MAX_TARGET_R,
+}
+
+NEW_FLAGS_TO_OLD = dict(zip(OLD_FLAGS_TO_NEW.values(), OLD_FLAGS_TO_NEW.keys()))
 
 # List of all known flags.
 FLAGS_API_LIST = [
-    FLAG_WHITELIST,
-    FLAG_GREYLIST,
-    FLAG_BLACKLIST,
-    FLAG_GREYLIST_MAX_O,
-    FLAG_GREYLIST_MAX_P,
-    FLAG_GREYLIST_MAX_Q,
-    FLAG_GREYLIST_MAX_R,
+    FLAG_SDK,
+    FLAG_UNSUPPORTED,
+    FLAG_BLOCKED,
+    FLAG_MAX_TARGET_O,
+    FLAG_MAX_TARGET_P,
+    FLAG_MAX_TARGET_Q,
+    FLAG_MAX_TARGET_R,
 ]
 ALL_FLAGS = FLAGS_API_LIST + [
     FLAG_CORE_PLATFORM_API,
@@ -58,7 +76,7 @@
 
 # Suffix used in command line args to express that only known and
 # otherwise unassigned entries should be assign the given flag.
-# For example, the P dark greylist is checked in as it was in P,
+# For example, the max-target-P list is checked in as it was in P,
 # but signatures have changes since then. The flag instructs this
 # script to skip any entries which do not exist any more.
 FLAG_IGNORE_CONFLICTS_SUFFIX = "-ignore-conflicts"
@@ -87,6 +105,7 @@
 HAS_NO_API_LIST_ASSIGNED = lambda api, flags: not FLAGS_API_LIST_SET.intersection(flags)
 IS_SERIALIZATION = lambda api, flags: SERIALIZATION_REGEX.match(api)
 
+
 def get_args():
     """Parses command line arguments.
 
@@ -113,6 +132,7 @@
 
     return parser.parse_args()
 
+
 def read_lines(filename):
     """Reads entire file and return it as a list of lines.
 
@@ -130,8 +150,9 @@
     lines = map(lambda line: line.strip(), lines)
     return set(lines)
 
+
 def write_lines(filename, lines):
-    """Writes list of lines into a file, overwriting the file it it exists.
+    """Writes list of lines into a file, overwriting the file if it exists.
 
     Args:
         filename (string): Path to the file to be writting into.
@@ -141,6 +162,7 @@
     with open(filename, 'w') as f:
         f.writelines(lines)
 
+
 def extract_package(signature):
     """Extracts the package from a signature.
 
@@ -159,6 +181,7 @@
     package_name = full_class_name.rpartition("/")[0]
     return package_name.replace('/', '.')
 
+
 class FlagsDict:
     def __init__(self):
         self._dict_keyset = set()
@@ -182,6 +205,36 @@
             "Please visit go/hiddenapi for more information.").format(
                 source, "\n".join(flags_subset - ALL_FLAGS_SET))
 
+    def convert_to_new_flag(self, flag):
+      """Converts old flag to a new variant.
+
+      Flags that are considered old are replaced with new versions.
+      Otherwise, it is a no-op.
+
+      Args:
+        flag: a string, representing SDK flag.
+
+      Returns:
+         A string. Result of conversion.
+
+      """
+      return OLD_FLAGS_TO_NEW.get(flag, flag)
+
+    def convert_to_old_flag(self, flag):
+      """Converts a new flag to a old variant.
+
+      No-op if there is no suitable old flag.
+      Only used to support backwards compatibility.
+
+      Args:
+        flag: a string, representing SDK flag.
+
+      Returns:
+         A string. Result of conversion.
+
+      """
+      return NEW_FLAGS_TO_OLD.get(flag, flag)
+
     def filter_apis(self, filter_fn):
         """Returns APIs which match a given predicate.
 
@@ -212,10 +265,16 @@
     def generate_csv(self):
         """Constructs CSV entries from a dictionary.
 
+        Old versions of flags are used to generate the file.
+
         Returns:
             List of lines comprising a CSV file. See "parse_and_merge_csv" for format description.
         """
-        return sorted(map(lambda api: ",".join([api] + sorted(self._dict[api])), self._dict))
+        lines = []
+        for api in self._dict:
+          flags = sorted([self.convert_to_old_flag(flag) for flag in self._dict[api]])
+          lines.append(",".join([api] + flags))
+        return sorted(lines)
 
     def parse_and_merge_csv(self, csv_lines, source = "<unknown>"):
         """Parses CSV entries and merges them into a given dictionary.
@@ -237,17 +296,16 @@
         self._dict_keyset.update([ csv[0] for csv in csv_values ])
 
         # Check that all flags are known.
-        csv_flags = set(functools.reduce(
-            lambda x, y: set(x).union(y),
-            [ csv[1:] for csv in csv_values ],
-            []))
+        csv_flags = set()
+        for csv in csv_values:
+          csv_flags.update([self.convert_to_new_flag(flag) for flag in csv[1:]])
         self._check_flags_set(csv_flags, source)
 
         # Iterate over all CSV lines, find entry in dict and append flags to it.
         for csv in csv_values:
-            flags = csv[1:]
+            flags = [self.convert_to_new_flag(flag) for flag in csv[1:]]
             if (FLAG_PUBLIC_API in flags) or (FLAG_SYSTEM_API in flags):
-                flags.append(FLAG_WHITELIST)
+                flags.append(FLAG_SDK)
             self._dict[csv[0]].update(flags)
 
     def assign_flag(self, flag, apis, source="<unknown>"):
@@ -271,6 +329,7 @@
         for api in apis:
             self._dict[api].add(flag)
 
+
 def main(argv):
     # Parse arguments.
     args = vars(get_args())
@@ -287,8 +346,8 @@
         flags.parse_and_merge_csv(read_lines(filename), filename)
 
     # Combine inputs which do not require any particular order.
-    # (1) Assign serialization API to whitelist.
-    flags.assign_flag(FLAG_WHITELIST, flags.filter_apis(IS_SERIALIZATION))
+    # (1) Assign serialization API to SDK.
+    flags.assign_flag(FLAG_SDK, flags.filter_apis(IS_SERIALIZATION))
 
     # (2) Merge text files with a known flag into the dictionary.
     for flag in ALL_FLAGS:
@@ -314,8 +373,8 @@
             valid_entries = flags.filter_apis(should_add_signature_to_list)
             flags.assign_flag(flag, valid_entries)
 
-    # Assign all remaining entries to the blacklist.
-    flags.assign_flag(FLAG_BLACKLIST, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED))
+    # Mark all remaining entries as blocked.
+    flags.assign_flag(FLAG_BLOCKED, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED))
 
     # Write output.
     write_lines(args["output"], flags.generate_csv())
diff --git a/tools/hiddenapi/generate_hiddenapi_lists_test.py b/tools/hiddenapi/generate_hiddenapi_lists_test.py
index 55c3a7d..321c400 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists_test.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists_test.py
@@ -23,7 +23,7 @@
         # Initialize flags so that A and B are put on the whitelist and
         # C, D, E are left unassigned. Try filtering for the unassigned ones.
         flags = FlagsDict()
-        flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B,' + FLAG_WHITELIST,
+        flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B,' + FLAG_SDK,
                         'C', 'D', 'E'])
         filter_set = flags.filter_apis(lambda api, flags: not flags)
         self.assertTrue(isinstance(filter_set, set))
@@ -32,10 +32,10 @@
     def test_get_valid_subset_of_unassigned_keys(self):
         # Create flags where only A is unassigned.
         flags = FlagsDict()
-        flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B', 'C'])
-        flags.assign_flag(FLAG_GREYLIST, set(['C']))
+        flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B', 'C'])
+        flags.assign_flag(FLAG_UNSUPPORTED, set(['C']))
         self.assertEqual(flags.generate_csv(),
-            [ 'A,' + FLAG_WHITELIST, 'B', 'C,' + FLAG_GREYLIST ])
+            [ 'A,' + OLD_FLAG_SDK, 'B', 'C,' + OLD_FLAG_UNSUPPORTED ])
 
         # Check three things:
         # (1) B is selected as valid unassigned
@@ -50,20 +50,21 @@
         # Test empty CSV entry.
         self.assertEqual(flags.generate_csv(), [])
 
-        # Test new additions.
+        # Test new additions. CSV generator produces values with old flags
+        # to be backwards compatible.
         flags.parse_and_merge_csv([
-            'A,' + FLAG_GREYLIST,
-            'B,' + FLAG_BLACKLIST + ',' + FLAG_GREYLIST_MAX_O,
-            'C,' + FLAG_SYSTEM_API + ',' + FLAG_WHITELIST,
-            'D,' + FLAG_GREYLIST+ ',' + FLAG_TEST_API,
-            'E,' + FLAG_BLACKLIST+ ',' + FLAG_TEST_API,
+            'A,' + FLAG_UNSUPPORTED,
+            'B,' + FLAG_BLOCKED + ',' + FLAG_MAX_TARGET_O,
+            'C,' + FLAG_SDK + ',' + FLAG_SYSTEM_API,
+            'D,' + FLAG_UNSUPPORTED + ',' + FLAG_TEST_API,
+            'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API,
         ])
         self.assertEqual(flags.generate_csv(), [
-            'A,' + FLAG_GREYLIST,
-            'B,' + FLAG_BLACKLIST + "," + FLAG_GREYLIST_MAX_O,
-            'C,' + FLAG_SYSTEM_API + ',' + FLAG_WHITELIST,
-            'D,' + FLAG_GREYLIST+ ',' + FLAG_TEST_API,
-            'E,' + FLAG_BLACKLIST+ ',' + FLAG_TEST_API,
+            'A,' + OLD_FLAG_UNSUPPORTED,
+            'B,' + OLD_FLAG_BLOCKED + "," + OLD_FLAG_MAX_TARGET_O,
+            'C,' + FLAG_SYSTEM_API + ',' + OLD_FLAG_SDK,
+            'D,' + OLD_FLAG_UNSUPPORTED + ',' + FLAG_TEST_API,
+            'E,' + OLD_FLAG_BLOCKED + ',' + FLAG_TEST_API,
         ])
 
         # Test unknown flag.
@@ -72,16 +73,16 @@
 
     def test_assign_flag(self):
         flags = FlagsDict()
-        flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B'])
+        flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B'])
 
         # Test new additions.
-        flags.assign_flag(FLAG_GREYLIST, set([ 'A', 'B' ]))
+        flags.assign_flag(FLAG_UNSUPPORTED, set([ 'A', 'B' ]))
         self.assertEqual(flags.generate_csv(),
-            [ 'A,' + FLAG_GREYLIST + "," + FLAG_WHITELIST, 'B,' + FLAG_GREYLIST ])
+            [ 'A,' + OLD_FLAG_UNSUPPORTED + "," + OLD_FLAG_SDK, 'B,' + OLD_FLAG_UNSUPPORTED ])
 
         # Test invalid API signature.
         with self.assertRaises(AssertionError):
-            flags.assign_flag(FLAG_WHITELIST, set([ 'C' ]))
+            flags.assign_flag(FLAG_SDK, set([ 'C' ]))
 
         # Test invalid flag.
         with self.assertRaises(AssertionError):