diff --git a/firebase-common/firebase-common.gradle.kts b/firebase-common/firebase-common.gradle.kts
index ae4fd4292ec..18ac5764ce9 100644
--- a/firebase-common/firebase-common.gradle.kts
+++ b/firebase-common/firebase-common.gradle.kts
@@ -14,6 +14,7 @@
plugins {
id("firebase-library")
+ id("kotlin-android")
}
firebaseLibrary {
@@ -56,6 +57,8 @@ dependencies {
implementation(libs.androidx.futures)
implementation(libs.playservices.basement)
implementation(libs.playservices.tasks)
+ api(libs.kotlin.coroutines.tasks)
+ implementation(libs.kotlin.stdlib)
annotationProcessor(libs.autovalue)
@@ -73,6 +76,8 @@ dependencies {
testImplementation(libs.org.json)
testImplementation(libs.robolectric)
testImplementation(libs.truth)
+ testImplementation(libs.androidx.test.core)
+ testImplementation(libs.kotlin.coroutines.test)
androidTestImplementation(libs.androidx.test.junit)
androidTestImplementation(libs.androidx.test.runner)
diff --git a/firebase-common/ktx/ktx.gradle.kts b/firebase-common/ktx/ktx.gradle.kts
index eb0218a0948..2fbd7e06062 100644
--- a/firebase-common/ktx/ktx.gradle.kts
+++ b/firebase-common/ktx/ktx.gradle.kts
@@ -42,16 +42,10 @@ android {
}
dependencies {
- implementation(libs.kotlin.stdlib)
-
- implementation("com.google.firebase:firebase-annotations:16.2.0")
- implementation(project(":firebase-common"))
- implementation("com.google.firebase:firebase-components:17.1.0")
- implementation(libs.androidx.annotation)
+ api(project(":firebase-common"))
// We"re exposing this library as a transitive dependency so developers can
// get Kotlin Coroutines support out-of-the-box for methods that return a Task
- api(libs.kotlin.coroutines.tasks)
testImplementation(libs.robolectric)
testImplementation(libs.junit)
diff --git a/firebase-common/ktx/src/main/AndroidManifest.xml b/firebase-common/ktx/src/main/AndroidManifest.xml
deleted file mode 100644
index 05858c6eb7b..00000000000
--- a/firebase-common/ktx/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/firebase-common/src/main/AndroidManifest.xml b/firebase-common/src/main/AndroidManifest.xml
index a2913a3a915..718739377e5 100644
--- a/firebase-common/src/main/AndroidManifest.xml
+++ b/firebase-common/src/main/AndroidManifest.xml
@@ -29,6 +29,10 @@
android:name="com.google.firebase.components.ComponentDiscoveryService"
android:directBootAware="true"
android:exported="false"
- tools:targetApi="n" />
+ tools:targetApi="n" >
+
+
+
diff --git a/firebase-common/ktx/src/main/kotlin/com/google/firebase/ktx/Firebase.kt b/firebase-common/src/main/java/com/google/firebase/Firebase.kt
similarity index 96%
rename from firebase-common/ktx/src/main/kotlin/com/google/firebase/ktx/Firebase.kt
rename to firebase-common/src/main/java/com/google/firebase/Firebase.kt
index 058c0f20626..e1e1187828f 100644
--- a/firebase-common/ktx/src/main/kotlin/com/google/firebase/ktx/Firebase.kt
+++ b/firebase-common/src/main/java/com/google/firebase/Firebase.kt
@@ -11,12 +11,10 @@
// 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.google.firebase.ktx
+package com.google.firebase
import android.content.Context
import androidx.annotation.Keep
-import com.google.firebase.FirebaseApp
-import com.google.firebase.FirebaseOptions
import com.google.firebase.annotations.concurrent.Background
import com.google.firebase.annotations.concurrent.Blocking
import com.google.firebase.annotations.concurrent.Lightweight
diff --git a/firebase-common/src/main/java/com/google/firebase/ktx/Firebase.kt b/firebase-common/src/main/java/com/google/firebase/ktx/Firebase.kt
new file mode 100644
index 00000000000..9620d1bb010
--- /dev/null
+++ b/firebase-common/src/main/java/com/google/firebase/ktx/Firebase.kt
@@ -0,0 +1,60 @@
+// Copyright 2019 Google LLC
+//
+// 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.google.firebase.ktx
+
+import android.content.Context
+import androidx.annotation.Keep
+import com.google.firebase.FirebaseApp
+import com.google.firebase.FirebaseOptions
+import com.google.firebase.components.Component
+import com.google.firebase.components.ComponentRegistrar
+
+/**
+ * Single access point to all firebase SDKs from Kotlin.
+ *
+ *
Acts as a target for extension methods provided by sdks.
+ */
+object Firebase
+
+/** Returns the default firebase app instance. */
+val Firebase.app: FirebaseApp
+ get() = FirebaseApp.getInstance()
+
+/** Returns a named firebase app instance. */
+fun Firebase.app(name: String): FirebaseApp = FirebaseApp.getInstance(name)
+
+/** Initializes and returns a FirebaseApp. */
+fun Firebase.initialize(context: Context): FirebaseApp? = FirebaseApp.initializeApp(context)
+
+/** Initializes and returns a FirebaseApp. */
+fun Firebase.initialize(context: Context, options: FirebaseOptions): FirebaseApp =
+ FirebaseApp.initializeApp(context, options)
+
+/** Initializes and returns a FirebaseApp. */
+fun Firebase.initialize(context: Context, options: FirebaseOptions, name: String): FirebaseApp =
+ FirebaseApp.initializeApp(context, options, name)
+
+/** Returns options of default FirebaseApp */
+val Firebase.options: FirebaseOptions
+ get() = Firebase.app.options
+
+internal const val LIBRARY_NAME: String = "fire-core-ktx"
+
+/** @suppress */
+@Keep
+class FirebaseCommonKtxRegistrar : ComponentRegistrar {
+ override fun getComponents(): List> {
+ return listOf()
+ }
+}
diff --git a/firebase-common/src/test/java/com/google/firebase/Tests.kt b/firebase-common/src/test/java/com/google/firebase/Tests.kt
new file mode 100644
index 00000000000..76b561159a2
--- /dev/null
+++ b/firebase-common/src/test/java/com/google/firebase/Tests.kt
@@ -0,0 +1,140 @@
+// Copyright 2019 Google LLC
+//
+// 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.google.firebase
+
+import androidx.test.core.app.ApplicationProvider
+import com.google.android.gms.tasks.Tasks
+import com.google.common.truth.Truth.assertThat
+import com.google.firebase.platforminfo.UserAgentPublisher
+import kotlinx.coroutines.tasks.await
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.fail
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+
+fun withApp(name: String, block: FirebaseApp.() -> Unit) {
+ val app =
+ Firebase.initialize(
+ ApplicationProvider.getApplicationContext(),
+ FirebaseOptions.Builder().setApplicationId("appId").build(),
+ name
+ )
+ try {
+ block(app)
+ } finally {
+ app.delete()
+ }
+}
+
+class TestException(message: String) : Exception(message)
+
+@RunWith(RobolectricTestRunner::class)
+class VersionTests {
+ @Test
+ fun libraryVersions_shouldBeRegisteredWithRuntime() {
+ withApp("ktxTestApp") {
+ val uaPublisher = get(UserAgentPublisher::class.java)
+ assertThat(uaPublisher.userAgent).contains("kotlin")
+ assertThat(uaPublisher.userAgent).contains(LIBRARY_NAME)
+ }
+ }
+}
+
+@RunWith(RobolectricTestRunner::class)
+class KtxTests {
+ @Test
+ fun `Firebase#app should delegate to FirebaseApp#getInstance()`() {
+ withApp(FirebaseApp.DEFAULT_APP_NAME) {
+ assertThat(Firebase.app).isSameInstanceAs(FirebaseApp.getInstance())
+ }
+ }
+
+ @Test
+ fun `Firebase#app(String) should delegate to FirebaseApp#getInstance(String)`() {
+ val appName = "testApp"
+ withApp(appName) {
+ assertThat(Firebase.app(appName)).isSameInstanceAs(FirebaseApp.getInstance(appName))
+ }
+ }
+
+ @Test
+ fun `Firebase#options should delegate to FirebaseApp#getInstance()#options`() {
+ withApp(FirebaseApp.DEFAULT_APP_NAME) {
+ assertThat(Firebase.options).isSameInstanceAs(FirebaseApp.getInstance().options)
+ }
+ }
+
+ @Test
+ fun `Firebase#initialize(Context, FirebaseOptions) should initialize the app correctly`() {
+ val options = FirebaseOptions.Builder().setApplicationId("appId").build()
+ val app = Firebase.initialize(ApplicationProvider.getApplicationContext(), options)
+ try {
+ assertThat(app).isNotNull()
+ assertThat(app.name).isEqualTo(FirebaseApp.DEFAULT_APP_NAME)
+ assertThat(app.options).isSameInstanceAs(options)
+ assertThat(app.applicationContext)
+ .isSameInstanceAs(ApplicationProvider.getApplicationContext())
+ } finally {
+ app.delete()
+ }
+ }
+
+ @Test
+ fun `Firebase#initialize(Context, FirebaseOptions, String) should initialize the app correctly`() {
+ val options = FirebaseOptions.Builder().setApplicationId("appId").build()
+ val name = "appName"
+ val app = Firebase.initialize(ApplicationProvider.getApplicationContext(), options, name)
+ try {
+ assertThat(app).isNotNull()
+ assertThat(app.name).isEqualTo(name)
+ assertThat(app.options).isSameInstanceAs(options)
+ assertThat(app.applicationContext)
+ .isSameInstanceAs(ApplicationProvider.getApplicationContext())
+ } finally {
+ app.delete()
+ }
+ }
+}
+
+class CoroutinesPlayServicesTests {
+ // We are only interested in the await() function offered by kotlinx-coroutines-play-services
+ // So we're not testing the other functions provided by that library.
+
+ @Test
+ fun `Task#await() resolves to the same result as Task#getResult()`() = runTest {
+ val task = Tasks.forResult(21)
+
+ val expected = task.result
+ val actual = task.await()
+
+ assertThat(actual).isEqualTo(expected)
+ assertThat(task.isSuccessful).isTrue()
+ assertThat(task.exception).isNull()
+ }
+
+ @Test
+ fun `Task#await() throws an Exception for failing Tasks`() = runTest {
+ val task = Tasks.forException(TestException("some error happened"))
+
+ try {
+ task.await()
+ fail("Task#await should throw an Exception")
+ } catch (e: Exception) {
+ assertThat(e).isInstanceOf(TestException::class.java)
+ assertThat(task.isSuccessful).isFalse()
+ }
+ }
+}
diff --git a/firebase-common/ktx/src/test/kotlin/com/google/firebase/ktx/Tests.kt b/firebase-common/src/test/java/com/google/firebase/ktx/Tests.kt
similarity index 100%
rename from firebase-common/ktx/src/test/kotlin/com/google/firebase/ktx/Tests.kt
rename to firebase-common/src/test/java/com/google/firebase/ktx/Tests.kt
diff --git a/firebase-functions/firebase-functions.gradle.kts b/firebase-functions/firebase-functions.gradle.kts
index f3d09f893c3..410449983b5 100644
--- a/firebase-functions/firebase-functions.gradle.kts
+++ b/firebase-functions/firebase-functions.gradle.kts
@@ -15,6 +15,7 @@
plugins {
id("firebase-library")
id("firebase-vendor")
+ id("kotlin-android")
}
firebaseLibrary {
@@ -46,7 +47,7 @@ android {
dependencies {
implementation("com.google.firebase:firebase-annotations:16.2.0")
- implementation("com.google.firebase:firebase-common:20.3.1")
+ implementation(project(":firebase-common"))
implementation("com.google.firebase:firebase-components:17.1.0")
implementation(project(":appcheck:firebase-appcheck-interop"))
implementation(libs.playservices.base)
diff --git a/firebase-functions/ktx/ktx.gradle.kts b/firebase-functions/ktx/ktx.gradle.kts
index fc16e4fd407..cda586a2d2e 100644
--- a/firebase-functions/ktx/ktx.gradle.kts
+++ b/firebase-functions/ktx/ktx.gradle.kts
@@ -44,18 +44,19 @@ android {
}
dependencies {
- implementation("com.google.firebase:firebase-common:20.3.1")
- implementation("com.google.firebase:firebase-components:17.1.0")
- implementation("com.google.firebase:firebase-common-ktx:20.3.1")
- implementation(project(":firebase-functions"))
- implementation(libs.kotlin.stdlib)
- implementation(libs.androidx.annotation)
- implementation(libs.playservices.tasks)
+ api(project(":firebase-functions"))
+ androidTestImplementation(project(":firebase-common"))
+ androidTestImplementation("com.google.firebase:firebase-components:17.1.0")
+ androidTestImplementation(project(":firebase-common:ktx"))
androidTestImplementation(libs.junit)
androidTestImplementation(libs.truth)
androidTestImplementation(libs.androidx.test.runner)
+ testImplementation(project(":firebase-common"))
+ testImplementation("com.google.firebase:firebase-components:17.1.0")
+ testImplementation(project(":firebase-common:ktx"))
+
testImplementation(libs.robolectric)
testImplementation(libs.junit)
testImplementation(libs.truth)
diff --git a/firebase-functions/ktx/src/main/AndroidManifest.xml b/firebase-functions/ktx/src/main/AndroidManifest.xml
deleted file mode 100644
index 28c8c25d8cd..00000000000
--- a/firebase-functions/ktx/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/firebase-functions/ktx/src/test/kotlin/com/google/firebase/functions/ktx/FunctionsTests.kt b/firebase-functions/ktx/src/test/kotlin/com/google/firebase/functions/ktx/FunctionsTests.kt
index 7c5655902e1..671ac2a2d59 100644
--- a/firebase-functions/ktx/src/test/kotlin/com/google/firebase/functions/ktx/FunctionsTests.kt
+++ b/firebase-functions/ktx/src/test/kotlin/com/google/firebase/functions/ktx/FunctionsTests.kt
@@ -99,7 +99,7 @@ class LibraryVersionTest : BaseTestCase() {
@Test
fun `library version should be registered with runtime`() {
val publisher = Firebase.app.get(UserAgentPublisher::class.java)
- assertThat(publisher.userAgent).contains(LIBRARY_NAME)
+ assertThat(publisher.userAgent).contains("fire-fun-ktx")
}
}
diff --git a/firebase-functions/src/androidTest/java/com/google/firebase/functions/CallTests.kt b/firebase-functions/src/androidTest/java/com/google/firebase/functions/CallTests.kt
new file mode 100644
index 00000000000..54b547bb1c0
--- /dev/null
+++ b/firebase-functions/src/androidTest/java/com/google/firebase/functions/CallTests.kt
@@ -0,0 +1,91 @@
+// Copyright 2019 Google LLC
+//
+// 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.google.firebase.functions
+
+import androidx.test.InstrumentationRegistry
+import androidx.test.runner.AndroidJUnit4
+import com.google.android.gms.tasks.Tasks
+import com.google.common.truth.Truth.assertThat
+import com.google.firebase.Firebase
+import com.google.firebase.FirebaseApp
+import com.google.firebase.app
+import com.google.firebase.initialize
+import org.junit.AfterClass
+import org.junit.BeforeClass
+import org.junit.Test
+import org.junit.runner.RunWith
+
+const val APP_ID = "APP_ID"
+const val API_KEY = "API_KEY"
+
+@RunWith(AndroidJUnit4::class)
+class CallTests {
+ companion object {
+ lateinit var app: FirebaseApp
+
+ @BeforeClass
+ @JvmStatic
+ fun setup() {
+ app = Firebase.initialize(InstrumentationRegistry.getContext())!!
+ }
+
+ @AfterClass
+ @JvmStatic
+ fun cleanup() {
+ app.delete()
+ }
+ }
+
+ @Test
+ fun testDataCall() {
+ val functions = Firebase.functions(app)
+ val input =
+ hashMapOf(
+ "bool" to true,
+ "int" to 2,
+ "long" to 3L,
+ "string" to "four",
+ "array" to listOf(5, 6),
+ "null" to null
+ )
+
+ var function = functions.getHttpsCallable("dataTest")
+ val actual = Tasks.await(function.call(input)).getData()
+
+ assertThat(actual).isInstanceOf(Map::class.java)
+ @Suppress("UNCHECKED_CAST") val map = actual as Map
+ assertThat(map["message"]).isEqualTo("stub response")
+ assertThat(map["code"]).isEqualTo(42)
+ assertThat(map["long"]).isEqualTo(420L)
+ }
+
+ @Test
+ fun testNullDataCall() {
+ val functions = Firebase.functions(app)
+ var function = functions.getHttpsCallable("nullTest")
+ val actual = Tasks.await(function.call(null)).getData()
+
+ assertThat(actual).isNull()
+ }
+
+ @Test
+ fun testEmptyDataCall() {
+ val functions = Firebase.functions(app)
+ var function = functions.getHttpsCallable("nullTest")
+ val actual = Tasks.await(function.call()).getData()
+
+ assertThat(actual).isNull()
+ }
+}
diff --git a/firebase-functions/src/androidTest/java/com/google/firebase/functions/ktx/CallTests.kt b/firebase-functions/src/androidTest/java/com/google/firebase/functions/ktx/CallTests.kt
new file mode 100644
index 00000000000..45361539f1b
--- /dev/null
+++ b/firebase-functions/src/androidTest/java/com/google/firebase/functions/ktx/CallTests.kt
@@ -0,0 +1,91 @@
+// Copyright 2019 Google LLC
+//
+// 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.google.firebase.functions.ktx
+
+import androidx.test.InstrumentationRegistry
+import androidx.test.runner.AndroidJUnit4
+import com.google.android.gms.tasks.Tasks
+import com.google.common.truth.Truth.assertThat
+import com.google.firebase.Firebase
+import com.google.firebase.FirebaseApp
+import com.google.firebase.app
+import com.google.firebase.initialize
+import org.junit.AfterClass
+import org.junit.BeforeClass
+import org.junit.Test
+import org.junit.runner.RunWith
+
+const val APP_ID = "APP_ID"
+const val API_KEY = "API_KEY"
+
+@RunWith(AndroidJUnit4::class)
+class CallTests {
+ companion object {
+ lateinit var app: FirebaseApp
+
+ @BeforeClass
+ @JvmStatic
+ fun setup() {
+ app = Firebase.initialize(InstrumentationRegistry.getContext())!!
+ }
+
+ @AfterClass
+ @JvmStatic
+ fun cleanup() {
+ app.delete()
+ }
+ }
+
+ @Test
+ fun testDataCall() {
+ val functions = Firebase.functions(app)
+ val input =
+ hashMapOf(
+ "bool" to true,
+ "int" to 2,
+ "long" to 3L,
+ "string" to "four",
+ "array" to listOf(5, 6),
+ "null" to null
+ )
+
+ var function = functions.getHttpsCallable("dataTest")
+ val actual = Tasks.await(function.call(input)).getData()
+
+ assertThat(actual).isInstanceOf(Map::class.java)
+ @Suppress("UNCHECKED_CAST") val map = actual as Map
+ assertThat(map["message"]).isEqualTo("stub response")
+ assertThat(map["code"]).isEqualTo(42)
+ assertThat(map["long"]).isEqualTo(420L)
+ }
+
+ @Test
+ fun testNullDataCall() {
+ val functions = Firebase.functions(app)
+ var function = functions.getHttpsCallable("nullTest")
+ val actual = Tasks.await(function.call(null)).getData()
+
+ assertThat(actual).isNull()
+ }
+
+ @Test
+ fun testEmptyDataCall() {
+ val functions = Firebase.functions(app)
+ var function = functions.getHttpsCallable("nullTest")
+ val actual = Tasks.await(function.call()).getData()
+
+ assertThat(actual).isNull()
+ }
+}
diff --git a/firebase-functions/src/main/AndroidManifest.xml b/firebase-functions/src/main/AndroidManifest.xml
index 241d9ae04ea..9402a26cb1d 100644
--- a/firebase-functions/src/main/AndroidManifest.xml
+++ b/firebase-functions/src/main/AndroidManifest.xml
@@ -8,6 +8,8 @@
+
diff --git a/firebase-functions/ktx/src/main/kotlin/com/google/firebase/functions/ktx/Functions.kt b/firebase-functions/src/main/java/com/google/firebase/functions/Functions.kt
similarity index 91%
rename from firebase-functions/ktx/src/main/kotlin/com/google/firebase/functions/ktx/Functions.kt
rename to firebase-functions/src/main/java/com/google/firebase/functions/Functions.kt
index 65464fd9906..3435737f980 100644
--- a/firebase-functions/ktx/src/main/kotlin/com/google/firebase/functions/ktx/Functions.kt
+++ b/firebase-functions/src/main/java/com/google/firebase/functions/Functions.kt
@@ -12,16 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.firebase.functions.ktx
+package com.google.firebase.functions
import androidx.annotation.Keep
+import com.google.firebase.Firebase
import com.google.firebase.FirebaseApp
import com.google.firebase.components.Component
import com.google.firebase.components.ComponentRegistrar
-import com.google.firebase.functions.FirebaseFunctions
-import com.google.firebase.functions.HttpsCallableOptions
-import com.google.firebase.functions.HttpsCallableReference
-import com.google.firebase.ktx.Firebase
import com.google.firebase.platforminfo.LibraryVersionComponent
import java.net.URL
diff --git a/firebase-functions/src/main/java/com/google/firebase/functions/ktx/Functions.kt b/firebase-functions/src/main/java/com/google/firebase/functions/ktx/Functions.kt
new file mode 100644
index 00000000000..df329157486
--- /dev/null
+++ b/firebase-functions/src/main/java/com/google/firebase/functions/ktx/Functions.kt
@@ -0,0 +1,72 @@
+// Copyright 2019 Google LLC
+//
+// 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.google.firebase.functions.ktx
+
+import androidx.annotation.Keep
+import com.google.firebase.FirebaseApp
+import com.google.firebase.components.Component
+import com.google.firebase.components.ComponentRegistrar
+import com.google.firebase.functions.BuildConfig
+import com.google.firebase.functions.FirebaseFunctions
+import com.google.firebase.functions.HttpsCallableOptions
+import com.google.firebase.functions.HttpsCallableReference
+import com.google.firebase.ktx.Firebase
+import com.google.firebase.platforminfo.LibraryVersionComponent
+import java.net.URL
+
+/** Returns the [FirebaseFunctions] instance of the default [FirebaseApp]. */
+val Firebase.functions: FirebaseFunctions
+ get() = com.google.firebase.functions.FirebaseFunctions.getInstance()
+
+/** Returns the [FirebaseFunctions] instance of a given [regionOrCustomDomain]. */
+fun Firebase.functions(regionOrCustomDomain: String): FirebaseFunctions =
+ com.google.firebase.functions.FirebaseFunctions.getInstance(regionOrCustomDomain)
+
+/** Returns the [FirebaseFunctions] instance of a given [FirebaseApp]. */
+fun Firebase.functions(app: FirebaseApp): FirebaseFunctions =
+ com.google.firebase.functions.FirebaseFunctions.getInstance(app)
+
+/** Returns the [FirebaseFunctions] instance of a given [FirebaseApp] and [regionOrCustomDomain]. */
+fun Firebase.functions(app: FirebaseApp, regionOrCustomDomain: String): FirebaseFunctions =
+ com.google.firebase.functions.FirebaseFunctions.getInstance(app, regionOrCustomDomain)
+
+internal const val LIBRARY_NAME: String = "fire-fun-ktx"
+
+/** @suppress */
+@Keep
+class FirebaseFunctionsKtxRegistrar : ComponentRegistrar {
+ override fun getComponents(): List> =
+ listOf(LibraryVersionComponent.create(LIBRARY_NAME, BuildConfig.VERSION_NAME))
+}
+
+/** Returns a reference to the Callable HTTPS trigger with the given name and call options. */
+fun FirebaseFunctions.getHttpsCallable(
+ name: String,
+ init: HttpsCallableOptions.Builder.() -> Unit
+): HttpsCallableReference {
+ val builder = HttpsCallableOptions.Builder()
+ builder.init()
+ return getHttpsCallable(name, builder.build())
+}
+
+/** Returns a reference to the Callable HTTPS trigger with the given URL and call options. */
+fun FirebaseFunctions.getHttpsCallableFromUrl(
+ url: URL,
+ init: HttpsCallableOptions.Builder.() -> Unit
+): HttpsCallableReference {
+ val builder = HttpsCallableOptions.Builder()
+ builder.init()
+ return getHttpsCallableFromUrl(url, builder.build())
+}
diff --git a/firebase-functions/src/test/java/com/google/firebase/functions/TestVisibilityUtil.kt b/firebase-functions/src/test/java/com/google/firebase/functions/TestVisibilityUtil.kt
new file mode 100644
index 00000000000..ead456bb9e3
--- /dev/null
+++ b/firebase-functions/src/test/java/com/google/firebase/functions/TestVisibilityUtil.kt
@@ -0,0 +1,20 @@
+// Copyright 2023 Google LLC
+//
+// 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.google.firebase.functions
+
+/**
+ * Returns true if the {@link HttpsCallableReference} is configured to use FAC limited-use tokens.
+ */
+fun HttpsCallableReference.usesLimitedUseFacTokens() = options.getLimitedUseAppCheckTokens()