Android patch: Remove property android.icu.impl.ICUBinary.dataPath for apps targeting S+

This CL alone does not remove the property yet, because it provides
the replacement to set ICU4J data directories. The prebuilts and
libcore need to be updated to remove the property.

Pros:
1. The data directories are currently visible to app, but it's not
   intended, because the data files and file format are the internal
   implementation details.
2. having a recursive dependency between the ART module and the I18N
   module can be avoided, and the relationship simplified, by no longer
   relying on system properties to initialize ICU4J. Otherwise,
   ART modules needs to ask the I18N module where the files are,
   so it can set a system property, which tells the I18N module how
   to initialize.
   Instead, lazily generate the list of data directories when
   ICUBinary class is initialized.
3. Can remove the @IntraCoreApi TimeZoneDataFiles.generateIcuDataPath()
   in the CL after the ART prebuilts is updated.

Cons:
1. Maintain a large patch in ICU4J.

Note:
- TimeZoneDataFiles is removed from timezone-host target because
  it's not used, and avoid new dependency on AndroidDataFiles.

Bug: 171979766
Bug: 139480281
Test: ant core (using the upstream icu4j build system)
Test: ./updatecldrdata.py
Test: m droid cts
Test: CtsIcuTestCases
Change-Id: I63ce8b5bcf6da731b0a8f83aa9ea549d64c075d5
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/ICUBinary.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/ICUBinary.java
index c497cc2..bd4e8de 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/ICUBinary.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/ICUBinary.java
@@ -24,6 +24,7 @@
 import java.util.MissingResourceException;
 import java.util.Set;
 
+import com.ibm.icu.platform.AndroidDataFiles;
 import com.ibm.icu.util.ICUUncheckedIOException;
 import com.ibm.icu.util.VersionInfo;
 
@@ -281,8 +282,17 @@
     private static final List<DataFile> icuDataFiles = new ArrayList<>();
 
     static {
+        // BEGIN Android-changed: Initialize ICU data file paths.
+        /*
         // Normally com.ibm.icu.impl.ICUBinary.dataPath.
         String dataPath = ICUConfig.get(ICUBinary.class.getName() + ".dataPath");
+        */
+        String dataPath = null;
+        // Only when runs after repackaging ICU4J. Otherwise the jar should have the ICU resources.
+        if (ICUBinary.class.getName().startsWith("android.icu")) {
+            dataPath = AndroidDataFiles.generateIcuDataPath();
+        }
+        // END Android-changed: Initialize ICU data file paths.
         if (dataPath != null) {
             addDataFilesFromPath(dataPath, icuDataFiles);
         }
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/platform/AndroidDataFiles.java b/icu4j/main/classes/core/src/com/ibm/icu/platform/AndroidDataFiles.java
new file mode 100644
index 0000000..e599957
--- /dev/null
+++ b/icu4j/main/classes/core/src/com/ibm/icu/platform/AndroidDataFiles.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 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 com.ibm.icu.platform;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Android-added: Used by {@link com.ibm.icu.impl.ICUBinary} to locate ICU data files.
+ * The paths to ICU data files are generated dynamically from environment variables because
+ * the paths are different in various test environments. Thus, the paths can't be generated into
+ * ICUConfig.properties in the compile-time, and generated by this class instead.
+ *
+ * {@link com.android.i18n.timezone.TimeZoneDataFiles} holds the information related to other
+ * timezone data files.
+ */
+public class AndroidDataFiles {
+    /**
+     * The below are public to be used by {@link com.android.i18n.timezone.TimeZoneDataFiles}.
+     */
+    public static final String ANDROID_ROOT_ENV = "ANDROID_ROOT";
+    public static final String ANDROID_I18N_ROOT_ENV = "ANDROID_I18N_ROOT";
+    public static final String ANDROID_TZDATA_ROOT_ENV = "ANDROID_TZDATA_ROOT";
+    public static final String ANDROID_DATA_ENV = "ANDROID_DATA";
+
+    // VisibleForTesting
+    public static String getTimeZoneModuleIcuFile(String fileName) {
+        return getTimeZoneModuleFile("icu/" + fileName);
+    }
+
+    private static String getTimeZoneModuleFile(String fileName) {
+        return System.getenv(ANDROID_TZDATA_ROOT_ENV) + "/etc/" + fileName;
+    }
+
+    // VisibleForTesting
+    public static String getI18nModuleIcuFile(String fileName) {
+        return getI18nModuleFile("icu/" + fileName);
+    }
+
+    private static String getI18nModuleFile(String fileName) {
+        return System.getenv(ANDROID_I18N_ROOT_ENV) + "/etc/" + fileName;
+    }
+
+    public static String generateIcuDataPath() {
+        List<String> paths = new ArrayList<>(3);
+
+        // Note: This logic below should match the logic in IcuRegistration.cpp in external/icu/
+        // to ensure consistent behavior between ICU4C and ICU4J.
+
+        // ICU should first look in ANDROID_DATA. This is used for (optional) time zone data
+        // delivered by APK (https://source.android.com/devices/tech/config/timezone-rules)
+        String dataIcuDataPath =
+                getEnvironmentPath(ANDROID_DATA_ENV, "/misc/zoneinfo/current/icu/");
+        if (dataIcuDataPath != null) {
+            paths.add(dataIcuDataPath);
+        }
+
+        // ICU should then look for a mounted time zone module file in /apex. This is used for
+        // (optional) time zone data that can be updated with an APEX file.
+        String timeZoneModuleIcuDataPath = getTimeZoneModuleIcuFile("");
+        paths.add(timeZoneModuleIcuDataPath);
+
+        // ICU should always look in the i18n module path as this is where most of the data
+        // can be found.
+        String i18nModuleIcuDataPath = getI18nModuleIcuFile("");
+        paths.add(i18nModuleIcuDataPath);
+
+        return String.join(":", paths);
+    }
+
+    /**
+     * Creates a path by combining the value of an environment variable with a relative path.
+     * Returns {@code null} if the environment variable is not set.
+     */
+    private static String getEnvironmentPath(String environmentVariable, String path) {
+        String variable = System.getenv(environmentVariable);
+        if (variable == null) {
+            return null;
+        }
+        return variable + path;
+    }
+}