Add Data#containsKey API.

* Add Kotlin extensions with reified types.

Test: Added unit tests.
Fixes: b/117136838

Change-Id: Ie13594cad362912986c8b5786e41672c422245f2
diff --git a/work/workmanager-ktx/api/2.3.0-alpha01.txt b/work/workmanager-ktx/api/2.3.0-alpha01.txt
index ddfb009..32b05f64 100644
--- a/work/workmanager-ktx/api/2.3.0-alpha01.txt
+++ b/work/workmanager-ktx/api/2.3.0-alpha01.txt
@@ -13,6 +13,7 @@
 
   public final class DataKt {
     ctor public DataKt();
+    method public static inline <reified T> boolean containsKey(androidx.work.Data, String key);
     method public static inline androidx.work.Data workDataOf(kotlin.Pair<java.lang.String,?>... pairs);
   }
 
diff --git a/work/workmanager-ktx/api/current.txt b/work/workmanager-ktx/api/current.txt
index ddfb009..32b05f64 100644
--- a/work/workmanager-ktx/api/current.txt
+++ b/work/workmanager-ktx/api/current.txt
@@ -13,6 +13,7 @@
 
   public final class DataKt {
     ctor public DataKt();
+    method public static inline <reified T> boolean containsKey(androidx.work.Data, String key);
     method public static inline androidx.work.Data workDataOf(kotlin.Pair<java.lang.String,?>... pairs);
   }
 
diff --git a/work/workmanager-ktx/api/restricted_2.3.0-alpha01.txt b/work/workmanager-ktx/api/restricted_2.3.0-alpha01.txt
index 5b6423e..303990d 100644
--- a/work/workmanager-ktx/api/restricted_2.3.0-alpha01.txt
+++ b/work/workmanager-ktx/api/restricted_2.3.0-alpha01.txt
@@ -13,6 +13,7 @@
 
   public final class DataKt {
     ctor public DataKt();
+    method public static inline <reified T> boolean containsKey(androidx.work.Data, String key);
     method public static inline androidx.work.Data workDataOf(kotlin.Pair<java.lang.String,?>... pairs);
   }
 
diff --git a/work/workmanager-ktx/api/restricted_current.txt b/work/workmanager-ktx/api/restricted_current.txt
index 5b6423e..303990d 100644
--- a/work/workmanager-ktx/api/restricted_current.txt
+++ b/work/workmanager-ktx/api/restricted_current.txt
@@ -13,6 +13,7 @@
 
   public final class DataKt {
     ctor public DataKt();
+    method public static inline <reified T> boolean containsKey(androidx.work.Data, String key);
     method public static inline androidx.work.Data workDataOf(kotlin.Pair<java.lang.String,?>... pairs);
   }
 
diff --git a/work/workmanager-ktx/src/androidTest/java/androidx/work/DataTest.kt b/work/workmanager-ktx/src/androidTest/java/androidx/work/DataTest.kt
index 2583ece..16f4b23 100644
--- a/work/workmanager-ktx/src/androidTest/java/androidx/work/DataTest.kt
+++ b/work/workmanager-ktx/src/androidTest/java/androidx/work/DataTest.kt
@@ -19,16 +19,17 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
 import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertTrue
 import org.junit.Test
 import org.junit.runner.RunWith
 
 @RunWith(AndroidJUnit4::class)
 @SmallTest
 class DataTest {
-
     @Test
-    fun testToWorkDataOf() {
+    fun testDataExtensions() {
         val data = workDataOf("one" to 1,
                 "two" to 2L,
                 "three" to "Three",
@@ -41,5 +42,11 @@
         assertEquals(longArray!!.size, 2)
         assertEquals(longArray[0], 1L)
         assertEquals(longArray[1], 2L)
+        assertTrue(data.containsKey<Int>("one"))
+        assertTrue(data.containsKey<Long>("two"))
+        assertTrue(data.containsKey<String>("three"))
+        assertTrue(data.containsKey<Array<Long>>("four"))
+        assertFalse(data.containsKey<Any>("nothing"))
+        assertFalse(data.containsKey<Float>("two"))
     }
 }
diff --git a/work/workmanager-ktx/src/main/java/androidx/work/Data.kt b/work/workmanager-ktx/src/main/java/androidx/work/Data.kt
index 4e502df..8d97e75 100644
--- a/work/workmanager-ktx/src/main/java/androidx/work/Data.kt
+++ b/work/workmanager-ktx/src/main/java/androidx/work/Data.kt
@@ -34,3 +34,9 @@
     }
     return dataBuilder.build()
 }
+
+/**
+ * Returns true if the instance of [Data] has a value corresponding to the given [key] with an
+ * expected type [T].
+ */
+inline fun <reified T : Any> Data.containsKey(key: String) = containsKey(key, T::class.java)
diff --git a/work/workmanager/api/2.3.0-alpha01.txt b/work/workmanager/api/2.3.0-alpha01.txt
index d007563..51cdfd0 100644
--- a/work/workmanager/api/2.3.0-alpha01.txt
+++ b/work/workmanager/api/2.3.0-alpha01.txt
@@ -64,6 +64,7 @@
 
   public final class Data {
     ctor public Data(androidx.work.Data);
+    method public <T> boolean containsKey(String, Class<T!>);
     method public static androidx.work.Data fromByteArray(byte[]);
     method public boolean getBoolean(String, boolean);
     method public boolean[]? getBooleanArray(String);
diff --git a/work/workmanager/api/current.txt b/work/workmanager/api/current.txt
index d007563..51cdfd0 100644
--- a/work/workmanager/api/current.txt
+++ b/work/workmanager/api/current.txt
@@ -64,6 +64,7 @@
 
   public final class Data {
     ctor public Data(androidx.work.Data);
+    method public <T> boolean containsKey(String, Class<T!>);
     method public static androidx.work.Data fromByteArray(byte[]);
     method public boolean getBoolean(String, boolean);
     method public boolean[]? getBooleanArray(String);
diff --git a/work/workmanager/src/main/java/androidx/work/Data.java b/work/workmanager/src/main/java/androidx/work/Data.java
index 4fafd31..8e5fbac 100644
--- a/work/workmanager/src/main/java/androidx/work/Data.java
+++ b/work/workmanager/src/main/java/androidx/work/Data.java
@@ -343,6 +343,21 @@
         return Data.toByteArray(this);
     }
 
+     /**
+     * Returns {@code true} if the instance of {@link Data} has a non-null value corresponding to
+     * the given {@link String} key with the expected type of {@code T}.
+     *
+     * @param key   The {@link String} key
+     * @param klass The {@link Class} container for the expected type
+     * @param <T>   The expected type
+     * @return {@code true} If the instance of {@link Data} has a value for the given
+     * {@link String} key with the expected type.
+     */
+    public <T> boolean containsKey(@NonNull String key, @NonNull Class<T> klass) {
+        Object value = mValues.get(key);
+        return value != null && klass.isAssignableFrom(value.getClass());
+    }
+
     /**
      * @return The number of elements in this Data object.
      * @hide