Merge remote-tracking branch 'goog/upstream-master' into androidx-platform-dev

* goog/upstream-master:
  Sync from upstream

Bug: 184373205
Test: presubmit
Change-Id: Ic8a677e18763f3c516383cc1ca90780b48b58be4
diff --git a/.gitignore b/.gitignore
index f57bd5e..962fbd5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
 
 # Files
 *.iml
+*.cmake.gen
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 556150a..a740924 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,75 +14,69 @@
 
 cmake_minimum_required(VERSION 3.10.2)
 
-# Build protoc with a host configuration. We need to run it on the host to create our proto
-# files.
-set(CMAKE_HOST_ARGS
-  -DBUILD_SHARED_LIBS:BOOL=${BUILD_SHARED_LIBS}
-  -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
-  -DCMAKE_C_COMPILER:STRING=${CMAKE_C_COMPILER}
-  -DCMAKE_CXX_COMPILER:STRING=${CMAKE_CXX_COMPILER}
-  -DCMAKE_GENERATOR:STRING=${CMAKE_GENERATOR}
-  -DCMAKE_MAKE_PROGRAM:FILEPATH=${CMAKE_MAKE_PROGRAM})
+add_definitions("-DICING_REVERSE_JNI_SEGMENTATION=1")
 
+set(
+    Protobuf_PREBUILTS_DIR
+    "${CMAKE_CURRENT_SOURCE_DIR}/../../prebuilts/protobuf")
 set(Protobuf_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../protobuf")
-set(Protobuf_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/protobuf-host")
-# Run another cmake invocation to configure the protobuf project
-execute_process(
-    COMMAND "${CMAKE_COMMAND}"
-    ${CMAKE_HOST_ARGS}
-    -H${Protobuf_SOURCE_DIR}/cmake
-    -B${Protobuf_BINARY_DIR}
-    -Dprotobuf_BUILD_TESTS:BOOL=OFF
-    RESULT_VARIABLE exec_value
-    OUTPUT_VARIABLE exec_output
-    ERROR_VARIABLE exec_output
-)
-message("Result of proto configuration: ${exec_value}. Output: ${exec_output}")
+set(Protobuf_TARGET_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/protobuf-target")
+set(Icing_PROTO_GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/icing-protobuf-gen")
 
-# Run the actual build tool (ninja) to compile protoc for the host
-execute_process(
-    COMMAND "${CMAKE_MAKE_PROGRAM}" protoc
-    WORKING_DIRECTORY ${Protobuf_BINARY_DIR}
-    RESULT_VARIABLE exec_value
-    OUTPUT_VARIABLE exec_output
-    ERROR_VARIABLE exec_output
-)
-message("Result of proto build: ${exec_value}. Output: ${exec_output}")
+## Configure libprotobuf ##
+# Find the right protoc to compile our proto files
+if(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Darwin")
+  set(Protobuf_PROTOC_PATH "${Protobuf_PREBUILTS_DIR}/darwin-x86_64/protoc")
+elseif(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux")
+  set(Protobuf_PROTOC_PATH "${Protobuf_PREBUILTS_DIR}/linux-x86_64/protoc")
+elseif(${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows")
+  set(Protobuf_PROTOC_PATH "${Protobuf_PREBUILTS_DIR}/windows-x86/protoc.exe")
+else()
+  message(
+      FATAL_ERROR
+      "No protoc prebuilt found for host OS ${CMAKE_HOST_SYSTEM_NAME}")
+endif()
+message(STATUS "Using prebuilt protoc at: ${Protobuf_PROTOC_PATH}")
 
-# Glob Icing proto sources
+# Compile libprotobuf
+set(protobuf_BUILD_TESTS OFF CACHE BOOL "")
+add_subdirectory("${Protobuf_SOURCE_DIR}/cmake" ${Protobuf_TARGET_BINARY_DIR})
+
+# Compile libandroidicu
+set(ICU_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../icu/libandroidicu")
+set(ICU_TARGET_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/icu-target")
+add_subdirectory(${ICU_SOURCE_DIR} ${ICU_TARGET_BINARY_DIR})
+
+# Glob Icing proto sources. Results look like this: icing/proto/document.proto
 file(
     GLOB_RECURSE
     Icing_PROTO_FILES
-    RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
-    "icing/*.proto")
+    RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/proto"
+    "*.proto")
 message(STATUS "Icing_PROTO_FILES=${Icing_PROTO_FILES}")
 
+
 # Run protoc on Icing_PROTO_FILES to generate pb.cc and pb.h files
-set(Icing_PROTO_GEN_DIR "${PROTO_GENERATED_FILES_BASE_DIR}/cpp")
+# The DEPENDS section of add_custom_command could trigger a remake if any proto
+# source file has been updated.
 file(MAKE_DIRECTORY ${Icing_PROTO_GEN_DIR})
 foreach(FILE ${Icing_PROTO_FILES})
     # Find the name of the proto file without the .proto extension
     string(REGEX REPLACE "\.proto$" "" FILE_NOEXT ${FILE})
-    execute_process(
-        COMMAND "${Protobuf_BINARY_DIR}/protoc"
-        --proto_path ${CMAKE_CURRENT_SOURCE_DIR}
-        --cpp_out ${Icing_PROTO_GEN_DIR}
-        ${FILE}
+    list(APPEND Icing_PROTO_SOURCES
+      "${Icing_PROTO_GEN_DIR}/${FILE_NOEXT}.pb.cc"
+      "${Icing_PROTO_GEN_DIR}/${FILE_NOEXT}.pb.h")
+    add_custom_command(
+        OUTPUT "${Icing_PROTO_GEN_DIR}/${FILE_NOEXT}.pb.cc"
+          "${Icing_PROTO_GEN_DIR}/${FILE_NOEXT}.pb.h"
+        COMMAND ${Protobuf_PROTOC_PATH}
+          --proto_path "${CMAKE_CURRENT_SOURCE_DIR}/proto"
+          --cpp_out ${Icing_PROTO_GEN_DIR}
+          ${FILE}
         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
-        RESULT_VARIABLE exec_value
-        OUTPUT_VARIABLE exec_output
-        ERROR_VARIABLE exec_output
+        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/proto/${FILE}
     )
-    message("Result of protoc ${FILE}: ${exec_value}. Output: ${exec_output}")
 endforeach()
-
-# Glob generated source files from running protoc
-file(
-    GLOB_RECURSE
-    Icing_PROTO_SOURCES
-    "${Icing_PROTO_GEN_DIR}/*.pb.cc"
-    "${Icing_PROTO_GEN_DIR}/*.pb.h"
-)
 message(STATUS "Icing_PROTO_SOURCES=${Icing_PROTO_SOURCES}")
 
 # Glob Icing C++ sources
@@ -98,11 +92,21 @@
     # Glob expressions
     icing/*.cc icing/*.h
 )
+
+# TODO(b/170611579): When supporting cmake v3.12 or higher, use CONFIGURE_DEPENDS
+# in the glob and remove this section.
+include(synced_AOSP_CL_number.txt)
+
 # Exclude the same types of files as Android.bp. See the comments there.
-list(FILTER Icing_CC_SOURCES EXCLUDE REGEX "^icing/.*_test\.cc$")
+list(FILTER Icing_CC_SOURCES EXCLUDE REGEX "^icing/.*[^a-zA-Z0-9]test[^a-zA-Z0-9].*$")
 list(FILTER Icing_CC_SOURCES EXCLUDE REGEX "^icing/.*_benchmark\.cc$")
+list(FILTER Icing_CC_SOURCES EXCLUDE REGEX "^icing/helpers/icu/.*$")
 list(FILTER Icing_CC_SOURCES EXCLUDE REGEX "^icing/testing/.*$")
+list(FILTER Icing_CC_SOURCES EXCLUDE REGEX "^icing/tokenization/icu/.*$")
+list(FILTER Icing_CC_SOURCES EXCLUDE REGEX "^icing/tokenization/simple/.*$")
 list(FILTER Icing_CC_SOURCES EXCLUDE REGEX "^icing/tools/.*$")
+list(FILTER Icing_CC_SOURCES EXCLUDE REGEX "^icing/transform/icu/.*$")
+list(FILTER Icing_CC_SOURCES EXCLUDE REGEX "^icing/transform/simple/.*$")
 message(STATUS "Icing_CC_SOURCES=${Icing_CC_SOURCES}")
 
 add_library(
@@ -119,3 +123,5 @@
 target_include_directories(icing PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
 target_include_directories(icing PRIVATE ${Icing_PROTO_GEN_DIR})
 target_include_directories(icing PRIVATE "${Protobuf_SOURCE_DIR}/src")
+target_include_directories(icing PRIVATE "${ICU_SOURCE_DIR}/include")
+target_link_libraries(icing protobuf::libprotobuf libandroidicu log)
diff --git a/build.gradle b/build.gradle
index 30265cd..437f57f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -14,63 +14,55 @@
  * limitations under the License.
  */
 
+import static androidx.build.SupportConfig.*
+import static androidx.build.dependencies.DependenciesKt.*
+
 buildscript {
-    boolean unbundleBuild = (new File('unbundled-build')).exists()
-    repositories {
-        maven { url '../../prebuilts/androidx/external' }
-        if (unbundleBuild) {
-            jcenter()
-        }
-    }
     dependencies {
-        classpath('gradle.plugin.com.google.protobuf:protobuf-gradle-plugin:0.8.8')
+        classpath('gradle.plugin.com.google.protobuf:protobuf-gradle-plugin:0.8.13')
     }
 }
 
-apply plugin: 'AndroidXPlugin'
-apply plugin: 'com.android.library'
-apply plugin: 'com.google.protobuf'
-apply plugin: 'idea'
-
-def protoGeneratedFilesBaseDir = "${project.buildDir}/generated/source/proto"
+plugins {
+    id('com.android.library')
+    id('com.google.protobuf')
+}
 
 android {
+    buildToolsVersion BUILD_TOOLS_VERSION
+    compileSdkVersion COMPILE_SDK_VERSION
     defaultConfig {
-        externalNativeBuild {
-            cmake {
-                arguments "-DPROTO_GENERATED_FILES_BASE_DIR=${protoGeneratedFilesBaseDir}"
-                cppFlags "-std=c++17"
-                arguments "-DCMAKE_VERBOSE_MAKEFILE=ON"
-                targets "icing"
-            }
-        }
+        minSdkVersion DEFAULT_MIN_SDK_VERSION
+        targetSdkVersion TARGET_SDK_VERSION
+        testInstrumentationRunner INSTRUMENTATION_RUNNER
     }
-
+    compileOptions {
+        sourceCompatibility = JavaVersion.VERSION_1_8
+        targetCompatibility = JavaVersion.VERSION_1_8
+    }
     sourceSets {
         main {
+            java.srcDir 'java/src/'
             manifest.srcFile 'AndroidManifest.xml'
-            proto {
-                srcDir '.'
-                include '**/*.proto'
-            }
+            proto.srcDir 'proto/'
         }
-    }
-
-    externalNativeBuild {
-        cmake {
-            version '3.10.2'
-            // TODO(b/149853706): Uncomment this line once the lib fully compiles under cmake
-            //path 'CMakeLists.txt'
-        }
+        // TODO(b/161205849): Re-enable this test once icing nativeLib is no longer being built
+        //  inside appsearch:appsearch.
+        //androidTest.java.srcDir 'java/tests/instrumentation/'
     }
 }
 
 dependencies {
-    api('com.google.protobuf:protobuf-javalite:3.10.0')
+    api('androidx.annotation:annotation:1.1.0')
+
+    implementation('com.google.protobuf:protobuf-javalite:3.10.0')
+
+    androidTestImplementation(ANDROIDX_TEST_CORE)
+    androidTestImplementation(ANDROIDX_TEST_RULES)
+    androidTestImplementation(TRUTH)
 }
 
 protobuf {
-    generatedFilesBaseDir = protoGeneratedFilesBaseDir
     protoc {
         artifact = 'com.google.protobuf:protoc:3.10.0'
     }
@@ -85,3 +77,27 @@
         }
     }
 }
+
+// Create export artifact for all variants (debug/release) for JarJaring
+android.libraryVariants.all { variant ->
+    def variantName = variant.name
+    def suffix = variantName.capitalize()
+    def exportJarTask = tasks.register("exportJar${suffix}", Jar) {
+        archiveBaseName.set("icing-${variantName}")
+
+        // The proto-lite dependency includes .proto files, which are not used by icing. When apps
+        // depend on appsearch as well as proto-lite directly, these files conflict since jarjar
+        // only renames the java classes. Remove them here since they are unused.
+        // Expand the jar and remove any .proto files.
+        from(zipTree(configurations.detachedConfiguration(
+                dependencies.create(PROTOBUF_LITE)).getSingleFile())) {
+            exclude("**/*.proto")
+        }
+
+        from files(variant.javaCompileProvider.get().destinationDir)
+        dependsOn variant.javaCompileProvider.get()
+    }
+
+    def exportConfiguration = configurations.register("export${suffix}")
+    artifacts.add(exportConfiguration.name, exportJarTask.flatMap { it.archiveFile })
+}
diff --git a/nativeLib/build.gradle b/nativeLib/build.gradle
new file mode 100644
index 0000000..6b30451
--- /dev/null
+++ b/nativeLib/build.gradle
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+// TODO(b/161205849): We've had to move libicing.so compilation into appsearch:appsearch to get
+//  it included into the exported aar. Find a proper solution for bundling libicing.so into
+//  appsearch-release.aar and move compilation of libicing.so back into the external/icing tree.