Merge "Move to even more newer and exciting Gradle 4.7 nightly." into pi-preview1-androidx-dev
am: 0c6af02fbd

Change-Id: I4adeead03675cbd89df0711705e6b7aee50dd084
diff --git a/adding-support-library-as-included-build.md b/adding-support-library-as-included-build.md
index 136929f..b77233e 100644
--- a/adding-support-library-as-included-build.md
+++ b/adding-support-library-as-included-build.md
@@ -1,5 +1,8 @@
 # Adding the Support Library Build Within Another Build
 
+Sorry, this doesn't seem to be working at the moment.
+For now, run `./gradlew createArchive` and copy the output to where your project can use it, as described fuller in go/support-dev
+
 Would you like to make a change in Support Library and have it be propagated to
 your downstream Gradle build (generally an app) without having to separately
 build Support Library and then build your application?
diff --git a/app-toolkit/settings.gradle b/app-toolkit/settings.gradle
index fcec40d..4a9a91c 100644
--- a/app-toolkit/settings.gradle
+++ b/app-toolkit/settings.gradle
@@ -59,6 +59,7 @@
 includeProject(":lifecycle:lifecycle-livedata-core", new File(supportRoot, "lifecycle/livedata-core"))
 includeProject(":lifecycle:lifecycle-livedata", new File(supportRoot, "lifecycle/livedata"))
 includeProject(":lifecycle:lifecycle-reactivestreams", new File(supportRoot, "lifecycle/reactivestreams"))
+includeProject(":lifecycle:lifecycle-reactivestreams-ktx", new File(supportRoot, "lifecycle/reactivestreams/ktx"))
 includeProject(":lifecycle:lifecycle-runtime", new File(supportRoot, "lifecycle/runtime"))
 includeProject(":lifecycle:lifecycle-viewmodel", new File(supportRoot, "lifecycle/viewmodel"))
 includeProject(":paging:integration-tests:testapp", new File(supportRoot, "paging/integration-tests/testapp"))
@@ -75,6 +76,7 @@
 includeProject(":room:room-testing", new File(supportRoot, "room/testing"))
 includeProject(":sqlite:sqlite", new File(supportRoot, "persistence/db"))
 includeProject(":sqlite:sqlite-framework", new File(supportRoot, "persistence/db-framework"))
+includeProject(":sqlite:sqlite-ktx", new File(supportRoot, "persistence/db/ktx"))
 
 includeProject(":jetifier-core", new File(supportRoot, "jetifier/jetifier/core"))
 includeProject(":jetifier-processor", new File(supportRoot, "jetifier/jetifier/processor"))
diff --git a/car/res/values-af/strings.xml b/car/res/values-af/strings.xml
index f307fc7..1e90b40 100644
--- a/car/res/values-af/strings.xml
+++ b/car/res/values-af/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Konsentreer op die pad"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Vou knoppie in/uit"</string>
 </resources>
diff --git a/car/res/values-am/strings.xml b/car/res/values-am/strings.xml
index 30ae48e..6759ee3 100644
--- a/car/res/values-am/strings.xml
+++ b/car/res/values-am/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"መንገዱ ላይ ያተኩሩ"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"አዝራርን ዘርጋ/ሰብስብ"</string>
 </resources>
diff --git a/car/res/values-ar/strings.xml b/car/res/values-ar/strings.xml
index e970ed9..845908b 100644
--- a/car/res/values-ar/strings.xml
+++ b/car/res/values-ar/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"ركِّز في الطريق"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"زر التوسيع/التصغير"</string>
 </resources>
diff --git a/car/res/values-az/strings.xml b/car/res/values-az/strings.xml
index e813849..b5e25dc 100644
--- a/car/res/values-az/strings.xml
+++ b/car/res/values-az/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Diqqətinizi yola yönəldin"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Düyməni genişləndirin/yığcamlaşdırın"</string>
 </resources>
diff --git a/car/res/values-b+sr+Latn/strings.xml b/car/res/values-b+sr+Latn/strings.xml
index a83a82c..43dbac2 100644
--- a/car/res/values-b+sr+Latn/strings.xml
+++ b/car/res/values-b+sr+Latn/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Fokusirajte se na put"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Dugme Proširi/skupi"</string>
 </resources>
diff --git a/car/res/values-be/strings.xml b/car/res/values-be/strings.xml
index 80912e4..cfef873 100644
--- a/car/res/values-be/strings.xml
+++ b/car/res/values-be/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Увага на дарогу"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Кнопка \"Разгарнуць/згарнуць\""</string>
 </resources>
diff --git a/car/res/values-bg/strings.xml b/car/res/values-bg/strings.xml
index dd5811f..49e7a61 100644
--- a/car/res/values-bg/strings.xml
+++ b/car/res/values-bg/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Съсредоточете се върху пътя"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Бутон за разгъване/свиване"</string>
 </resources>
diff --git a/car/res/values-bn/strings.xml b/car/res/values-bn/strings.xml
index fcf0165..4ab2ca4 100644
--- a/car/res/values-bn/strings.xml
+++ b/car/res/values-bn/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"মনোযোগ দিয়ে গাড়ি চালান"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"বোতাম বড় করুন/আড়াল করুন"</string>
 </resources>
diff --git a/car/res/values-bs/strings.xml b/car/res/values-bs/strings.xml
index 99e655e..6ff5714 100644
--- a/car/res/values-bs/strings.xml
+++ b/car/res/values-bs/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Fokusirajte se na cestu"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Dugme proširi/suzi"</string>
 </resources>
diff --git a/car/res/values-ca/strings.xml b/car/res/values-ca/strings.xml
index 758f6e7..8e20fd8 100644
--- a/car/res/values-ca/strings.xml
+++ b/car/res/values-ca/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Concentra\'t en la carretera"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Botó per desplegar o replegar"</string>
 </resources>
diff --git a/car/res/values-cs/strings.xml b/car/res/values-cs/strings.xml
index 27090ef..1b4cad2 100644
--- a/car/res/values-cs/strings.xml
+++ b/car/res/values-cs/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Soustřeďte se na silnici"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Tlačítko rozbalení/sbalení"</string>
 </resources>
diff --git a/car/res/values-da/strings.xml b/car/res/values-da/strings.xml
index 96cc062..4a0e180 100644
--- a/car/res/values-da/strings.xml
+++ b/car/res/values-da/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Hold øjnene på vejen"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Knappen Udvid/skjul"</string>
 </resources>
diff --git a/car/res/values-de/strings.xml b/car/res/values-de/strings.xml
index ee289ac..f670bd6 100644
--- a/car/res/values-de/strings.xml
+++ b/car/res/values-de/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Achte auf den Verkehr"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Schaltfläche zum Maximieren/Minimieren"</string>
 </resources>
diff --git a/car/res/values-el/strings.xml b/car/res/values-el/strings.xml
index cf8ab8f..4010875 100644
--- a/car/res/values-el/strings.xml
+++ b/car/res/values-el/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Επικεντρωθείτε στον δρόμο"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Κουμπί ανάπτυξης/σύμπτυξης"</string>
 </resources>
diff --git a/car/res/values-en-rAU/strings.xml b/car/res/values-en-rAU/strings.xml
index 8cc3360..a307f7e 100644
--- a/car/res/values-en-rAU/strings.xml
+++ b/car/res/values-en-rAU/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Focus on the road"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Expand/collapse button"</string>
 </resources>
diff --git a/car/res/values-en-rCA/strings.xml b/car/res/values-en-rCA/strings.xml
index 8cc3360..a307f7e 100644
--- a/car/res/values-en-rCA/strings.xml
+++ b/car/res/values-en-rCA/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Focus on the road"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Expand/collapse button"</string>
 </resources>
diff --git a/car/res/values-en-rGB/strings.xml b/car/res/values-en-rGB/strings.xml
index 8cc3360..a307f7e 100644
--- a/car/res/values-en-rGB/strings.xml
+++ b/car/res/values-en-rGB/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Focus on the road"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Expand/collapse button"</string>
 </resources>
diff --git a/car/res/values-en-rIN/strings.xml b/car/res/values-en-rIN/strings.xml
index 8cc3360..a307f7e 100644
--- a/car/res/values-en-rIN/strings.xml
+++ b/car/res/values-en-rIN/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Focus on the road"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Expand/collapse button"</string>
 </resources>
diff --git a/car/res/values-en-rXC/strings.xml b/car/res/values-en-rXC/strings.xml
index c11c1cb..16d0daf 100644
--- a/car/res/values-en-rXC/strings.xml
+++ b/car/res/values-en-rXC/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‏‏‏‎Focus on the road‎‏‎‎‏‎"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‎‏‏‏‎‏‏‏‎‎‏‎‎‎‎‏‎‎‏‎‎‏‎‏‎‏‏‎‎‎‏‎‎‏‎‎‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‏‎‎‎Expand/collapse button‎‏‎‎‏‎"</string>
 </resources>
diff --git a/car/res/values-es-rUS/strings.xml b/car/res/values-es-rUS/strings.xml
index 6ac20d7..46a5e11 100644
--- a/car/res/values-es-rUS/strings.xml
+++ b/car/res/values-es-rUS/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Concéntrate en el camino"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Botón Expandir/contraer"</string>
 </resources>
diff --git a/car/res/values-es/strings.xml b/car/res/values-es/strings.xml
index 09a493f..33ed10b 100644
--- a/car/res/values-es/strings.xml
+++ b/car/res/values-es/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Céntrate en la carretera"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Botón para mostrar u ocultar"</string>
 </resources>
diff --git a/car/res/values-et/strings.xml b/car/res/values-et/strings.xml
index 66f6e48..7561817 100644
--- a/car/res/values-et/strings.xml
+++ b/car/res/values-et/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Keskenduge teele"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Nupp Laienda/Ahenda"</string>
 </resources>
diff --git a/car/res/values-eu/strings.xml b/car/res/values-eu/strings.xml
index 3773f71..0e92575 100644
--- a/car/res/values-eu/strings.xml
+++ b/car/res/values-eu/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Jarri arreta errepidean"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Zabaltzeko/Tolesteko botoia"</string>
 </resources>
diff --git a/car/res/values-fa/strings.xml b/car/res/values-fa/strings.xml
index 8668d6b..59152f0 100644
--- a/car/res/values-fa/strings.xml
+++ b/car/res/values-fa/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"روی جاده تمرکز داشته باشید"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"دکمه بزرگ کردن/کوچک کردن"</string>
 </resources>
diff --git a/car/res/values-fi/strings.xml b/car/res/values-fi/strings.xml
index e93cb9c..5bbb440 100644
--- a/car/res/values-fi/strings.xml
+++ b/car/res/values-fi/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Pidä katse tiessä"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Laajennus- ja tiivistyspainike"</string>
 </resources>
diff --git a/car/res/values-fr-rCA/strings.xml b/car/res/values-fr-rCA/strings.xml
index f32315b..e90ddf2 100644
--- a/car/res/values-fr-rCA/strings.xml
+++ b/car/res/values-fr-rCA/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Concentrez-vous sur la route"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Bouton Développer/Réduire"</string>
 </resources>
diff --git a/car/res/values-fr/strings.xml b/car/res/values-fr/strings.xml
index f32315b..e90ddf2 100644
--- a/car/res/values-fr/strings.xml
+++ b/car/res/values-fr/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Concentrez-vous sur la route"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Bouton Développer/Réduire"</string>
 </resources>
diff --git a/car/res/values-gl/strings.xml b/car/res/values-gl/strings.xml
index 42bc515..c89cc35 100644
--- a/car/res/values-gl/strings.xml
+++ b/car/res/values-gl/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Céntrate na estrada"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Botón despregar/contraer"</string>
 </resources>
diff --git a/car/res/values-gu/strings.xml b/car/res/values-gu/strings.xml
index f215ec2..4397f5d 100644
--- a/car/res/values-gu/strings.xml
+++ b/car/res/values-gu/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"રસ્તા પર ફોકસ કરો"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"વિસ્તાર કરો/સંકુચિત કરો બટન"</string>
 </resources>
diff --git a/car/res/values-hi/strings.xml b/car/res/values-hi/strings.xml
index 53f8a8d..08d973b 100644
--- a/car/res/values-hi/strings.xml
+++ b/car/res/values-hi/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"सड़क पर ध्यान दें"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"बड़ा/छोटा करने वाला बटन"</string>
 </resources>
diff --git a/car/res/values-hr/strings.xml b/car/res/values-hr/strings.xml
index 0a08dcc..5714327 100644
--- a/car/res/values-hr/strings.xml
+++ b/car/res/values-hr/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Usredotočite se na cestu"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Gumb za proširivanje/sažimanje"</string>
 </resources>
diff --git a/car/res/values-hu/strings.xml b/car/res/values-hu/strings.xml
index 3618719..88c2577 100644
--- a/car/res/values-hu/strings.xml
+++ b/car/res/values-hu/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Figyeljen az útra"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Gomb kibontása/összecsukása"</string>
 </resources>
diff --git a/car/res/values-hy/strings.xml b/car/res/values-hy/strings.xml
index 3a85b41..d97cd0a 100644
--- a/car/res/values-hy/strings.xml
+++ b/car/res/values-hy/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Հետևեք ճանապարհին"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"«Ծավալել/ծալել» կոճակ"</string>
 </resources>
diff --git a/car/res/values-in/strings.xml b/car/res/values-in/strings.xml
index 81daf29..faf2f43 100644
--- a/car/res/values-in/strings.xml
+++ b/car/res/values-in/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Konsentrasi saat mengemudi"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Tombol luaskan/ciutkan"</string>
 </resources>
diff --git a/car/res/values-is/strings.xml b/car/res/values-is/strings.xml
index 4b5d26d..7c2dd76 100644
--- a/car/res/values-is/strings.xml
+++ b/car/res/values-is/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Einbeittu þér að akstrinum"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Hnappur til að stækka/minnka"</string>
 </resources>
diff --git a/car/res/values-it/strings.xml b/car/res/values-it/strings.xml
index b395409..d2b3f4f 100644
--- a/car/res/values-it/strings.xml
+++ b/car/res/values-it/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Concentrati sulla strada"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Pulsante Espandi/Comprimi"</string>
 </resources>
diff --git a/car/res/values-iw/strings.xml b/car/res/values-iw/strings.xml
index ab92be5..79bad9c 100644
--- a/car/res/values-iw/strings.xml
+++ b/car/res/values-iw/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"עליך להתמקד בכביש"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"לחצן הרחבה וכיווץ"</string>
 </resources>
diff --git a/car/res/values-ja/strings.xml b/car/res/values-ja/strings.xml
index 89fce3b..87deba0 100644
--- a/car/res/values-ja/strings.xml
+++ b/car/res/values-ja/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"運転に集中してください"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"展開 / 折りたたみボタン"</string>
 </resources>
diff --git a/car/res/values-ka/strings.xml b/car/res/values-ka/strings.xml
index e3f2e07..b525a9b 100644
--- a/car/res/values-ka/strings.xml
+++ b/car/res/values-ka/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"კონცენტრირდით გზაზე"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"ღილაკის გაფართოება/ჩაკეცვა"</string>
 </resources>
diff --git a/car/res/values-kk/strings.xml b/car/res/values-kk/strings.xml
index bbccd56..ff327d3 100644
--- a/car/res/values-kk/strings.xml
+++ b/car/res/values-kk/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Жолға назар аударыңыз"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"\"Жаю/Жию\" түймесі"</string>
 </resources>
diff --git a/car/res/values-km/strings.xml b/car/res/values-km/strings.xml
index 50fe2db..f9d9111 100644
--- a/car/res/values-km/strings.xml
+++ b/car/res/values-km/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"ផ្តោតលើ​ការបើកបរ"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"ប៊ូតុង​ពង្រីក/បង្រួម"</string>
 </resources>
diff --git a/car/res/values-kn/strings.xml b/car/res/values-kn/strings.xml
index 6562ee2..50ba985 100644
--- a/car/res/values-kn/strings.xml
+++ b/car/res/values-kn/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"ರಸ್ತೆಯ ಮೇಲೆ ಗಮನಹರಿಸಿ"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"ವಿಸ್ತರಿಸಿ/ಕುಗ್ಗಿಸಿ ಬಟನ್"</string>
 </resources>
diff --git a/car/res/values-ko/strings.xml b/car/res/values-ko/strings.xml
index ac5865a..0081b5c 100644
--- a/car/res/values-ko/strings.xml
+++ b/car/res/values-ko/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"도로 상황에 집중하세요."</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"펼치기/접기 버튼"</string>
 </resources>
diff --git a/car/res/values-ky/strings.xml b/car/res/values-ky/strings.xml
index 3640239..8a752fa 100644
--- a/car/res/values-ky/strings.xml
+++ b/car/res/values-ky/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Жолго көңүл буруңуз"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Жайып көрсөтүү/жыйыштыруу баскычы"</string>
 </resources>
diff --git a/car/res/values-lo/strings.xml b/car/res/values-lo/strings.xml
index 4af3152..02afe60 100644
--- a/car/res/values-lo/strings.xml
+++ b/car/res/values-lo/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"ຕັ້ງໃຈຂັບລົດ"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"ປຸ່ມຫຍໍ້/ຂະຫຍາຍ"</string>
 </resources>
diff --git a/car/res/values-lt/strings.xml b/car/res/values-lt/strings.xml
index 685bbe5..5281e18 100644
--- a/car/res/values-lt/strings.xml
+++ b/car/res/values-lt/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Sutelkite dėmesį į kelią"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Mygtukas „Išskleisti / sutraukti“"</string>
 </resources>
diff --git a/car/res/values-lv/strings.xml b/car/res/values-lv/strings.xml
index 417d331..7b4372b 100644
--- a/car/res/values-lv/strings.xml
+++ b/car/res/values-lv/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Pievērsieties autovadīšanai"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Izvēršanas/sakļaušanas poga"</string>
 </resources>
diff --git a/car/res/values-mk/strings.xml b/car/res/values-mk/strings.xml
index 7377299..5184503 100644
--- a/car/res/values-mk/strings.xml
+++ b/car/res/values-mk/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Фокусирајте се на патот"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Копче за проширување/собирање"</string>
 </resources>
diff --git a/car/res/values-ml/strings.xml b/car/res/values-ml/strings.xml
index d5ad91d..8047b4c 100644
--- a/car/res/values-ml/strings.xml
+++ b/car/res/values-ml/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"റോഡിൽ ശ്രദ്ധിക്കുക"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"വികസിപ്പിക്കുക/ചുരുക്കുക ബട്ടൺ"</string>
 </resources>
diff --git a/car/res/values-mn/strings.xml b/car/res/values-mn/strings.xml
index 4b249a4..a8ef13c 100644
--- a/car/res/values-mn/strings.xml
+++ b/car/res/values-mn/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Зам дээр төвлөрөх"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Дэлгэх/буулгах товчлуур"</string>
 </resources>
diff --git a/car/res/values-mr/strings.xml b/car/res/values-mr/strings.xml
index c79f3f3..3032c97 100644
--- a/car/res/values-mr/strings.xml
+++ b/car/res/values-mr/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"रस्त्यावर फोकस करा"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"बटण विस्‍तृत करा/कोलॅप्‍स करा"</string>
 </resources>
diff --git a/car/res/values-ms/strings.xml b/car/res/values-ms/strings.xml
index d209113..301f7eb 100644
--- a/car/res/values-ms/strings.xml
+++ b/car/res/values-ms/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Beri tumpuan pada jalan raya"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Butang kembangkan/runtuhkan"</string>
 </resources>
diff --git a/car/res/values-my/strings.xml b/car/res/values-my/strings.xml
index 438729a..f5317f7 100644
--- a/car/res/values-my/strings.xml
+++ b/car/res/values-my/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"လမ်းကို အာရုံစိုက်ရန်"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"ချဲ့ရန်/ခေါက်သိမ်းရန် ခလုတ်"</string>
 </resources>
diff --git a/car/res/values-nb/strings.xml b/car/res/values-nb/strings.xml
index eb3a144..e4c4810 100644
--- a/car/res/values-nb/strings.xml
+++ b/car/res/values-nb/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Fokuser på veien"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Vis/skjul-knapp"</string>
 </resources>
diff --git a/car/res/values-ne/strings.xml b/car/res/values-ne/strings.xml
index d066c0b..c4499b8 100644
--- a/car/res/values-ne/strings.xml
+++ b/car/res/values-ne/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"सडकमा ध्यान केन्द्रित गर्नु…"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"विस्तृत/संक्षिप्त गर्ने बटन"</string>
 </resources>
diff --git a/car/res/values-nl/strings.xml b/car/res/values-nl/strings.xml
index 7fcb11e..de08f63 100644
--- a/car/res/values-nl/strings.xml
+++ b/car/res/values-nl/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Houd je aandacht op de weg"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Knop voor uitvouwen/samenvouwen"</string>
 </resources>
diff --git a/car/res/values-pa/strings.xml b/car/res/values-pa/strings.xml
index 137bd2a..63a19f3 100644
--- a/car/res/values-pa/strings.xml
+++ b/car/res/values-pa/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"ਸੜਕ \'ਤੇ ਧਿਆਨ ਦਿਓ"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"ਵਿਸਤਾਰ ਕਰੋ/ਸਮੇਟੋ ਬਟਨ"</string>
 </resources>
diff --git a/car/res/values-pl/strings.xml b/car/res/values-pl/strings.xml
index c5aa323..133d27e 100644
--- a/car/res/values-pl/strings.xml
+++ b/car/res/values-pl/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Skup się na drodze"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Przycisk zwijania/rozwijania"</string>
 </resources>
diff --git a/car/res/values-pt-rBR/strings.xml b/car/res/values-pt-rBR/strings.xml
index a6c515a..6c6e459 100644
--- a/car/res/values-pt-rBR/strings.xml
+++ b/car/res/values-pt-rBR/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Foco na estrada"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Botão \"Expandir/Recolher\""</string>
 </resources>
diff --git a/car/res/values-pt-rPT/strings.xml b/car/res/values-pt-rPT/strings.xml
index 2338efe..911b120 100644
--- a/car/res/values-pt-rPT/strings.xml
+++ b/car/res/values-pt-rPT/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Concentre-se na estrada."</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Botão Expandir/reduzir"</string>
 </resources>
diff --git a/car/res/values-pt/strings.xml b/car/res/values-pt/strings.xml
index a6c515a..6c6e459 100644
--- a/car/res/values-pt/strings.xml
+++ b/car/res/values-pt/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Foco na estrada"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Botão \"Expandir/Recolher\""</string>
 </resources>
diff --git a/car/res/values-ro/strings.xml b/car/res/values-ro/strings.xml
index 20cc3e7..7fe204a 100644
--- a/car/res/values-ro/strings.xml
+++ b/car/res/values-ro/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Concentrați-vă asupra drumului"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Butonul de extindere/restrângere"</string>
 </resources>
diff --git a/car/res/values-ru/strings.xml b/car/res/values-ru/strings.xml
index 198f7fa..6554dc3 100644
--- a/car/res/values-ru/strings.xml
+++ b/car/res/values-ru/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Следите за дорогой"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Кнопка \"Развернуть/свернуть\""</string>
 </resources>
diff --git a/car/res/values-si/strings.xml b/car/res/values-si/strings.xml
index 530c12a..48977bd 100644
--- a/car/res/values-si/strings.xml
+++ b/car/res/values-si/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"මාර්ගයට අවධානය යොමු කරන්න"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"දිග හැරීමේ/හැකිළීමේ බොත්තම"</string>
 </resources>
diff --git a/car/res/values-sk/strings.xml b/car/res/values-sk/strings.xml
index a959d09..d8175c4 100644
--- a/car/res/values-sk/strings.xml
+++ b/car/res/values-sk/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Sústreďte sa na cestu"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Tlačidlo rozbalenia/zbalenia"</string>
 </resources>
diff --git a/car/res/values-sl/strings.xml b/car/res/values-sl/strings.xml
index c0a8164..85f2602 100644
--- a/car/res/values-sl/strings.xml
+++ b/car/res/values-sl/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Glejte na cesto"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Gumb za razširitev/strnitev"</string>
 </resources>
diff --git a/car/res/values-sq/strings.xml b/car/res/values-sq/strings.xml
index c8c91ef..87cb023 100644
--- a/car/res/values-sq/strings.xml
+++ b/car/res/values-sq/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Përqendrohu te rruga"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Butoni i zgjerimit/palosjes"</string>
 </resources>
diff --git a/car/res/values-sr/strings.xml b/car/res/values-sr/strings.xml
index d7a6b85..d3fe526 100644
--- a/car/res/values-sr/strings.xml
+++ b/car/res/values-sr/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Фокусирајте се на пут"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Дугме Прошири/скупи"</string>
 </resources>
diff --git a/car/res/values-sv/strings.xml b/car/res/values-sv/strings.xml
index 3798509..c4ae438 100644
--- a/car/res/values-sv/strings.xml
+++ b/car/res/values-sv/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Fokusera på körningen"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Knappen Utöka/komprimera"</string>
 </resources>
diff --git a/car/res/values-sw/strings.xml b/car/res/values-sw/strings.xml
index a5b76c7..d3472f5 100644
--- a/car/res/values-sw/strings.xml
+++ b/car/res/values-sw/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Tia makini barabarani"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Kitufe cha kupanua/kukunja"</string>
 </resources>
diff --git a/car/res/values-ta/strings.xml b/car/res/values-ta/strings.xml
index e97f385..e13ede5 100644
--- a/car/res/values-ta/strings.xml
+++ b/car/res/values-ta/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"வாகனம் ஓட்டும்போது கவனம் தேவை"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"விரிவாக்குவதற்கான/சுருக்குவதற்கான பட்டன்"</string>
 </resources>
diff --git a/car/res/values-te/strings.xml b/car/res/values-te/strings.xml
index 9079a09..b106363 100644
--- a/car/res/values-te/strings.xml
+++ b/car/res/values-te/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"రహదారిపై దృష్టి ఉంచండి"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"విస్తరించు/కుదించు బటన్"</string>
 </resources>
diff --git a/car/res/values-th/strings.xml b/car/res/values-th/strings.xml
index 3ba0d6b..05be415 100644
--- a/car/res/values-th/strings.xml
+++ b/car/res/values-th/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"จดจ่อกับถนน"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"ปุ่มขยาย/ยุบ"</string>
 </resources>
diff --git a/car/res/values-tl/strings.xml b/car/res/values-tl/strings.xml
index 395e555..a56c37c 100644
--- a/car/res/values-tl/strings.xml
+++ b/car/res/values-tl/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Tumuon sa kalsada"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Button na i-expand/i-collapse"</string>
 </resources>
diff --git a/car/res/values-tr/strings.xml b/car/res/values-tr/strings.xml
index a0f0b22..b28b66e 100644
--- a/car/res/values-tr/strings.xml
+++ b/car/res/values-tr/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Dikkatinizi yola verin"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Genişlet/daralt düğmesi"</string>
 </resources>
diff --git a/car/res/values-uk/strings.xml b/car/res/values-uk/strings.xml
index 2657348..1964936 100644
--- a/car/res/values-uk/strings.xml
+++ b/car/res/values-uk/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Зосередьтеся на дорозі"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Кнопка \"Розгорнути або згорнути\""</string>
 </resources>
diff --git a/car/res/values-ur/strings.xml b/car/res/values-ur/strings.xml
index 60c578c..c1d6b3e 100644
--- a/car/res/values-ur/strings.xml
+++ b/car/res/values-ur/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"سڑک پر توجہ مرکوز کریں"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"پھیلائیں/سکیڑیں بٹن"</string>
 </resources>
diff --git a/car/res/values-uz/strings.xml b/car/res/values-uz/strings.xml
index bdaba48..a830b84 100644
--- a/car/res/values-uz/strings.xml
+++ b/car/res/values-uz/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Diqqatingizni yo‘lga qarating"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Yoyish/yig‘ish tugmasi"</string>
 </resources>
diff --git a/car/res/values-vi/strings.xml b/car/res/values-vi/strings.xml
index 37457d4..144f41a 100644
--- a/car/res/values-vi/strings.xml
+++ b/car/res/values-vi/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Tập trung vào đường đi"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Nút mở rộng/thu gọn"</string>
 </resources>
diff --git a/car/res/values-zh-rCN/strings.xml b/car/res/values-zh-rCN/strings.xml
index ec0c3c4..0c2caea 100644
--- a/car/res/values-zh-rCN/strings.xml
+++ b/car/res/values-zh-rCN/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"请专心驾驶"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"“展开”/“收起”按钮"</string>
 </resources>
diff --git a/car/res/values-zh-rHK/strings.xml b/car/res/values-zh-rHK/strings.xml
index 61102cc..09c1a9e 100644
--- a/car/res/values-zh-rHK/strings.xml
+++ b/car/res/values-zh-rHK/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"請專心駕駛"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"展開/收合按鈕"</string>
 </resources>
diff --git a/car/res/values-zh-rTW/strings.xml b/car/res/values-zh-rTW/strings.xml
index 61102cc..09c1a9e 100644
--- a/car/res/values-zh-rTW/strings.xml
+++ b/car/res/values-zh-rTW/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"請專心駕駛"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"展開/收合按鈕"</string>
 </resources>
diff --git a/car/res/values-zu/strings.xml b/car/res/values-zu/strings.xml
index bdf7337..9403834 100644
--- a/car/res/values-zu/strings.xml
+++ b/car/res/values-zu/strings.xml
@@ -17,4 +17,5 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="speed_bump_lockout_message" msgid="5405697774899378511">"Gxila emgwaqweni"</string>
+    <string name="action_bar_expand_collapse_button" msgid="196909968432559564">"Inkinobho yokunweba/ukugoqa"</string>
 </resources>
diff --git a/collection/ktx/OWNERS b/collection/ktx/OWNERS
new file mode 100644
index 0000000..e450f4c
--- /dev/null
+++ b/collection/ktx/OWNERS
@@ -0,0 +1 @@
+jakew@google.com
diff --git a/collection/ktx/build.gradle b/collection/ktx/build.gradle
new file mode 100644
index 0000000..83944f2
--- /dev/null
+++ b/collection/ktx/build.gradle
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2018 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.
+ */
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+
+plugins {
+    id("SupportKotlinLibraryPlugin")
+}
+
+dependencies {
+    compile(project(":collection"))
+    compile(KOTLIN_STDLIB)
+    testCompile(JUNIT)
+    testCompile(TRUTH)
+    testCompile(project(":internal-testutils-ktx"))
+}
+
+supportLibrary {
+    name = "Collections Kotlin Extensions"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.COLLECTION
+    inceptionYear = "2018"
+    description = "Kotlin extensions for 'collection' artifact"
+}
diff --git a/collection/ktx/src/main/java/androidx/collection/ArrayMap.kt b/collection/ktx/src/main/java/androidx/collection/ArrayMap.kt
new file mode 100644
index 0000000..8f3299e
--- /dev/null
+++ b/collection/ktx/src/main/java/androidx/collection/ArrayMap.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.collection
+
+/** Returns an empty new [ArrayMap]. */
+inline fun <K, V> arrayMapOf(): ArrayMap<K, V> = ArrayMap()
+
+/**
+ * Returns a new [ArrayMap] with the specified contents, given as a list of pairs where the first
+ * component is the key and the second component is the value.
+ *
+ * If multiple pairs have the same key, the resulting map will contain the value from the last of
+ * those pairs.
+ */
+fun <K, V> arrayMapOf(vararg pairs: Pair<K, V>): ArrayMap<K, V> {
+    val map = ArrayMap<K, V>(pairs.size)
+    for (pair in pairs) {
+        map[pair.first] = pair.second
+    }
+    return map
+}
diff --git a/collection/ktx/src/main/java/androidx/collection/ArraySet.kt b/collection/ktx/src/main/java/androidx/collection/ArraySet.kt
new file mode 100644
index 0000000..07b4be7
--- /dev/null
+++ b/collection/ktx/src/main/java/androidx/collection/ArraySet.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.collection
+
+/** Returns an empty new [ArraySet]. */
+inline fun <T> arraySetOf(): ArraySet<T> = ArraySet()
+
+/** Returns a new [ArraySet] with the specified contents. */
+fun <T> arraySetOf(vararg values: T): ArraySet<T> {
+    val set = ArraySet<T>(values.size)
+    @Suppress("LoopToCallChain") // Causes needless copy to a list.
+    for (value in values) {
+        set.add(value)
+    }
+    return set
+}
diff --git a/collection/ktx/src/main/java/androidx/collection/LongSparseArray.kt b/collection/ktx/src/main/java/androidx/collection/LongSparseArray.kt
new file mode 100644
index 0000000..fd6201a
--- /dev/null
+++ b/collection/ktx/src/main/java/androidx/collection/LongSparseArray.kt
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.collection
+
+/** Returns the number of key/value pairs in the collection. */
+inline val <T> LongSparseArray<T>.size get() = size()
+
+/** Returns true if the collection contains [key]. */
+inline operator fun <T> LongSparseArray<T>.contains(key: Long) = indexOfKey(key) >= 0
+
+/** Allows the use of the index operator for storing values in the collection. */
+inline operator fun <T> LongSparseArray<T>.set(key: Long, value: T) = put(key, value)
+
+/** Creates a new collection by adding or replacing entries from [other]. */
+operator fun <T> LongSparseArray<T>.plus(other: LongSparseArray<T>): LongSparseArray<T> {
+    val new = LongSparseArray<T>(size() + other.size())
+    new.putAll(this)
+    new.putAll(other)
+    return new
+}
+
+/** Returns true if the collection contains [key]. */
+inline fun <T> LongSparseArray<T>.containsKey(key: Long) = indexOfKey(key) >= 0
+
+/** Returns true if the collection contains [value]. */
+inline fun <T> LongSparseArray<T>.containsValue(value: T) = indexOfValue(value) != -1
+
+/** Return the value corresponding to [key], or [defaultValue] when not present. */
+inline fun <T> LongSparseArray<T>.getOrDefault(key: Long, defaultValue: T) =
+    get(key) ?: defaultValue
+
+/** Return the value corresponding to [key], or from [defaultValue] when not present. */
+inline fun <T> LongSparseArray<T>.getOrElse(key: Long, defaultValue: () -> T) =
+    get(key) ?: defaultValue()
+
+/** Return true when the collection contains elements. */
+inline fun <T> LongSparseArray<T>.isNotEmpty() = size() != 0
+
+/** Removes the entry for [key] only if it is mapped to [value]. */
+fun <T> LongSparseArray<T>.remove(key: Long, value: T): Boolean {
+    val index = indexOfKey(key)
+    if (index != -1 && value == valueAt(index)) {
+        removeAt(index)
+        return true
+    }
+    return false
+}
+
+/** Update this collection by adding or replacing entries from [other]. */
+fun <T> LongSparseArray<T>.putAll(other: LongSparseArray<T>) = other.forEach(::put)
+
+/** Performs the given [action] for each key/value entry. */
+inline fun <T> LongSparseArray<T>.forEach(action: (key: Long, value: T) -> Unit) {
+    for (index in 0 until size()) {
+        action(keyAt(index), valueAt(index))
+    }
+}
+
+/** Return an iterator over the collection's keys. */
+fun <T> LongSparseArray<T>.keyIterator(): LongIterator = object : LongIterator() {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun nextLong() = keyAt(index++)
+}
+
+/** Return an iterator over the collection's values. */
+fun <T> LongSparseArray<T>.valueIterator(): Iterator<T> = object : Iterator<T> {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun next() = valueAt(index++)
+}
diff --git a/collection/ktx/src/main/java/androidx/collection/LruCache.kt b/collection/ktx/src/main/java/androidx/collection/LruCache.kt
new file mode 100644
index 0000000..554a012
--- /dev/null
+++ b/collection/ktx/src/main/java/androidx/collection/LruCache.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 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 androidx.collection
+
+/**
+ * Creates an [LruCache] with the given parameters.
+ *
+ * @param maxSize for caches that do not specify [sizeOf], this is
+ * the maximum number of entries in the cache. For all other caches,
+ * this is the maximum sum of the sizes of the entries in this cache.
+ * @param sizeOf function that returns the size of the entry for key and value in
+ * user-defined units. The default implementation returns 1.
+ * @param create a create called after a cache miss to compute a value for the corresponding key.
+ * Returns the computed value or null if no value can be computed. The default implementation
+ * returns null.
+ * @param onEntryRemoved a function called for entries that have been evicted or removed.
+ *
+ * @see LruCache.sizeOf
+ * @see LruCache.create
+ * @see LruCache.entryRemoved
+ */
+inline fun <K : Any, V : Any> lruCache(
+    maxSize: Int,
+    crossinline sizeOf: (key: K, value: V) -> Int = { _, _ -> 1 },
+    @Suppress("USELESS_CAST") // https://youtrack.jetbrains.com/issue/KT-21946
+    crossinline create: (key: K) -> V? = { null as V? },
+    crossinline onEntryRemoved: (evicted: Boolean, key: K, oldValue: V, newValue: V?) -> Unit =
+        { _, _, _, _ -> }
+): LruCache<K, V> {
+    return object : LruCache<K, V>(maxSize) {
+        override fun sizeOf(key: K, value: V) = sizeOf(key, value)
+        override fun create(key: K) = create(key)
+        override fun entryRemoved(evicted: Boolean, key: K, oldValue: V, newValue: V?) {
+            onEntryRemoved(evicted, key, oldValue, newValue)
+        }
+    }
+}
diff --git a/collection/ktx/src/main/java/androidx/collection/SparseArray.kt b/collection/ktx/src/main/java/androidx/collection/SparseArray.kt
new file mode 100644
index 0000000..e1d2382
--- /dev/null
+++ b/collection/ktx/src/main/java/androidx/collection/SparseArray.kt
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.collection
+
+/** Returns the number of key/value pairs in the collection. */
+inline val <T> SparseArrayCompat<T>.size get() = size()
+
+/** Returns true if the collection contains [key]. */
+inline operator fun <T> SparseArrayCompat<T>.contains(key: Int) = indexOfKey(key) >= 0
+
+/** Allows the use of the index operator for storing values in the collection. */
+inline operator fun <T> SparseArrayCompat<T>.set(key: Int, value: T) = put(key, value)
+
+/** Creates a new collection by adding or replacing entries from [other]. */
+operator fun <T> SparseArrayCompat<T>.plus(other: SparseArrayCompat<T>): SparseArrayCompat<T> {
+    val new = SparseArrayCompat<T>(size() + other.size())
+    new.putAll(this)
+    new.putAll(other)
+    return new
+}
+
+/** Returns true if the collection contains [key]. */
+inline fun <T> SparseArrayCompat<T>.containsKey(key: Int) = indexOfKey(key) >= 0
+
+/** Returns true if the collection contains [value]. */
+inline fun <T> SparseArrayCompat<T>.containsValue(value: T) = indexOfValue(value) != -1
+
+/** Return the value corresponding to [key], or [defaultValue] when not present. */
+inline fun <T> SparseArrayCompat<T>.getOrDefault(key: Int, defaultValue: T) =
+    get(key) ?: defaultValue
+
+/** Return the value corresponding to [key], or from [defaultValue] when not present. */
+inline fun <T> SparseArrayCompat<T>.getOrElse(key: Int, defaultValue: () -> T) =
+    get(key) ?: defaultValue()
+
+/** Return true when the collection contains elements. */
+inline fun <T> SparseArrayCompat<T>.isNotEmpty() = size() != 0
+
+/** Removes the entry for [key] only if it is mapped to [value]. */
+fun <T> SparseArrayCompat<T>.remove(key: Int, value: T): Boolean {
+    val index = indexOfKey(key)
+    if (index != -1 && value == valueAt(index)) {
+        removeAt(index)
+        return true
+    }
+    return false
+}
+
+/** Update this collection by adding or replacing entries from [other]. */
+fun <T> SparseArrayCompat<T>.putAll(other: SparseArrayCompat<T>) = other.forEach(::put)
+
+/** Performs the given [action] for each key/value entry. */
+inline fun <T> SparseArrayCompat<T>.forEach(action: (key: Int, value: T) -> Unit) {
+    for (index in 0 until size()) {
+        action(keyAt(index), valueAt(index))
+    }
+}
+
+/** Return an iterator over the collection's keys. */
+fun <T> SparseArrayCompat<T>.keyIterator(): IntIterator = object : IntIterator() {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun nextInt() = keyAt(index++)
+}
+
+/** Return an iterator over the collection's values. */
+fun <T> SparseArrayCompat<T>.valueIterator(): Iterator<T> = object : Iterator<T> {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun next() = valueAt(index++)
+}
diff --git a/collection/ktx/src/test/java/androidx/collection/ArrayMapTest.kt b/collection/ktx/src/test/java/androidx/collection/ArrayMapTest.kt
new file mode 100644
index 0000000..8c002dd
--- /dev/null
+++ b/collection/ktx/src/test/java/androidx/collection/ArrayMapTest.kt
@@ -0,0 +1,38 @@
+/*
+ * 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 androidx.collection
+
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class ArrayMapTest {
+    @Test fun empty() {
+        val map = arrayMapOf<String, String>()
+        assertEquals(0, map.size)
+    }
+
+    @Test fun nonEmpty() {
+        val map = arrayMapOf("foo" to "bar", "bar" to "baz")
+        assertThat(map).containsExactly("foo", "bar", "bar", "baz")
+    }
+
+    @Test fun duplicateKeyKeepsLast() {
+        val map = arrayMapOf("foo" to "bar", "foo" to "baz")
+        assertThat(map).containsExactly("foo", "baz")
+    }
+}
diff --git a/collection/ktx/src/test/java/androidx/collection/ArraySetTest.kt b/collection/ktx/src/test/java/androidx/collection/ArraySetTest.kt
new file mode 100644
index 0000000..71a561d
--- /dev/null
+++ b/collection/ktx/src/test/java/androidx/collection/ArraySetTest.kt
@@ -0,0 +1,33 @@
+/*
+ * 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 androidx.collection
+
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class ArraySetTest {
+    @Test fun empty() {
+        val set = arraySetOf<String>()
+        assertEquals(0, set.size)
+    }
+
+    @Test fun nonEmpty() {
+        val set = arraySetOf("foo", "bar", "baz")
+        assertThat(set).containsExactly("foo", "bar", "baz")
+    }
+}
diff --git a/collection/ktx/src/test/java/androidx/collection/LongSparseArrayTest.kt b/collection/ktx/src/test/java/androidx/collection/LongSparseArrayTest.kt
new file mode 100644
index 0000000..3419664
--- /dev/null
+++ b/collection/ktx/src/test/java/androidx/collection/LongSparseArrayTest.kt
@@ -0,0 +1,190 @@
+/*
+ * 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 androidx.collection
+
+import androidx.testutils.fail
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertSame
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class LongSparseArrayTest {
+    @Test fun sizeProperty() {
+        val array = LongSparseArray<String>()
+        assertEquals(0, array.size)
+        array.put(1L, "one")
+        assertEquals(1, array.size)
+    }
+
+    @Test fun containsOperator() {
+        val array = LongSparseArray<String>()
+        assertFalse(1L in array)
+        array.put(1L, "one")
+        assertTrue(1L in array)
+    }
+
+    @Test fun containsOperatorWithValue() {
+        val array = LongSparseArray<String>()
+
+        array.put(1L, "one")
+        assertFalse(2L in array)
+
+        array.put(2L, "two")
+        assertTrue(2L in array)
+    }
+
+    @Test fun setOperator() {
+        val array = LongSparseArray<String>()
+        array[1L] = "one"
+        assertEquals("one", array.get(1L))
+    }
+
+    @Test fun plusOperator() {
+        val first = LongSparseArray<String>().apply { put(1L, "one") }
+        val second = LongSparseArray<String>().apply { put(2L, "two") }
+        val combined = first + second
+        assertEquals(2, combined.size())
+        assertEquals(1L, combined.keyAt(0))
+        assertEquals("one", combined.valueAt(0))
+        assertEquals(2L, combined.keyAt(1))
+        assertEquals("two", combined.valueAt(1))
+    }
+
+    @Test fun containsKey() {
+        val array = LongSparseArray<String>()
+        assertFalse(array.containsKey(1L))
+        array.put(1L, "one")
+        assertTrue(array.containsKey(1L))
+    }
+
+    @Test fun containsKeyWithValue() {
+        val array = LongSparseArray<String>()
+
+        array.put(1L, "one")
+        assertFalse(array.containsKey(2L))
+
+        array.put(2L, "one")
+        assertTrue(array.containsKey(2L))
+    }
+
+    @Test fun containsValue() {
+        val array = LongSparseArray<String>()
+        assertFalse(array.containsValue("one"))
+        array.put(1L, "one")
+        assertTrue(array.containsValue("one"))
+    }
+
+    @Test fun getOrDefault() {
+        val array = LongSparseArray<Any>()
+        val default = Any()
+        assertSame(default, array.getOrDefault(1L, default))
+        array.put(1L, "one")
+        assertEquals("one", array.getOrDefault(1L, default))
+    }
+
+    @Test fun getOrElse() {
+        val array = LongSparseArray<Any>()
+        val default = Any()
+        assertSame(default, array.getOrElse(1L) { default })
+        array.put(1L, "one")
+        assertEquals("one", array.getOrElse(1L) { fail() })
+    }
+
+    @Test fun isNotEmpty() {
+        val array = LongSparseArray<String>()
+        assertFalse(array.isNotEmpty())
+        array.put(1L, "one")
+        assertTrue(array.isNotEmpty())
+    }
+
+    @Test fun removeValue() {
+        val array = LongSparseArray<String>()
+        array.put(1L, "one")
+        assertFalse(array.remove(0L, "one"))
+        assertEquals(1, array.size())
+        assertFalse(array.remove(1L, "two"))
+        assertEquals(1, array.size())
+        assertTrue(array.remove(1L, "one"))
+        assertEquals(0, array.size())
+    }
+
+    @Test fun putAll() {
+        val dest = LongSparseArray<String>()
+        val source = LongSparseArray<String>()
+        source.put(1L, "one")
+
+        assertEquals(0, dest.size())
+        dest.putAll(source)
+        assertEquals(1, dest.size())
+    }
+
+    @Test fun forEach() {
+        val array = LongSparseArray<String>()
+        array.forEach { _, _ -> fail() }
+
+        array.put(1L, "one")
+        array.put(2L, "two")
+        array.put(6L, "six")
+
+        val keys = mutableListOf<Long>()
+        val values = mutableListOf<String>()
+        array.forEach { key, value ->
+            keys.add(key)
+            values.add(value)
+        }
+        assertThat(keys).containsExactly(1L, 2L, 6L)
+        assertThat(values).containsExactly("one", "two", "six")
+    }
+
+    @Test fun keyIterator() {
+        val array = LongSparseArray<String>()
+        assertFalse(array.keyIterator().hasNext())
+
+        array.put(1L, "one")
+        array.put(2L, "two")
+        array.put(6L, "six")
+
+        val iterator = array.keyIterator()
+        assertTrue(iterator.hasNext())
+        assertEquals(1L, iterator.nextLong())
+        assertTrue(iterator.hasNext())
+        assertEquals(2L, iterator.nextLong())
+        assertTrue(iterator.hasNext())
+        assertEquals(6L, iterator.nextLong())
+        assertFalse(iterator.hasNext())
+    }
+
+    @Test fun valueIterator() {
+        val array = LongSparseArray<String>()
+        assertFalse(array.valueIterator().hasNext())
+
+        array.put(1L, "one")
+        array.put(2L, "two")
+        array.put(6L, "six")
+
+        val iterator = array.valueIterator()
+        assertTrue(iterator.hasNext())
+        assertEquals("one", iterator.next())
+        assertTrue(iterator.hasNext())
+        assertEquals("two", iterator.next())
+        assertTrue(iterator.hasNext())
+        assertEquals("six", iterator.next())
+        assertFalse(iterator.hasNext())
+    }
+}
diff --git a/collection/ktx/src/test/java/androidx/collection/LruCacheTest.kt b/collection/ktx/src/test/java/androidx/collection/LruCacheTest.kt
new file mode 100644
index 0000000..c47b423
--- /dev/null
+++ b/collection/ktx/src/test/java/androidx/collection/LruCacheTest.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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 androidx.collection
+
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class LruCacheTest {
+    private data class TestData(val x: String = "bla")
+
+    @Test fun size() {
+        val cache = lruCache<String, TestData>(200, { k, (x) -> k.length * x.length })
+        cache.put("long", TestData())
+        assertEquals(cache.size(), 12)
+    }
+
+    @Test fun create() {
+        val cache = lruCache<String, TestData>(200, create = { key -> TestData("$key foo") })
+        assertEquals(cache.get("kung"), TestData("kung foo"))
+    }
+
+    @Test fun onEntryRemoved() {
+        var wasCalled = false
+
+        val cache = lruCache<String, TestData>(200, onEntryRemoved = { _, _, _, _ ->
+            wasCalled = true
+        })
+        val initial = TestData()
+        cache.put("a", initial)
+        cache.remove("a")
+        assertTrue(wasCalled)
+    }
+}
diff --git a/collection/ktx/src/test/java/androidx/collection/SparseArrayTest.kt b/collection/ktx/src/test/java/androidx/collection/SparseArrayTest.kt
new file mode 100644
index 0000000..90d46c8
--- /dev/null
+++ b/collection/ktx/src/test/java/androidx/collection/SparseArrayTest.kt
@@ -0,0 +1,180 @@
+/*
+ * 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 androidx.collection
+
+import androidx.testutils.fail
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertSame
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class SparseArrayCompatTest {
+    @Test fun sizeProperty() {
+        val array = SparseArrayCompat<String>()
+        assertEquals(0, array.size)
+        array.put(1, "one")
+        assertEquals(1, array.size)
+    }
+
+    @Test fun containsOperator() {
+        val array = SparseArrayCompat<String>()
+        assertFalse(1 in array)
+        array.put(1, "one")
+        assertTrue(1 in array)
+    }
+
+    @Test fun containsOperatorWithItem() {
+        val array = SparseArrayCompat<String>()
+
+        array.put(1, "one")
+        assertFalse(2 in array)
+
+        array.put(2, "two")
+        assertTrue(2 in array)
+    }
+
+    @Test fun setOperator() {
+        val array = SparseArrayCompat<String>()
+        array[1] = "one"
+        assertEquals("one", array.get(1))
+    }
+
+    @Test fun plusOperator() {
+        val first = SparseArrayCompat<String>().apply { put(1, "one") }
+        val second = SparseArrayCompat<String>().apply { put(2, "two") }
+        val combined = first + second
+        assertEquals(2, combined.size())
+        assertEquals(1, combined.keyAt(0))
+        assertEquals("one", combined.valueAt(0))
+        assertEquals(2, combined.keyAt(1))
+        assertEquals("two", combined.valueAt(1))
+    }
+
+    @Test fun containsKey() {
+        val array = SparseArrayCompat<String>()
+        assertFalse(array.containsKey(1))
+        array.put(1, "one")
+        assertTrue(array.containsKey(1))
+    }
+
+    @Test fun containsValue() {
+        val array = SparseArrayCompat<String>()
+        assertFalse(array.containsValue("one"))
+        array.put(1, "one")
+        assertTrue(array.containsValue("one"))
+    }
+
+    @Test fun getOrDefault() {
+        val array = SparseArrayCompat<Any>()
+        val default = Any()
+        assertSame(default, array.getOrDefault(1, default))
+        array.put(1, "one")
+        assertEquals("one", array.getOrDefault(1, default))
+    }
+
+    @Test fun getOrElse() {
+        val array = SparseArrayCompat<Any>()
+        val default = Any()
+        assertSame(default, array.getOrElse(1) { default })
+        array.put(1, "one")
+        assertEquals("one", array.getOrElse(1) { fail() })
+    }
+
+    @Test fun isNotEmpty() {
+        val array = SparseArrayCompat<String>()
+        assertFalse(array.isNotEmpty())
+        array.put(1, "one")
+        assertTrue(array.isNotEmpty())
+    }
+
+    @Test fun removeValue() {
+        val array = SparseArrayCompat<String>()
+        array.put(1, "one")
+        assertFalse(array.remove(0, "one"))
+        assertEquals(1, array.size())
+        assertFalse(array.remove(1, "two"))
+        assertEquals(1, array.size())
+        assertTrue(array.remove(1, "one"))
+        assertEquals(0, array.size())
+    }
+
+    @Test fun putAll() {
+        val dest = SparseArrayCompat<String>()
+        val source = SparseArrayCompat<String>()
+        source.put(1, "one")
+
+        assertEquals(0, dest.size())
+        dest.putAll(source)
+        assertEquals(1, dest.size())
+    }
+
+    @Test fun forEach() {
+        val array = SparseArrayCompat<String>()
+        array.forEach { _, _ -> fail() }
+
+        array.put(1, "one")
+        array.put(2, "two")
+        array.put(6, "six")
+
+        val keys = mutableListOf<Int>()
+        val values = mutableListOf<String>()
+        array.forEach { key, value ->
+            keys.add(key)
+            values.add(value)
+        }
+        assertThat(keys).containsExactly(1, 2, 6)
+        assertThat(values).containsExactly("one", "two", "six")
+    }
+
+    @Test fun keyIterator() {
+        val array = SparseArrayCompat<String>()
+        assertFalse(array.keyIterator().hasNext())
+
+        array.put(1, "one")
+        array.put(2, "two")
+        array.put(6, "six")
+
+        val iterator = array.keyIterator()
+        assertTrue(iterator.hasNext())
+        assertEquals(1, iterator.nextInt())
+        assertTrue(iterator.hasNext())
+        assertEquals(2, iterator.nextInt())
+        assertTrue(iterator.hasNext())
+        assertEquals(6, iterator.nextInt())
+        assertFalse(iterator.hasNext())
+    }
+
+    @Test fun valueIterator() {
+        val array = SparseArrayCompat<String>()
+        assertFalse(array.valueIterator().hasNext())
+
+        array.put(1, "one")
+        array.put(2, "two")
+        array.put(6, "six")
+
+        val iterator = array.valueIterator()
+        assertTrue(iterator.hasNext())
+        assertEquals("one", iterator.next())
+        assertTrue(iterator.hasNext())
+        assertEquals("two", iterator.next())
+        assertTrue(iterator.hasNext())
+        assertEquals("six", iterator.next())
+        assertFalse(iterator.hasNext())
+    }
+}
diff --git a/compat/res/values/dimens.xml b/compat/res/values/dimens.xml
index 1dcff5e..41abbe6 100644
--- a/compat/res/values/dimens.xml
+++ b/compat/res/values/dimens.xml
@@ -70,4 +70,10 @@
 
     <!-- the paddingtop on the right side of the notification (for time etc.) -->
     <dimen name="notification_right_side_padding_top">2dp</dimen>
+
+    <!-- the maximum width of the large icon, above which it will be downscaled -->
+    <dimen name="notification_icon_max_width">320dp</dimen>
+
+    <!-- the maximum height of the large icon, above which it will be downscaled -->
+    <dimen name="notification_icon_max_height">320dp</dimen>
 </resources>
diff --git a/compat/src/androidTest/java/androidx/core/graphics/drawable/IconCompatTest.java b/compat/src/androidTest/java/androidx/core/graphics/drawable/IconCompatTest.java
index 75ad1d5..2ca517f 100644
--- a/compat/src/androidTest/java/androidx/core/graphics/drawable/IconCompatTest.java
+++ b/compat/src/androidTest/java/androidx/core/graphics/drawable/IconCompatTest.java
@@ -32,6 +32,7 @@
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -258,7 +259,7 @@
     public void testBitmapIconCompat_getType() {
         IconCompat icon = IconCompat.createWithBitmap(Bitmap.createBitmap(16, 16,
                 Bitmap.Config.ARGB_8888));
-        assertEquals(IconCompat.TYPE_BITMAP, icon.getType());
+        assertEquals(Icon.TYPE_BITMAP, icon.getType());
     }
 
     @Test
@@ -266,7 +267,7 @@
         byte[] data = new byte[4];
         data[0] = data[1] = data[2] = data[3] = (byte) 255;
         IconCompat icon = IconCompat.createWithData(data, 0, 4);
-        assertEquals(IconCompat.TYPE_DATA, icon.getType());
+        assertEquals(Icon.TYPE_DATA, icon.getType());
     }
 
     @Test
@@ -278,11 +279,11 @@
             String filePath = file.toURI().getPath();
 
             IconCompat icon = IconCompat.createWithContentUri(Uri.fromFile(file));
-            assertEquals(IconCompat.TYPE_URI, icon.getType());
+            assertEquals(Icon.TYPE_URI, icon.getType());
             assertEquals(filePath, icon.getUri().getPath());
 
             icon = IconCompat.createWithContentUri(file.toURI().toString());
-            assertEquals(IconCompat.TYPE_URI, icon.getType());
+            assertEquals(Icon.TYPE_URI, icon.getType());
             assertEquals(filePath, icon.getUri().getPath());
         } finally {
             file.delete();
@@ -292,7 +293,7 @@
     @Test
     public void testResourceIconCompat_getType() {
         IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.bmp_test);
-        assertEquals(IconCompat.TYPE_RESOURCE, icon.getType());
+        assertEquals(Icon.TYPE_RESOURCE, icon.getType());
         assertEquals("androidx.core.test", icon.getResPackage());
         assertEquals(R.drawable.bmp_test, icon.getResId());
     }
diff --git a/compat/src/main/java/androidx/core/app/NotificationCompat.java b/compat/src/main/java/androidx/core/app/NotificationCompat.java
index b7d88eb..6d1ce46 100644
--- a/compat/src/main/java/androidx/core/app/NotificationCompat.java
+++ b/compat/src/main/java/androidx/core/app/NotificationCompat.java
@@ -963,11 +963,37 @@
          * Set the large icon that is shown in the ticker and notification.
          */
         public Builder setLargeIcon(Bitmap icon) {
-            mLargeIcon = icon;
+            mLargeIcon = reduceLargeIconSize(icon);
             return this;
         }
 
         /**
+         * Reduce the size of a notification icon if it's overly large. The framework does
+         * this automatically starting from API 27.
+         */
+        private Bitmap reduceLargeIconSize(Bitmap icon) {
+            if (icon == null || Build.VERSION.SDK_INT >= 27) {
+                return icon;
+            }
+
+            Resources res = mContext.getResources();
+            int maxWidth = res.getDimensionPixelSize(R.dimen.notification_icon_max_width);
+            int maxHeight = res.getDimensionPixelSize(R.dimen.notification_icon_max_height);
+            if (icon.getWidth() <= maxWidth && icon.getHeight() <= maxHeight) {
+                return icon;
+            }
+
+            double scale = Math.min(
+                    maxWidth / (double) Math.max(1, icon.getWidth()),
+                    maxHeight / (double) Math.max(1, icon.getHeight()));
+            return Bitmap.createScaledBitmap(
+                    icon,
+                    (int) Math.ceil(icon.getWidth() * scale),
+                    (int) Math.ceil(icon.getHeight() * scale),
+                    true /* filtered */);
+        }
+
+        /**
          * Set the sound to play.  It will play on the default stream.
          *
          * <p>
diff --git a/compat/src/main/java/androidx/core/graphics/drawable/IconCompat.java b/compat/src/main/java/androidx/core/graphics/drawable/IconCompat.java
index cd9968c..366ddf3 100644
--- a/compat/src/main/java/androidx/core/graphics/drawable/IconCompat.java
+++ b/compat/src/main/java/androidx/core/graphics/drawable/IconCompat.java
@@ -16,6 +16,12 @@
 
 package androidx.core.graphics.drawable;
 
+import static android.graphics.drawable.Icon.TYPE_ADAPTIVE_BITMAP;
+import static android.graphics.drawable.Icon.TYPE_BITMAP;
+import static android.graphics.drawable.Icon.TYPE_DATA;
+import static android.graphics.drawable.Icon.TYPE_RESOURCE;
+import static android.graphics.drawable.Icon.TYPE_URI;
+
 import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
@@ -57,6 +63,7 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.core.content.ContextCompat;
 import androidx.core.content.res.ResourcesCompat;
+import androidx.core.os.BuildCompat;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -79,34 +86,6 @@
      */
     public static final int TYPE_UNKOWN = -1;
 
-    // TODO: Switch these to the public constants in the beta branch.
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY)
-    public static final int TYPE_BITMAP = 1;
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY)
-    public static final int TYPE_RESOURCE = 2;
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY)
-    public static final int TYPE_DATA = 3;
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY)
-    public static final int TYPE_URI = 4;
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY)
-    public static final int TYPE_ADAPTIVE_BITMAP = 5;
-
-
     /**
      * @hide
      */
@@ -645,8 +624,10 @@
      */
     @IconType
     @RequiresApi(23)
-    public static int getType(Icon icon) {
-        // TODO: Switch to public APIs on P+ in beta branch.
+    public static int getType(@NonNull Icon icon) {
+        if (BuildCompat.isAtLeastP()) {
+            return icon.getType();
+        }
         try {
             return (int) icon.getClass().getMethod("getType").invoke(icon);
         } catch (IllegalAccessException e) {
@@ -671,8 +652,10 @@
      */
     @Nullable
     @RequiresApi(23)
-    public static String getResPackage(Icon icon) {
-        // TODO: Switch to public APIs on P+ in beta branch.
+    public static String getResPackage(@NonNull Icon icon) {
+        if (BuildCompat.isAtLeastP()) {
+            return icon.getResPackage();
+        }
         try {
             return (String) icon.getClass().getMethod("getResPackage").invoke(icon);
         } catch (IllegalAccessException e) {
@@ -697,8 +680,10 @@
      */
     @IdRes
     @RequiresApi(23)
-    public static int getResId(Icon icon) {
-        // TODO: Switch to public APIs on P+ in beta branch.
+    public static int getResId(@NonNull Icon icon) {
+        if (BuildCompat.isAtLeastP()) {
+            return icon.getResId();
+        }
         try {
             return (int) icon.getClass().getMethod("getResId").invoke(icon);
         } catch (IllegalAccessException e) {
@@ -723,8 +708,10 @@
      */
     @Nullable
     @RequiresApi(23)
-    public Uri getUri(Icon icon) {
-        // TODO: Switch to public APIs on P+ in beta branch.
+    public Uri getUri(@NonNull Icon icon) {
+        if (BuildCompat.isAtLeastP()) {
+            return icon.getUri();
+        }
         try {
             return (Uri) icon.getClass().getMethod("getUri").invoke(icon);
         } catch (IllegalAccessException e) {
diff --git a/core/ktx/OWNERS b/core/ktx/OWNERS
new file mode 100644
index 0000000..e450f4c
--- /dev/null
+++ b/core/ktx/OWNERS
@@ -0,0 +1 @@
+jakew@google.com
diff --git a/core/ktx/api/0.1.txt b/core/ktx/api/0.1.txt
new file mode 100644
index 0000000..e324352
--- /dev/null
+++ b/core/ktx/api/0.1.txt
@@ -0,0 +1,673 @@
+package androidx.animation {
+
+  public final class AnimatorKt {
+    ctor public AnimatorKt();
+    method public static final android.animation.Animator.AnimatorListener addListener(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onEnd = "null", kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onStart = "null", kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onCancel = "null", kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onRepeat = "null");
+    method @RequiresApi(19) public static final android.animation.Animator.AnimatorPauseListener addPauseListener(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onResume = "null", kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onPause = "null");
+    method public static final android.animation.Animator.AnimatorListener doOnCancel(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static final android.animation.Animator.AnimatorListener doOnEnd(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method @RequiresApi(19) public static final android.animation.Animator.AnimatorPauseListener doOnPause(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static final android.animation.Animator.AnimatorListener doOnRepeat(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method @RequiresApi(19) public static final android.animation.Animator.AnimatorPauseListener doOnResume(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static final android.animation.Animator.AnimatorListener doOnStart(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+  }
+
+}
+
+package androidx.content {
+
+  public final class ContentValuesKt {
+    ctor public ContentValuesKt();
+    method public static final error.NonExistentClass contentValuesOf(kotlin.Pair<String,?>... pairs);
+  }
+
+  public final class ContextKt {
+    ctor public ContextKt();
+    method public static final void withStyledAttributes(android.content.Context, android.util.AttributeSet? set = "null", int[] attrs, @AttrRes int defStyleAttr = "0", @StyleRes int defStyleRes = "0", kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+    method public static final void withStyledAttributes(android.content.Context, @StyleRes int resourceId, int[] attrs, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+  }
+
+  public final class SharedPreferencesKt {
+    ctor public SharedPreferencesKt();
+    method public static final void edit(android.content.SharedPreferences, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action);
+  }
+
+}
+
+package androidx.content.res {
+
+  public final class TypedArrayKt {
+    ctor public TypedArrayKt();
+    method public static final boolean getBooleanOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method @ColorInt public static final int getColorOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static final android.content.res.ColorStateList getColorStateListOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static final float getDimensionOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method @Dimension public static final int getDimensionPixelOffsetOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method @Dimension public static final int getDimensionPixelSizeOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static final android.graphics.drawable.Drawable getDrawableOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static final float getFloatOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method @RequiresApi(26) public static final android.graphics.Typeface getFontOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static final int getIntOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static final int getIntegerOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static final String getStringOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static final CharSequence[] getTextArrayOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static final CharSequence getTextOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+  }
+
+}
+
+package androidx.database {
+
+  public final class CursorKt {
+    ctor public CursorKt();
+    method public static final byte[] getBlob(android.database.Cursor, String columnName);
+    method public static final byte[]? getBlobOrNull(android.database.Cursor, int index);
+    method public static final error.NonExistentClass getBlobOrNull(android.database.Cursor, String columnName);
+    method public static final double getDouble(android.database.Cursor, String columnName);
+    method public static final Double? getDoubleOrNull(android.database.Cursor, int index);
+    method public static final error.NonExistentClass getDoubleOrNull(android.database.Cursor, String columnName);
+    method public static final float getFloat(android.database.Cursor, String columnName);
+    method public static final Float? getFloatOrNull(android.database.Cursor, int index);
+    method public static final error.NonExistentClass getFloatOrNull(android.database.Cursor, String columnName);
+    method public static final int getInt(android.database.Cursor, String columnName);
+    method public static final Integer? getIntOrNull(android.database.Cursor, int index);
+    method public static final error.NonExistentClass getIntOrNull(android.database.Cursor, String columnName);
+    method public static final long getLong(android.database.Cursor, String columnName);
+    method public static final Long? getLongOrNull(android.database.Cursor, int index);
+    method public static final error.NonExistentClass getLongOrNull(android.database.Cursor, String columnName);
+    method public static final short getShort(android.database.Cursor, String columnName);
+    method public static final Short? getShortOrNull(android.database.Cursor, int index);
+    method public static final error.NonExistentClass getShortOrNull(android.database.Cursor, String columnName);
+    method public static final String getString(android.database.Cursor, String columnName);
+    method public static final String? getStringOrNull(android.database.Cursor, int index);
+    method public static final error.NonExistentClass getStringOrNull(android.database.Cursor, String columnName);
+  }
+
+}
+
+package androidx.database.sqlite {
+
+  public final class SQLiteDatabaseKt {
+    ctor public SQLiteDatabaseKt();
+    method public static final <T> T! transaction(android.database.sqlite.SQLiteDatabase, boolean exclusive = "true", kotlin.jvm.functions.Function1<? super android.database.sqlite.SQLiteDatabase,? extends T> body);
+  }
+
+}
+
+package androidx.graphics {
+
+  public final class BitmapKt {
+    ctor public BitmapKt();
+    method public static final android.graphics.Bitmap applyCanvas(android.graphics.Bitmap, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static final android.graphics.Bitmap createBitmap(int width, int height, android.graphics.Bitmap.Config config = "Bitmap.Config.ARGB_8888");
+    method @RequiresApi(26) public static final android.graphics.Bitmap createBitmap(int width, int height, android.graphics.Bitmap.Config config = "Bitmap.Config.ARGB_8888", boolean hasAlpha = "true", android.graphics.ColorSpace colorSpace = "ColorSpace.get(ColorSpace.Named.SRGB)");
+    method public static final operator int get(android.graphics.Bitmap, int x, int y);
+    method public static final android.graphics.Bitmap scale(android.graphics.Bitmap, int width, int height, boolean filter = "true");
+    method public static final operator void set(android.graphics.Bitmap, int x, int y, @ColorInt int color);
+  }
+
+  public final class CanvasKt {
+    ctor public CanvasKt();
+    method public static final void withRotation(android.graphics.Canvas, float degrees = "0.0f", float pivotX = "0.0f", float pivotY = "0.0f", kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static final void withSave(android.graphics.Canvas, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static final void withScale(android.graphics.Canvas, float x = "1.0f", float y = "1.0f", float pivotX = "0.0f", float pivotY = "0.0f", kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static final void withSkew(android.graphics.Canvas, float x = "0.0f", float y = "0.0f", kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static final void withTranslation(android.graphics.Canvas, float x = "0.0f", float y = "0.0f", kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+  }
+
+  public final class ColorKt {
+    ctor public ColorKt();
+    method @RequiresApi(26) public static final operator float component1(android.graphics.Color);
+    method public static final operator int component1(int);
+    method @RequiresApi(26) public static final operator float component1(long);
+    method @RequiresApi(26) public static final operator float component2(android.graphics.Color);
+    method public static final operator int component2(int);
+    method @RequiresApi(26) public static final operator float component2(long);
+    method @RequiresApi(26) public static final operator float component3(android.graphics.Color);
+    method public static final operator int component3(int);
+    method @RequiresApi(26) public static final operator float component3(long);
+    method @RequiresApi(26) public static final operator float component4(android.graphics.Color);
+    method public static final operator int component4(int);
+    method @RequiresApi(26) public static final operator float component4(long);
+    method public static final int getAlpha(int);
+    method @RequiresApi(26) public static final float getAlpha(long);
+    method public static final int getBlue(int);
+    method @RequiresApi(26) public static final float getBlue(long);
+    method @RequiresApi(26) public static final android.graphics.ColorSpace getColorSpace(long);
+    method public static final int getGreen(int);
+    method @RequiresApi(26) public static final float getGreen(long);
+    method @RequiresApi(26) public static final float getLuminance(int);
+    method @RequiresApi(26) public static final float getLuminance(long);
+    method public static final int getRed(int);
+    method @RequiresApi(26) public static final float getRed(long);
+    method @RequiresApi(26) public static final boolean isSrgb(long);
+    method @RequiresApi(26) public static final boolean isWideGamut(long);
+    method @RequiresApi(26) public static final operator android.graphics.Color plus(android.graphics.Color, android.graphics.Color c);
+    method @RequiresApi(26) public static final android.graphics.Color toColor(int);
+    method @RequiresApi(26) public static final android.graphics.Color toColor(long);
+    method @RequiresApi(26) @ColorInt public static final int toColorInt(long);
+    method @RequiresApi(26) @ColorLong public static final long toColorLong(int);
+  }
+
+  public final class MatrixKt {
+    ctor public MatrixKt();
+    method public static final error.NonExistentClass rotationMatrix(float degrees, float px = "0.0f", float py = "0.0f");
+    method public static final error.NonExistentClass scaleMatrix(float sx = "1.0f", float sy = "1.0f");
+    method public static final operator error.NonExistentClass times(android.graphics.Matrix, android.graphics.Matrix m);
+    method public static final error.NonExistentClass translationMatrix(float tx = "0.0f", float ty = "0.0f");
+    method public static final error.NonExistentClass values(android.graphics.Matrix);
+  }
+
+  public final class PathKt {
+    ctor public PathKt();
+    method @RequiresApi(19) public static final infix android.graphics.Path and(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(26) public static final Iterable<androidx.graphics.PathSegment> flatten(android.graphics.Path, float error = "0.5f");
+    method @RequiresApi(19) public static final operator android.graphics.Path minus(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static final infix android.graphics.Path or(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static final operator android.graphics.Path plus(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static final infix android.graphics.Path xor(android.graphics.Path, android.graphics.Path p);
+  }
+
+  public final class PathSegment {
+    ctor public PathSegment(android.graphics.PointF start, float startFraction, android.graphics.PointF end, float endFraction);
+    method public final android.graphics.PointF component1();
+    method public final float component2();
+    method public final android.graphics.PointF component3();
+    method public final float component4();
+    method public final androidx.graphics.PathSegment copy(android.graphics.PointF start, float startFraction, android.graphics.PointF end, float endFraction);
+    method public final android.graphics.PointF getEnd();
+    method public final float getEndFraction();
+    method public final android.graphics.PointF getStart();
+    method public final float getStartFraction();
+  }
+
+  public final class PictureKt {
+    ctor public PictureKt();
+    method public static final android.graphics.Picture record(android.graphics.Picture, int width, int height, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+  }
+
+  public final class PointKt {
+    ctor public PointKt();
+    method public static final operator int component1(android.graphics.Point);
+    method public static final operator float component1(android.graphics.PointF);
+    method public static final operator int component2(android.graphics.Point);
+    method public static final operator float component2(android.graphics.PointF);
+    method public static final operator android.graphics.Point minus(android.graphics.Point, android.graphics.Point p);
+    method public static final operator android.graphics.PointF minus(android.graphics.PointF, android.graphics.PointF p);
+    method public static final operator android.graphics.Point minus(android.graphics.Point, int xy);
+    method public static final operator android.graphics.PointF minus(android.graphics.PointF, float xy);
+    method public static final operator android.graphics.Point plus(android.graphics.Point, android.graphics.Point p);
+    method public static final operator android.graphics.PointF plus(android.graphics.PointF, android.graphics.PointF p);
+    method public static final operator android.graphics.Point plus(android.graphics.Point, int xy);
+    method public static final operator android.graphics.PointF plus(android.graphics.PointF, float xy);
+    method public static final android.graphics.Point toPoint(android.graphics.PointF);
+    method public static final android.graphics.PointF toPointF(android.graphics.Point);
+    method public static final operator android.graphics.Point unaryMinus(android.graphics.Point);
+    method public static final operator android.graphics.PointF unaryMinus(android.graphics.PointF);
+  }
+
+  public final class PorterDuffKt {
+    ctor public PorterDuffKt();
+    method public static final android.graphics.PorterDuffColorFilter toColorFilter(android.graphics.PorterDuff.Mode, int color);
+    method public static final android.graphics.PorterDuffXfermode toXfermode(android.graphics.PorterDuff.Mode);
+  }
+
+  public final class RectKt {
+    ctor public RectKt();
+    method public static final infix android.graphics.Rect and(android.graphics.Rect, android.graphics.Rect r);
+    method public static final infix android.graphics.RectF and(android.graphics.RectF, android.graphics.RectF r);
+    method public static final operator int component1(android.graphics.Rect);
+    method public static final operator float component1(android.graphics.RectF);
+    method public static final operator int component2(android.graphics.Rect);
+    method public static final operator float component2(android.graphics.RectF);
+    method public static final operator int component3(android.graphics.Rect);
+    method public static final operator float component3(android.graphics.RectF);
+    method public static final operator int component4(android.graphics.Rect);
+    method public static final operator float component4(android.graphics.RectF);
+    method public static final operator boolean contains(android.graphics.Rect, android.graphics.Point p);
+    method public static final operator boolean contains(android.graphics.RectF, android.graphics.PointF p);
+    method public static final operator android.graphics.Region minus(android.graphics.Rect, android.graphics.Rect r);
+    method public static final operator android.graphics.Region minus(android.graphics.RectF, android.graphics.RectF r);
+    method public static final operator android.graphics.Rect minus(android.graphics.Rect, int xy);
+    method public static final operator android.graphics.RectF minus(android.graphics.RectF, float xy);
+    method public static final operator android.graphics.Rect minus(android.graphics.Rect, android.graphics.Point xy);
+    method public static final operator android.graphics.RectF minus(android.graphics.RectF, android.graphics.PointF xy);
+    method public static final infix android.graphics.Rect or(android.graphics.Rect, android.graphics.Rect r);
+    method public static final infix android.graphics.RectF or(android.graphics.RectF, android.graphics.RectF r);
+    method public static final operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Rect r);
+    method public static final operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.RectF r);
+    method public static final operator android.graphics.Rect plus(android.graphics.Rect, int xy);
+    method public static final operator android.graphics.RectF plus(android.graphics.RectF, float xy);
+    method public static final operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Point xy);
+    method public static final operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.PointF xy);
+    method public static final android.graphics.Rect toRect(android.graphics.RectF);
+    method public static final android.graphics.RectF toRectF(android.graphics.Rect);
+    method public static final android.graphics.Region toRegion(android.graphics.Rect);
+    method public static final android.graphics.Region toRegion(android.graphics.RectF);
+    method public static final error.NonExistentClass transform(android.graphics.RectF, android.graphics.Matrix m);
+    method public static final infix android.graphics.Region xor(android.graphics.Rect, android.graphics.Rect r);
+    method public static final infix android.graphics.Region xor(android.graphics.RectF, android.graphics.RectF r);
+  }
+
+  public final class RegionKt {
+    ctor public RegionKt();
+    method public static final infix android.graphics.Region and(android.graphics.Region, android.graphics.Rect r);
+    method public static final infix android.graphics.Region and(android.graphics.Region, android.graphics.Region r);
+    method public static final operator boolean contains(android.graphics.Region, android.graphics.Point p);
+    method public static final void forEach(android.graphics.Region, kotlin.jvm.functions.Function1<? super android.graphics.Rect,kotlin.Unit> action);
+    method public static final operator java.util.Iterator<android.graphics.Rect> iterator(android.graphics.Region);
+    method public static final operator android.graphics.Region minus(android.graphics.Region, android.graphics.Rect r);
+    method public static final operator android.graphics.Region minus(android.graphics.Region, android.graphics.Region r);
+    method public static final operator android.graphics.Region not(android.graphics.Region);
+    method public static final infix android.graphics.Region or(android.graphics.Region, android.graphics.Rect r);
+    method public static final infix android.graphics.Region or(android.graphics.Region, android.graphics.Region r);
+    method public static final operator android.graphics.Region plus(android.graphics.Region, android.graphics.Rect r);
+    method public static final operator android.graphics.Region plus(android.graphics.Region, android.graphics.Region r);
+    method public static final operator android.graphics.Region unaryMinus(android.graphics.Region);
+    method public static final infix android.graphics.Region xor(android.graphics.Region, android.graphics.Rect r);
+    method public static final infix android.graphics.Region xor(android.graphics.Region, android.graphics.Region r);
+  }
+
+  public final class ShaderKt {
+    ctor public ShaderKt();
+    method public static final void transform(android.graphics.Shader, kotlin.jvm.functions.Function1<? super android.graphics.Matrix,kotlin.Unit> block);
+  }
+
+}
+
+package androidx.graphics.drawable {
+
+  public final class BitmapDrawableKt {
+    ctor public BitmapDrawableKt();
+    method public static final android.graphics.drawable.BitmapDrawable toDrawable(android.graphics.Bitmap, android.content.res.Resources resources);
+  }
+
+  public final class ColorDrawableKt {
+    ctor public ColorDrawableKt();
+    method public static final android.graphics.drawable.ColorDrawable toDrawable(int);
+    method @RequiresApi(26) public static final android.graphics.drawable.ColorDrawable toDrawable(android.graphics.Color);
+  }
+
+  public final class DrawableKt {
+    ctor public DrawableKt();
+    method public static final android.graphics.Bitmap toBitmap(android.graphics.drawable.Drawable, int width = "intrinsicWidth", int height = "intrinsicHeight", android.graphics.Bitmap.Config? config = "null");
+    method public static final void updateBounds(android.graphics.drawable.Drawable, int left = "bounds.left", int top = "bounds.top", int right = "bounds.right", int bottom = "bounds.bottom");
+  }
+
+  public final class IconKt {
+    ctor public IconKt();
+    method @RequiresApi(26) public static final android.graphics.drawable.Icon toAdaptiveIcon(android.graphics.Bitmap);
+    method @RequiresApi(26) public static final android.graphics.drawable.Icon toIcon(android.graphics.Bitmap);
+    method @RequiresApi(26) public static final android.graphics.drawable.Icon toIcon(android.net.Uri);
+    method @RequiresApi(26) public static final android.graphics.drawable.Icon toIcon(byte[]);
+  }
+
+}
+
+package androidx.net {
+
+  public final class UriKt {
+    ctor public UriKt();
+    method public static final android.net.Uri toUri(String);
+  }
+
+}
+
+package androidx.os {
+
+  public final class BundleKt {
+    ctor public BundleKt();
+    method public static final error.NonExistentClass bundleOf(kotlin.Pair<String,?>... pairs);
+  }
+
+  public final class HandlerKt {
+    ctor public HandlerKt();
+    method public static final error.NonExistentClass postAtTime(android.os.Handler, long uptimeMillis, Object? token = "null", kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method public static final void postDelayed(android.os.Handler, Runnable runnable, Object? token, long delayInMillis);
+    method public static final error.NonExistentClass postDelayed(android.os.Handler, long delayInMillis, Object? token = "null", kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method public static final error.NonExistentClass postDelayed(android.os.Handler, long amount, java.util.concurrent.TimeUnit unit, Object? token = "null", kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method @RequiresApi(26) public static final error.NonExistentClass postDelayed(android.os.Handler, java.time.Duration duration, Object? token = "null", kotlin.jvm.functions.Function0<kotlin.Unit> action);
+  }
+
+  public final class PersistableBundleKt {
+    ctor public PersistableBundleKt();
+    method @RequiresApi(21) public static final error.NonExistentClass persistableBundleOf(kotlin.Pair<String,?>... pairs);
+  }
+
+  public final class TraceKt {
+    ctor public TraceKt();
+    method public static final <T> T! trace(String sectionName, kotlin.jvm.functions.Function0<? extends T> block);
+  }
+
+}
+
+package androidx.text {
+
+  public final class SpannableStringBuilderKt {
+    ctor public SpannableStringBuilderKt();
+    method public static final android.text.SpannableStringBuilder backgroundColor(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static final android.text.SpannableStringBuilder bold(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static final android.text.SpannedString buildSpannedString(kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static final android.text.SpannableStringBuilder color(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static final android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object[] spans, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static final android.text.SpannableStringBuilder italic(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static final android.text.SpannableStringBuilder underline(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+  }
+
+}
+
+package androidx.time {
+
+  public final class DayOfWeekKt {
+    ctor public DayOfWeekKt();
+    method @RequiresApi(26) public static final java.time.DayOfWeek asDayOfWeek(int);
+    method @RequiresApi(26) public static final int asInt(java.time.DayOfWeek);
+  }
+
+  public final class DurationKt {
+    ctor public DurationKt();
+    method @RequiresApi(26) public static final operator long component1(java.time.Duration);
+    method @RequiresApi(26) public static final operator int component2(java.time.Duration);
+    method @RequiresApi(26) public static final operator java.time.Duration div(java.time.Duration, long divisor);
+    method @RequiresApi(260) public static final java.time.Duration hours(int);
+    method @RequiresApi(260) public static final java.time.Duration hours(long);
+    method @RequiresApi(26) public static final java.time.Duration millis(int);
+    method @RequiresApi(26) public static final java.time.Duration millis(long);
+    method @RequiresApi(260) public static final java.time.Duration minutes(int);
+    method @RequiresApi(260) public static final java.time.Duration minutes(long);
+    method @RequiresApi(26) public static final java.time.Duration nanos(int);
+    method @RequiresApi(26) public static final java.time.Duration nanos(long);
+    method @RequiresApi(26) public static final java.time.Duration seconds(int);
+    method @RequiresApi(26) public static final java.time.Duration seconds(long);
+    method @RequiresApi(26) public static final operator java.time.Duration times(java.time.Duration, long multiplicand);
+    method @RequiresApi(26) public static final operator java.time.Duration unaryMinus(java.time.Duration);
+  }
+
+  public final class InstantKt {
+    ctor public InstantKt();
+    method @RequiresApi(26) public static final java.time.Instant asEpochMillis(long);
+    method @RequiresApi(26) public static final java.time.Instant asEpochSeconds(long);
+    method @RequiresApi(26) public static final operator long component1(java.time.Instant);
+    method @RequiresApi(26) public static final operator int component2(java.time.Instant);
+  }
+
+  public final class LocalDateKt {
+    ctor public LocalDateKt();
+    method @RequiresApi(26) public static final operator int component1(java.time.LocalDate);
+    method @RequiresApi(26) public static final operator java.time.Month component2(java.time.LocalDate);
+    method @RequiresApi(26) public static final operator int component3(java.time.LocalDate);
+  }
+
+  public final class LocalDateTimeKt {
+    ctor public LocalDateTimeKt();
+    method @RequiresApi(26) public static final operator java.time.LocalDate component1(java.time.LocalDateTime);
+    method @RequiresApi(26) public static final operator java.time.LocalTime component2(java.time.LocalDateTime);
+  }
+
+  public final class LocalTimeKt {
+    ctor public LocalTimeKt();
+    method @RequiresApi(26) public static final operator int component1(java.time.LocalTime);
+    method @RequiresApi(26) public static final operator int component2(java.time.LocalTime);
+    method @RequiresApi(26) public static final operator int component3(java.time.LocalTime);
+    method @RequiresApi(26) public static final operator int component4(java.time.LocalTime);
+  }
+
+  public final class MonthDayKt {
+    ctor public MonthDayKt();
+    method @RequiresApi(26) public static final operator java.time.Month component1(java.time.MonthDay);
+    method @RequiresApi(26) public static final operator int component2(java.time.MonthDay);
+  }
+
+  public final class MonthKt {
+    ctor public MonthKt();
+    method @RequiresApi(26) public static final int asInt(java.time.Month);
+    method @RequiresApi(26) public static final java.time.Month asMonth(int);
+  }
+
+  public final class OffsetDateTimeKt {
+    ctor public OffsetDateTimeKt();
+    method @RequiresApi(26) public static final operator java.time.LocalDateTime component1(java.time.OffsetDateTime);
+    method @RequiresApi(26) public static final operator java.time.ZoneOffset component2(java.time.OffsetDateTime);
+  }
+
+  public final class OffsetTimeKt {
+    ctor public OffsetTimeKt();
+    method @RequiresApi(26) public static final operator java.time.LocalTime component1(java.time.OffsetTime);
+    method @RequiresApi(26) public static final operator java.time.ZoneOffset component2(java.time.OffsetTime);
+  }
+
+  public final class PeriodKt {
+    ctor public PeriodKt();
+    method @RequiresApi(26) public static final operator int component1(java.time.Period);
+    method @RequiresApi(26) public static final operator int component2(java.time.Period);
+    method @RequiresApi(26) public static final operator int component3(java.time.Period);
+    method @RequiresApi(26) public static final java.time.Period days(int);
+    method @RequiresApi(26) public static final java.time.Period months(int);
+    method @RequiresApi(26) public static final operator java.time.Period times(java.time.Period, int multiplicand);
+    method @RequiresApi(26) public static final operator java.time.Period unaryMinus(java.time.Period);
+    method @RequiresApi(26) public static final java.time.Period years(int);
+  }
+
+  public final class YearKt {
+    ctor public YearKt();
+    method @RequiresApi(26) public static final int asInt(java.time.Year);
+    method @RequiresApi(26) public static final java.time.Year asYear(int);
+  }
+
+  public final class YearMonthKt {
+    ctor public YearMonthKt();
+    method @RequiresApi(26) public static final operator int component1(java.time.YearMonth);
+    method @RequiresApi(26) public static final operator java.time.Month component2(java.time.YearMonth);
+  }
+
+  public final class ZonedDateTimeKt {
+    ctor public ZonedDateTimeKt();
+    method @RequiresApi(26) public static final operator java.time.LocalDateTime component1(java.time.ZonedDateTime);
+    method @RequiresApi(26) public static final operator java.time.ZoneId component2(java.time.ZonedDateTime);
+  }
+
+}
+
+package androidx.transition {
+
+  public final class TransitionKt {
+    ctor public TransitionKt();
+    method @RequiresApi(19) public static final void addListener(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit>? onEnd = "null", kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit>? onStart = "null", kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit>? onCancel = "null", kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit>? onResume = "null", kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit>? onPause = "null");
+    method @RequiresApi(19) public static final void doOnCancel(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static final void doOnEnd(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static final void doOnPause(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static final void doOnResume(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static final void doOnStart(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+  }
+
+}
+
+package androidx.util {
+
+  public final class ArrayMapKt {
+    ctor public ArrayMapKt();
+    method @RequiresApi(19) public static final <K, V> android.util.ArrayMap<K,V> arrayMapOf();
+    method @RequiresApi(19) public static final <K, V> android.util.ArrayMap<K,V> arrayMapOf(kotlin.Pair<? extends K,? extends V>... pairs);
+  }
+
+  public final class ArraySetKt {
+    ctor public ArraySetKt();
+    method @RequiresApi(23) public static final <T> android.util.ArraySet<T> arraySetOf();
+    method @RequiresApi(23) public static final <T> android.util.ArraySet<T> arraySetOf(T... values);
+  }
+
+  public final class AtomicFileKt {
+    ctor public AtomicFileKt();
+    method @RequiresApi(17) public static final byte[] readBytes(android.util.AtomicFile);
+    method @RequiresApi(17) public static final String readText(android.util.AtomicFile, java.nio.charset.Charset charset = "Charsets.UTF_8");
+    method @RequiresApi(17) public static final void tryWrite(android.util.AtomicFile, kotlin.jvm.functions.Function1<? super java.io.FileOutputStream,kotlin.Unit> block);
+    method @RequiresApi(17) public static final void writeBytes(android.util.AtomicFile, byte[] array);
+    method @RequiresApi(17) public static final void writeText(android.util.AtomicFile, String text, java.nio.charset.Charset charset = "Charsets.UTF_8");
+  }
+
+  public final class HalfKt {
+    ctor public HalfKt();
+    method @RequiresApi(26) public static final android.util.Half toHalf(short);
+    method @RequiresApi(26) public static final android.util.Half toHalf(float);
+    method @RequiresApi(26) public static final android.util.Half toHalf(double);
+    method @RequiresApi(26) public static final android.util.Half toHalf(String);
+  }
+
+  public final class LongSparseArrayKt {
+    ctor public LongSparseArrayKt();
+    method @RequiresApi(16) public static final operator <T> boolean contains(android.util.LongSparseArray<T>, long key);
+    method @RequiresApi(16) public static final <T> boolean containsKey(android.util.LongSparseArray<T>, long key);
+    method @RequiresApi(16) public static final <T> boolean containsValue(android.util.LongSparseArray<T>, T! value);
+    method @RequiresApi(16) public static final <T> void forEach(android.util.LongSparseArray<T>, kotlin.jvm.functions.Function2<? super Long,? super T,kotlin.Unit> action);
+    method @RequiresApi(16) public static final <T> T! getOrDefault(android.util.LongSparseArray<T>, long key, T! defaultValue);
+    method @RequiresApi(16) public static final <T> T! getOrElse(android.util.LongSparseArray<T>, long key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+    method @RequiresApi(16) public static final <T> int getSize(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static final <T> boolean isEmpty(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static final <T> boolean isNotEmpty(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static final <T> kotlin.collections.LongIterator keyIterator(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static final operator <T> android.util.LongSparseArray<T> plus(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+    method @RequiresApi(16) public static final <T> void putAll(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+    method @RequiresApi(16) public static final <T> boolean remove(android.util.LongSparseArray<T>, long key, T! value);
+    method @RequiresApi(16) public static final operator <T> void set(android.util.LongSparseArray<T>, long key, T! value);
+    method @RequiresApi(16) public static final <T> java.util.Iterator<T> valueIterator(android.util.LongSparseArray<T>);
+  }
+
+  public final class PairKt {
+    ctor public PairKt();
+    method public static final operator <F, S> F! component1(android.util.Pair<F,S>);
+    method public static final operator <F, S> S! component2(android.util.Pair<F,S>);
+    method public static final <F, S> android.util.Pair<F,S> toAndroidPair(kotlin.Pair<? extends F,? extends S>);
+    method public static final <F, S> kotlin.Pair<F,S> toKotlinPair(android.util.Pair<F,S>);
+  }
+
+  public final class RangeKt {
+    ctor public RangeKt();
+    method @RequiresApi(21) public static final infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> and(android.util.Range<T>, android.util.Range<T> other);
+    method @RequiresApi(21) public static final operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, T value);
+    method @RequiresApi(21) public static final operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, android.util.Range<T> other);
+    method @RequiresApi(21) public static final infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> rangeTo(T, T that);
+    method @RequiresApi(21) public static final <T extends java.lang.Comparable<? super T>> kotlin.ranges.ClosedRange<T> toClosedRange(android.util.Range<T>);
+    method @RequiresApi(21) public static final <T extends java.lang.Comparable<? super T>> android.util.Range<T> toRange(kotlin.ranges.ClosedRange<T>);
+  }
+
+  public final class SizeKt {
+    ctor public SizeKt();
+    method @RequiresApi(21) public static final operator int component1(android.util.Size);
+    method @RequiresApi(21) public static final operator float component1(android.util.SizeF);
+    method @RequiresApi(21) public static final operator int component2(android.util.Size);
+    method @RequiresApi(21) public static final operator float component2(android.util.SizeF);
+  }
+
+  public final class SparseArrayKt {
+    ctor public SparseArrayKt();
+    method public static final operator <T> boolean contains(android.util.SparseArray<T>, int key);
+    method public static final <T> boolean containsKey(android.util.SparseArray<T>, int key);
+    method public static final <T> boolean containsValue(android.util.SparseArray<T>, T! value);
+    method public static final <T> void forEach(android.util.SparseArray<T>, kotlin.jvm.functions.Function2<? super Integer,? super T,kotlin.Unit> action);
+    method public static final <T> T! getOrDefault(android.util.SparseArray<T>, int key, T! defaultValue);
+    method public static final <T> T! getOrElse(android.util.SparseArray<T>, int key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+    method public static final <T> int getSize(android.util.SparseArray<T>);
+    method public static final <T> boolean isEmpty(android.util.SparseArray<T>);
+    method public static final <T> boolean isNotEmpty(android.util.SparseArray<T>);
+    method public static final <T> kotlin.collections.IntIterator keyIterator(android.util.SparseArray<T>);
+    method public static final operator <T> android.util.SparseArray<T> plus(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+    method public static final <T> void putAll(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+    method public static final <T> boolean remove(android.util.SparseArray<T>, int key, T! value);
+    method public static final operator <T> void set(android.util.SparseArray<T>, int key, T! value);
+    method public static final <T> java.util.Iterator<T> valueIterator(android.util.SparseArray<T>);
+  }
+
+  public final class SparseBooleanArrayKt {
+    ctor public SparseBooleanArrayKt();
+    method public static final operator boolean contains(android.util.SparseBooleanArray, int key);
+    method public static final boolean containsKey(android.util.SparseBooleanArray, int key);
+    method public static final boolean containsValue(android.util.SparseBooleanArray, boolean value);
+    method public static final void forEach(android.util.SparseBooleanArray, kotlin.jvm.functions.Function2<? super Integer,? super Boolean,kotlin.Unit> action);
+    method public static final boolean getOrDefault(android.util.SparseBooleanArray, int key, boolean defaultValue);
+    method public static final error.NonExistentClass getOrElse(android.util.SparseBooleanArray, int key, kotlin.jvm.functions.Function0<Boolean> defaultValue);
+    method public static final int getSize(android.util.SparseBooleanArray);
+    method public static final boolean isEmpty(android.util.SparseBooleanArray);
+    method public static final boolean isNotEmpty(android.util.SparseBooleanArray);
+    method public static final kotlin.collections.IntIterator keyIterator(android.util.SparseBooleanArray);
+    method public static final operator android.util.SparseBooleanArray plus(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+    method public static final void putAll(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+    method public static final boolean remove(android.util.SparseBooleanArray, int key, boolean value);
+    method public static final void removeAt(android.util.SparseBooleanArray, int index);
+    method public static final operator void set(android.util.SparseBooleanArray, int key, boolean value);
+    method public static final kotlin.collections.BooleanIterator valueIterator(android.util.SparseBooleanArray);
+  }
+
+  public final class SparseIntArrayKt {
+    ctor public SparseIntArrayKt();
+    method public static final operator boolean contains(android.util.SparseIntArray, int key);
+    method public static final boolean containsKey(android.util.SparseIntArray, int key);
+    method public static final boolean containsValue(android.util.SparseIntArray, int value);
+    method public static final void forEach(android.util.SparseIntArray, kotlin.jvm.functions.Function2<? super Integer,? super Integer,kotlin.Unit> action);
+    method public static final int getOrDefault(android.util.SparseIntArray, int key, int defaultValue);
+    method public static final error.NonExistentClass getOrElse(android.util.SparseIntArray, int key, kotlin.jvm.functions.Function0<Integer> defaultValue);
+    method public static final int getSize(android.util.SparseIntArray);
+    method public static final boolean isEmpty(android.util.SparseIntArray);
+    method public static final boolean isNotEmpty(android.util.SparseIntArray);
+    method public static final kotlin.collections.IntIterator keyIterator(android.util.SparseIntArray);
+    method public static final operator android.util.SparseIntArray plus(android.util.SparseIntArray, android.util.SparseIntArray other);
+    method public static final void putAll(android.util.SparseIntArray, android.util.SparseIntArray other);
+    method public static final boolean remove(android.util.SparseIntArray, int key, int value);
+    method public static final operator void set(android.util.SparseIntArray, int key, int value);
+    method public static final kotlin.collections.IntIterator valueIterator(android.util.SparseIntArray);
+  }
+
+  public final class SparseLongArrayKt {
+    ctor public SparseLongArrayKt();
+    method @RequiresApi(18) public static final operator boolean contains(android.util.SparseLongArray, int key);
+    method @RequiresApi(18) public static final boolean containsKey(android.util.SparseLongArray, int key);
+    method @RequiresApi(18) public static final boolean containsValue(android.util.SparseLongArray, long value);
+    method @RequiresApi(18) public static final void forEach(android.util.SparseLongArray, kotlin.jvm.functions.Function2<? super Integer,? super Long,kotlin.Unit> action);
+    method @RequiresApi(18) public static final long getOrDefault(android.util.SparseLongArray, int key, long defaultValue);
+    method @RequiresApi(18) public static final error.NonExistentClass getOrElse(android.util.SparseLongArray, int key, kotlin.jvm.functions.Function0<Long> defaultValue);
+    method @RequiresApi(18) public static final int getSize(android.util.SparseLongArray);
+    method @RequiresApi(18) public static final boolean isEmpty(android.util.SparseLongArray);
+    method @RequiresApi(18) public static final boolean isNotEmpty(android.util.SparseLongArray);
+    method @RequiresApi(18) public static final kotlin.collections.IntIterator keyIterator(android.util.SparseLongArray);
+    method @RequiresApi(18) public static final operator android.util.SparseLongArray plus(android.util.SparseLongArray, android.util.SparseLongArray other);
+    method @RequiresApi(18) public static final void putAll(android.util.SparseLongArray, android.util.SparseLongArray other);
+    method @RequiresApi(18) public static final boolean remove(android.util.SparseLongArray, int key, long value);
+    method @RequiresApi(18) public static final operator void set(android.util.SparseLongArray, int key, long value);
+    method @RequiresApi(18) public static final kotlin.collections.LongIterator valueIterator(android.util.SparseLongArray);
+  }
+
+}
+
+package androidx.view {
+
+  public final class ViewGroupKt {
+    ctor public ViewGroupKt();
+    method public static final operator boolean contains(android.view.ViewGroup, android.view.View view);
+    method public static final void forEach(android.view.ViewGroup, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static final void forEachIndexed(android.view.ViewGroup, kotlin.jvm.functions.Function2<? super Integer,? super android.view.View,kotlin.Unit> action);
+    method public static final operator android.view.View get(android.view.ViewGroup, int index);
+    method public static final int getSize(android.view.ViewGroup);
+    method public static final boolean isEmpty(android.view.ViewGroup);
+    method public static final boolean isNotEmpty(android.view.ViewGroup);
+    method public static final operator java.util.Iterator<android.view.View> iterator(android.view.ViewGroup);
+    method public static final operator void minusAssign(android.view.ViewGroup, android.view.View view);
+    method public static final operator void plusAssign(android.view.ViewGroup, android.view.View view);
+    method public static final void setMargins(android.view.ViewGroup.MarginLayoutParams, int size);
+    method public static final void updateMargins(android.view.ViewGroup.MarginLayoutParams, int left = "leftMargin", int top = "topMargin", int right = "rightMargin", int bottom = "bottomMargin");
+    method @RequiresApi(17) public static final void updateMarginsRelative(android.view.ViewGroup.MarginLayoutParams, int start = "marginStart", int top = "topMargin", int end = "marginEnd", int bottom = "bottomMargin");
+  }
+
+  public final class ViewKt {
+    ctor public ViewKt();
+    method public static final void doOnLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static final void doOnNextLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static final void doOnPreDraw(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static final Runnable postDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method @RequiresApi(16) public static final Runnable postOnAnimationDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method public static final void setPadding(android.view.View, int size);
+    method public static final android.graphics.Bitmap toBitmap(android.view.View, android.graphics.Bitmap.Config config = "Bitmap.Config.ARGB_8888");
+    method public static final void updatePadding(android.view.View, int left = "paddingLeft", int top = "paddingTop", int right = "paddingRight", int bottom = "paddingBottom");
+    method @RequiresApi(17) public static final void updatePaddingRelative(android.view.View, int start = "paddingStart", int top = "paddingTop", int end = "paddingEnd", int bottom = "paddingBottom");
+  }
+
+}
+
diff --git a/core/ktx/api/0.2.txt b/core/ktx/api/0.2.txt
new file mode 100644
index 0000000..5fbfe40
--- /dev/null
+++ b/core/ktx/api/0.2.txt
@@ -0,0 +1,742 @@
+package androidx.animation {
+
+  public final class AnimatorKt {
+    ctor public AnimatorKt();
+    method public static android.animation.Animator.AnimatorListener addListener(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onEnd = "null", kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onStart = "null", kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onCancel = "null", kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onRepeat = "null");
+    method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener addPauseListener(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onResume = "null", kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onPause = "null");
+    method public static android.animation.Animator.AnimatorListener doOnCancel(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static android.animation.Animator.AnimatorListener doOnEnd(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener doOnPause(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static android.animation.Animator.AnimatorListener doOnRepeat(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener doOnResume(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static android.animation.Animator.AnimatorListener doOnStart(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+  }
+
+}
+
+package androidx.content {
+
+  public final class ContentValuesKt {
+    ctor public ContentValuesKt();
+    method public static error.NonExistentClass contentValuesOf(kotlin.Pair<String,?>... pairs);
+  }
+
+  public final class ContextKt {
+    ctor public ContextKt();
+    method public static void withStyledAttributes(android.content.Context, android.util.AttributeSet? set = "null", int[] attrs, @AttrRes int defStyleAttr = "0", @StyleRes int defStyleRes = "0", kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+    method public static void withStyledAttributes(android.content.Context, @StyleRes int resourceId, int[] attrs, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+  }
+
+  public final class SharedPreferencesKt {
+    ctor public SharedPreferencesKt();
+    method public static void edit(android.content.SharedPreferences, boolean commit = "false", kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action);
+  }
+
+}
+
+package androidx.content.res {
+
+  public final class TypedArrayKt {
+    ctor public TypedArrayKt();
+    method public static boolean getBooleanOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method @ColorInt public static int getColorOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static android.content.res.ColorStateList getColorStateListOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static float getDimensionOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method @Dimension public static int getDimensionPixelOffsetOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method @Dimension public static int getDimensionPixelSizeOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static android.graphics.drawable.Drawable getDrawableOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static float getFloatOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method @RequiresApi(26) public static android.graphics.Typeface getFontOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static int getIntOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static int getIntegerOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method @AnyRes public static int getResourceIdOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static String getStringOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static CharSequence[] getTextArrayOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static CharSequence getTextOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static <R> R! use(android.content.res.TypedArray, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,? extends R> block);
+  }
+
+}
+
+package androidx.database {
+
+  public final class CursorKt {
+    ctor public CursorKt();
+    method public static byte[] getBlob(android.database.Cursor, String columnName);
+    method public static byte[]? getBlobOrNull(android.database.Cursor, int index);
+    method public static error.NonExistentClass getBlobOrNull(android.database.Cursor, String columnName);
+    method public static double getDouble(android.database.Cursor, String columnName);
+    method public static Double? getDoubleOrNull(android.database.Cursor, int index);
+    method public static error.NonExistentClass getDoubleOrNull(android.database.Cursor, String columnName);
+    method public static float getFloat(android.database.Cursor, String columnName);
+    method public static Float? getFloatOrNull(android.database.Cursor, int index);
+    method public static error.NonExistentClass getFloatOrNull(android.database.Cursor, String columnName);
+    method public static int getInt(android.database.Cursor, String columnName);
+    method public static Integer? getIntOrNull(android.database.Cursor, int index);
+    method public static error.NonExistentClass getIntOrNull(android.database.Cursor, String columnName);
+    method public static long getLong(android.database.Cursor, String columnName);
+    method public static Long? getLongOrNull(android.database.Cursor, int index);
+    method public static error.NonExistentClass getLongOrNull(android.database.Cursor, String columnName);
+    method public static short getShort(android.database.Cursor, String columnName);
+    method public static Short? getShortOrNull(android.database.Cursor, int index);
+    method public static error.NonExistentClass getShortOrNull(android.database.Cursor, String columnName);
+    method public static String getString(android.database.Cursor, String columnName);
+    method public static String? getStringOrNull(android.database.Cursor, int index);
+    method public static error.NonExistentClass getStringOrNull(android.database.Cursor, String columnName);
+  }
+
+}
+
+package androidx.database.sqlite {
+
+  public final class SQLiteDatabaseKt {
+    ctor public SQLiteDatabaseKt();
+    method public static <T> T! transaction(android.database.sqlite.SQLiteDatabase, boolean exclusive = "true", kotlin.jvm.functions.Function1<? super android.database.sqlite.SQLiteDatabase,? extends T> body);
+  }
+
+}
+
+package androidx.graphics {
+
+  public final class BitmapKt {
+    ctor public BitmapKt();
+    method public static android.graphics.Bitmap applyCanvas(android.graphics.Bitmap, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static android.graphics.Bitmap createBitmap(int width, int height, android.graphics.Bitmap.Config config = "Bitmap.Config.ARGB_8888");
+    method @RequiresApi(26) public static android.graphics.Bitmap createBitmap(int width, int height, android.graphics.Bitmap.Config config = "Bitmap.Config.ARGB_8888", boolean hasAlpha = "true", android.graphics.ColorSpace colorSpace = "ColorSpace.get(ColorSpace.Named.SRGB)");
+    method public static operator int get(android.graphics.Bitmap, int x, int y);
+    method public static android.graphics.Bitmap scale(android.graphics.Bitmap, int width, int height, boolean filter = "true");
+    method public static operator void set(android.graphics.Bitmap, int x, int y, @ColorInt int color);
+  }
+
+  public final class CanvasKt {
+    ctor public CanvasKt();
+    method public static void withRotation(android.graphics.Canvas, float degrees = "0.0f", float pivotX = "0.0f", float pivotY = "0.0f", kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static void withSave(android.graphics.Canvas, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static void withScale(android.graphics.Canvas, float x = "1.0f", float y = "1.0f", float pivotX = "0.0f", float pivotY = "0.0f", kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static void withSkew(android.graphics.Canvas, float x = "0.0f", float y = "0.0f", kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static void withTranslation(android.graphics.Canvas, float x = "0.0f", float y = "0.0f", kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+  }
+
+  public final class ColorKt {
+    ctor public ColorKt();
+    method @RequiresApi(26) public static operator float component1(android.graphics.Color);
+    method public static operator int component1(int);
+    method @RequiresApi(26) public static operator float component1(long);
+    method @RequiresApi(26) public static operator float component2(android.graphics.Color);
+    method public static operator int component2(int);
+    method @RequiresApi(26) public static operator float component2(long);
+    method @RequiresApi(26) public static operator float component3(android.graphics.Color);
+    method public static operator int component3(int);
+    method @RequiresApi(26) public static operator float component3(long);
+    method @RequiresApi(26) public static operator float component4(android.graphics.Color);
+    method public static operator int component4(int);
+    method @RequiresApi(26) public static operator float component4(long);
+    method public static int getAlpha(int);
+    method @RequiresApi(26) public static float getAlpha(long);
+    method public static int getBlue(int);
+    method @RequiresApi(26) public static float getBlue(long);
+    method @RequiresApi(26) public static android.graphics.ColorSpace getColorSpace(long);
+    method public static int getGreen(int);
+    method @RequiresApi(26) public static float getGreen(long);
+    method @RequiresApi(26) public static float getLuminance(int);
+    method @RequiresApi(26) public static float getLuminance(long);
+    method public static int getRed(int);
+    method @RequiresApi(26) public static float getRed(long);
+    method @RequiresApi(26) public static boolean isSrgb(long);
+    method @RequiresApi(26) public static boolean isWideGamut(long);
+    method @RequiresApi(26) public static operator android.graphics.Color plus(android.graphics.Color, android.graphics.Color c);
+    method @RequiresApi(26) public static android.graphics.Color toColor(int);
+    method @RequiresApi(26) public static android.graphics.Color toColor(long);
+    method @RequiresApi(26) @ColorInt public static int toColorInt(long);
+    method @ColorInt public static int toColorInt(String);
+    method @RequiresApi(26) @ColorLong public static long toColorLong(int);
+  }
+
+  public final class MatrixKt {
+    ctor public MatrixKt();
+    method public static error.NonExistentClass rotationMatrix(float degrees, float px = "0.0f", float py = "0.0f");
+    method public static error.NonExistentClass scaleMatrix(float sx = "1.0f", float sy = "1.0f");
+    method public static operator error.NonExistentClass times(android.graphics.Matrix, android.graphics.Matrix m);
+    method public static error.NonExistentClass translationMatrix(float tx = "0.0f", float ty = "0.0f");
+    method public static error.NonExistentClass values(android.graphics.Matrix);
+  }
+
+  public final class PathKt {
+    ctor public PathKt();
+    method @RequiresApi(19) public static infix android.graphics.Path and(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(26) public static Iterable<androidx.graphics.PathSegment> flatten(android.graphics.Path, float error = "0.5f");
+    method @RequiresApi(19) public static operator android.graphics.Path minus(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static infix android.graphics.Path or(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static operator android.graphics.Path plus(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static infix android.graphics.Path xor(android.graphics.Path, android.graphics.Path p);
+  }
+
+  public final class PathSegment {
+    ctor public PathSegment(android.graphics.PointF start, float startFraction, android.graphics.PointF end, float endFraction);
+    method public android.graphics.PointF component1();
+    method public float component2();
+    method public android.graphics.PointF component3();
+    method public float component4();
+    method public androidx.graphics.PathSegment copy(android.graphics.PointF start, float startFraction, android.graphics.PointF end, float endFraction);
+    method public android.graphics.PointF getEnd();
+    method public float getEndFraction();
+    method public android.graphics.PointF getStart();
+    method public float getStartFraction();
+  }
+
+  public final class PictureKt {
+    ctor public PictureKt();
+    method public static android.graphics.Picture record(android.graphics.Picture, int width, int height, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+  }
+
+  public final class PointKt {
+    ctor public PointKt();
+    method public static operator int component1(android.graphics.Point);
+    method public static operator float component1(android.graphics.PointF);
+    method public static operator int component2(android.graphics.Point);
+    method public static operator float component2(android.graphics.PointF);
+    method public static operator android.graphics.Point minus(android.graphics.Point, android.graphics.Point p);
+    method public static operator android.graphics.PointF minus(android.graphics.PointF, android.graphics.PointF p);
+    method public static operator android.graphics.Point minus(android.graphics.Point, int xy);
+    method public static operator android.graphics.PointF minus(android.graphics.PointF, float xy);
+    method public static operator android.graphics.Point plus(android.graphics.Point, android.graphics.Point p);
+    method public static operator android.graphics.PointF plus(android.graphics.PointF, android.graphics.PointF p);
+    method public static operator android.graphics.Point plus(android.graphics.Point, int xy);
+    method public static operator android.graphics.PointF plus(android.graphics.PointF, float xy);
+    method public static android.graphics.Point toPoint(android.graphics.PointF);
+    method public static android.graphics.PointF toPointF(android.graphics.Point);
+    method public static operator android.graphics.Point unaryMinus(android.graphics.Point);
+    method public static operator android.graphics.PointF unaryMinus(android.graphics.PointF);
+  }
+
+  public final class PorterDuffKt {
+    ctor public PorterDuffKt();
+    method public static android.graphics.PorterDuffColorFilter toColorFilter(android.graphics.PorterDuff.Mode, int color);
+    method public static android.graphics.PorterDuffXfermode toXfermode(android.graphics.PorterDuff.Mode);
+  }
+
+  public final class RectKt {
+    ctor public RectKt();
+    method public static infix android.graphics.Rect and(android.graphics.Rect, android.graphics.Rect r);
+    method public static infix android.graphics.RectF and(android.graphics.RectF, android.graphics.RectF r);
+    method public static operator int component1(android.graphics.Rect);
+    method public static operator float component1(android.graphics.RectF);
+    method public static operator int component2(android.graphics.Rect);
+    method public static operator float component2(android.graphics.RectF);
+    method public static operator int component3(android.graphics.Rect);
+    method public static operator float component3(android.graphics.RectF);
+    method public static operator int component4(android.graphics.Rect);
+    method public static operator float component4(android.graphics.RectF);
+    method public static operator boolean contains(android.graphics.Rect, android.graphics.Point p);
+    method public static operator boolean contains(android.graphics.RectF, android.graphics.PointF p);
+    method public static operator android.graphics.Region minus(android.graphics.Rect, android.graphics.Rect r);
+    method public static operator android.graphics.Region minus(android.graphics.RectF, android.graphics.RectF r);
+    method public static operator android.graphics.Rect minus(android.graphics.Rect, int xy);
+    method public static operator android.graphics.RectF minus(android.graphics.RectF, float xy);
+    method public static operator android.graphics.Rect minus(android.graphics.Rect, android.graphics.Point xy);
+    method public static operator android.graphics.RectF minus(android.graphics.RectF, android.graphics.PointF xy);
+    method public static infix android.graphics.Rect or(android.graphics.Rect, android.graphics.Rect r);
+    method public static infix android.graphics.RectF or(android.graphics.RectF, android.graphics.RectF r);
+    method public static operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Rect r);
+    method public static operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.RectF r);
+    method public static operator android.graphics.Rect plus(android.graphics.Rect, int xy);
+    method public static operator android.graphics.RectF plus(android.graphics.RectF, float xy);
+    method public static operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Point xy);
+    method public static operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.PointF xy);
+    method public static android.graphics.Rect toRect(android.graphics.RectF);
+    method public static android.graphics.RectF toRectF(android.graphics.Rect);
+    method public static android.graphics.Region toRegion(android.graphics.Rect);
+    method public static android.graphics.Region toRegion(android.graphics.RectF);
+    method public static error.NonExistentClass transform(android.graphics.RectF, android.graphics.Matrix m);
+    method public static infix android.graphics.Region xor(android.graphics.Rect, android.graphics.Rect r);
+    method public static infix android.graphics.Region xor(android.graphics.RectF, android.graphics.RectF r);
+  }
+
+  public final class RegionKt {
+    ctor public RegionKt();
+    method public static infix android.graphics.Region and(android.graphics.Region, android.graphics.Rect r);
+    method public static infix android.graphics.Region and(android.graphics.Region, android.graphics.Region r);
+    method public static operator boolean contains(android.graphics.Region, android.graphics.Point p);
+    method public static void forEach(android.graphics.Region, kotlin.jvm.functions.Function1<? super android.graphics.Rect,kotlin.Unit> action);
+    method public static operator java.util.Iterator<android.graphics.Rect> iterator(android.graphics.Region);
+    method public static operator android.graphics.Region minus(android.graphics.Region, android.graphics.Rect r);
+    method public static operator android.graphics.Region minus(android.graphics.Region, android.graphics.Region r);
+    method public static operator android.graphics.Region not(android.graphics.Region);
+    method public static infix android.graphics.Region or(android.graphics.Region, android.graphics.Rect r);
+    method public static infix android.graphics.Region or(android.graphics.Region, android.graphics.Region r);
+    method public static operator android.graphics.Region plus(android.graphics.Region, android.graphics.Rect r);
+    method public static operator android.graphics.Region plus(android.graphics.Region, android.graphics.Region r);
+    method public static operator android.graphics.Region unaryMinus(android.graphics.Region);
+    method public static infix android.graphics.Region xor(android.graphics.Region, android.graphics.Rect r);
+    method public static infix android.graphics.Region xor(android.graphics.Region, android.graphics.Region r);
+  }
+
+  public final class ShaderKt {
+    ctor public ShaderKt();
+    method public static void transform(android.graphics.Shader, kotlin.jvm.functions.Function1<? super android.graphics.Matrix,kotlin.Unit> block);
+  }
+
+}
+
+package androidx.graphics.drawable {
+
+  public final class BitmapDrawableKt {
+    ctor public BitmapDrawableKt();
+    method public static android.graphics.drawable.BitmapDrawable toDrawable(android.graphics.Bitmap, android.content.res.Resources resources);
+  }
+
+  public final class ColorDrawableKt {
+    ctor public ColorDrawableKt();
+    method public static android.graphics.drawable.ColorDrawable toDrawable(int);
+    method @RequiresApi(26) public static android.graphics.drawable.ColorDrawable toDrawable(android.graphics.Color);
+  }
+
+  public final class DrawableKt {
+    ctor public DrawableKt();
+    method public static android.graphics.Bitmap toBitmap(android.graphics.drawable.Drawable, @Px int width = "intrinsicWidth", @Px int height = "intrinsicHeight", android.graphics.Bitmap.Config? config = "null");
+    method public static void updateBounds(android.graphics.drawable.Drawable, @Px int left = "bounds.left", @Px int top = "bounds.top", @Px int right = "bounds.right", @Px int bottom = "bounds.bottom");
+  }
+
+  public final class IconKt {
+    ctor public IconKt();
+    method @RequiresApi(26) public static android.graphics.drawable.Icon toAdaptiveIcon(android.graphics.Bitmap);
+    method @RequiresApi(26) public static android.graphics.drawable.Icon toIcon(android.graphics.Bitmap);
+    method @RequiresApi(26) public static android.graphics.drawable.Icon toIcon(android.net.Uri);
+    method @RequiresApi(26) public static android.graphics.drawable.Icon toIcon(byte[]);
+  }
+
+}
+
+package androidx.net {
+
+  public final class UriKt {
+    ctor public UriKt();
+    method public static android.net.Uri toUri(String);
+  }
+
+}
+
+package androidx.os {
+
+  public final class BundleKt {
+    ctor public BundleKt();
+    method public static error.NonExistentClass bundleOf(kotlin.Pair<String,?>... pairs);
+  }
+
+  public final class FileKt {
+    ctor public FileKt();
+    method public static android.net.Uri toUri(java.io.File);
+  }
+
+  public final class HandlerKt {
+    ctor public HandlerKt();
+    method public static error.NonExistentClass postAtTime(android.os.Handler, long uptimeMillis, Object? token = "null", kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method public static void postDelayed(android.os.Handler, Runnable runnable, Object? token, long delayInMillis);
+    method public static error.NonExistentClass postDelayed(android.os.Handler, long delayInMillis, Object? token = "null", kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method public static error.NonExistentClass postDelayed(android.os.Handler, long amount, java.util.concurrent.TimeUnit unit, Object? token = "null", kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method @RequiresApi(26) public static error.NonExistentClass postDelayed(android.os.Handler, java.time.Duration duration, Object? token = "null", kotlin.jvm.functions.Function0<kotlin.Unit> action);
+  }
+
+  public final class PersistableBundleKt {
+    ctor public PersistableBundleKt();
+    method @RequiresApi(21) public static error.NonExistentClass persistableBundleOf(kotlin.Pair<String,?>... pairs);
+  }
+
+  public final class TraceKt {
+    ctor public TraceKt();
+    method public static <T> T! trace(String sectionName, kotlin.jvm.functions.Function0<? extends T> block);
+  }
+
+}
+
+package androidx.text {
+
+  public final class CharSequenceKt {
+    ctor public CharSequenceKt();
+    method public static boolean isDigitsOnly(CharSequence);
+    method public static int trimmedLength(CharSequence);
+  }
+
+  public final class SpannableStringBuilderKt {
+    ctor public SpannableStringBuilderKt();
+    method public static android.text.SpannableStringBuilder backgroundColor(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder bold(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannedString buildSpannedString(kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder color(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object[] spans, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object span, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder italic(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder scale(android.text.SpannableStringBuilder, float proportion, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder strikeThrough(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder underline(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+  }
+
+  public final class SpannableStringKt {
+    ctor public SpannableStringKt();
+    method public static error.NonExistentClass clearSpans(android.text.Spannable);
+    method public static operator void minusAssign(android.text.Spannable, Object span);
+    method public static operator void plusAssign(android.text.Spannable, Object span);
+    method public static android.text.Spannable toSpannable(CharSequence);
+  }
+
+  public final class SpannedStringKt {
+    ctor public SpannedStringKt();
+    method public static android.text.Spanned toSpanned(CharSequence);
+  }
+
+  public final class StringKt {
+    ctor public StringKt();
+    method public static String htmlEncode(String);
+  }
+
+}
+
+package androidx.time {
+
+  public final class DayOfWeekKt {
+    ctor public DayOfWeekKt();
+    method @RequiresApi(26) deprecated public static java.time.DayOfWeek asDayOfWeek(int);
+    method @RequiresApi(26) deprecated public static int asInt(java.time.DayOfWeek);
+  }
+
+  public final class DeprecationKt {
+    ctor public DeprecationKt();
+  }
+
+  public final class DurationKt {
+    ctor public DurationKt();
+    method @RequiresApi(26) deprecated public static operator long component1(java.time.Duration);
+    method @RequiresApi(26) deprecated public static operator int component2(java.time.Duration);
+    method @RequiresApi(26) deprecated public static operator java.time.Duration div(java.time.Duration, long divisor);
+    method @RequiresApi(26) deprecated public static java.time.Duration hours(int);
+    method @RequiresApi(26) deprecated public static java.time.Duration hours(long);
+    method @RequiresApi(26) deprecated public static java.time.Duration millis(int);
+    method @RequiresApi(26) deprecated public static java.time.Duration millis(long);
+    method @RequiresApi(26) deprecated public static java.time.Duration minutes(int);
+    method @RequiresApi(26) deprecated public static java.time.Duration minutes(long);
+    method @RequiresApi(26) deprecated public static java.time.Duration nanos(int);
+    method @RequiresApi(26) deprecated public static java.time.Duration nanos(long);
+    method @RequiresApi(26) deprecated public static java.time.Duration seconds(int);
+    method @RequiresApi(26) deprecated public static java.time.Duration seconds(long);
+    method @RequiresApi(26) deprecated public static operator java.time.Duration times(java.time.Duration, long multiplicand);
+    method @RequiresApi(26) deprecated public static operator java.time.Duration unaryMinus(java.time.Duration);
+  }
+
+  public final class InstantKt {
+    ctor public InstantKt();
+    method @RequiresApi(26) deprecated public static java.time.Instant asEpochMillis(long);
+    method @RequiresApi(26) deprecated public static java.time.Instant asEpochSeconds(long);
+    method @RequiresApi(26) deprecated public static operator long component1(java.time.Instant);
+    method @RequiresApi(26) deprecated public static operator int component2(java.time.Instant);
+  }
+
+  public final class LocalDateKt {
+    ctor public LocalDateKt();
+    method @RequiresApi(26) deprecated public static operator int component1(java.time.LocalDate);
+    method @RequiresApi(26) deprecated public static operator java.time.Month component2(java.time.LocalDate);
+    method @RequiresApi(26) deprecated public static operator int component3(java.time.LocalDate);
+  }
+
+  public final class LocalDateTimeKt {
+    ctor public LocalDateTimeKt();
+    method @RequiresApi(26) deprecated public static operator java.time.LocalDate component1(java.time.LocalDateTime);
+    method @RequiresApi(26) deprecated public static operator java.time.LocalTime component2(java.time.LocalDateTime);
+  }
+
+  public final class LocalTimeKt {
+    ctor public LocalTimeKt();
+    method @RequiresApi(26) deprecated public static operator int component1(java.time.LocalTime);
+    method @RequiresApi(26) deprecated public static operator int component2(java.time.LocalTime);
+    method @RequiresApi(26) deprecated public static operator int component3(java.time.LocalTime);
+    method @RequiresApi(26) deprecated public static operator int component4(java.time.LocalTime);
+  }
+
+  public final class MonthDayKt {
+    ctor public MonthDayKt();
+    method @RequiresApi(26) deprecated public static operator java.time.Month component1(java.time.MonthDay);
+    method @RequiresApi(26) deprecated public static operator int component2(java.time.MonthDay);
+  }
+
+  public final class MonthKt {
+    ctor public MonthKt();
+    method @RequiresApi(26) deprecated public static int asInt(java.time.Month);
+    method @RequiresApi(26) deprecated public static java.time.Month asMonth(int);
+  }
+
+  public final class OffsetDateTimeKt {
+    ctor public OffsetDateTimeKt();
+    method @RequiresApi(26) deprecated public static operator java.time.LocalDateTime component1(java.time.OffsetDateTime);
+    method @RequiresApi(26) deprecated public static operator java.time.ZoneOffset component2(java.time.OffsetDateTime);
+  }
+
+  public final class OffsetTimeKt {
+    ctor public OffsetTimeKt();
+    method @RequiresApi(26) deprecated public static operator java.time.LocalTime component1(java.time.OffsetTime);
+    method @RequiresApi(26) deprecated public static operator java.time.ZoneOffset component2(java.time.OffsetTime);
+  }
+
+  public final class PeriodKt {
+    ctor public PeriodKt();
+    method @RequiresApi(26) deprecated public static operator int component1(java.time.Period);
+    method @RequiresApi(26) deprecated public static operator int component2(java.time.Period);
+    method @RequiresApi(26) deprecated public static operator int component3(java.time.Period);
+    method @RequiresApi(26) deprecated public static java.time.Period days(int);
+    method @RequiresApi(26) deprecated public static java.time.Period months(int);
+    method @RequiresApi(26) deprecated public static operator java.time.Period times(java.time.Period, int multiplicand);
+    method @RequiresApi(26) deprecated public static operator java.time.Period unaryMinus(java.time.Period);
+    method @RequiresApi(26) deprecated public static java.time.Period years(int);
+  }
+
+  public final class YearKt {
+    ctor public YearKt();
+    method @RequiresApi(26) deprecated public static int asInt(java.time.Year);
+    method @RequiresApi(26) deprecated public static java.time.Year asYear(int);
+  }
+
+  public final class YearMonthKt {
+    ctor public YearMonthKt();
+    method @RequiresApi(26) deprecated public static operator int component1(java.time.YearMonth);
+    method @RequiresApi(26) deprecated public static operator java.time.Month component2(java.time.YearMonth);
+  }
+
+  public final class ZonedDateTimeKt {
+    ctor public ZonedDateTimeKt();
+    method @RequiresApi(26) deprecated public static operator java.time.LocalDateTime component1(java.time.ZonedDateTime);
+    method @RequiresApi(26) deprecated public static operator java.time.ZoneId component2(java.time.ZonedDateTime);
+  }
+
+}
+
+package androidx.transition {
+
+  public final class TransitionKt {
+    ctor public TransitionKt();
+    method @RequiresApi(19) public static void addListener(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit>? onEnd = "null", kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit>? onStart = "null", kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit>? onCancel = "null", kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit>? onResume = "null", kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit>? onPause = "null");
+    method @RequiresApi(19) public static void doOnCancel(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static void doOnEnd(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static void doOnPause(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static void doOnResume(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static void doOnStart(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+  }
+
+}
+
+package androidx.util {
+
+  public final class ArrayMapKt {
+    ctor public ArrayMapKt();
+    method @RequiresApi(19) public static <K, V> android.util.ArrayMap<K,V> arrayMapOf();
+    method @RequiresApi(19) public static <K, V> android.util.ArrayMap<K,V> arrayMapOf(kotlin.Pair<? extends K,? extends V>... pairs);
+  }
+
+  public final class ArraySetKt {
+    ctor public ArraySetKt();
+    method @RequiresApi(23) public static <T> android.util.ArraySet<T> arraySetOf();
+    method @RequiresApi(23) public static <T> android.util.ArraySet<T> arraySetOf(T... values);
+  }
+
+  public final class AtomicFileKt {
+    ctor public AtomicFileKt();
+    method @RequiresApi(17) public static byte[] readBytes(android.util.AtomicFile);
+    method @RequiresApi(17) public static String readText(android.util.AtomicFile, java.nio.charset.Charset charset = "Charsets.UTF_8");
+    method @RequiresApi(17) public static void tryWrite(android.util.AtomicFile, kotlin.jvm.functions.Function1<? super java.io.FileOutputStream,kotlin.Unit> block);
+    method @RequiresApi(17) public static void writeBytes(android.util.AtomicFile, byte[] array);
+    method @RequiresApi(17) public static void writeText(android.util.AtomicFile, String text, java.nio.charset.Charset charset = "Charsets.UTF_8");
+  }
+
+  public final class HalfKt {
+    ctor public HalfKt();
+    method @RequiresApi(26) public static android.util.Half toHalf(short);
+    method @RequiresApi(26) public static android.util.Half toHalf(float);
+    method @RequiresApi(26) public static android.util.Half toHalf(double);
+    method @RequiresApi(26) public static android.util.Half toHalf(String);
+  }
+
+  public final class LocaleKt {
+    ctor public LocaleKt();
+    method @RequiresApi(17) public static int getLayoutDirection(java.util.Locale);
+  }
+
+  public final class LongSparseArrayKt {
+    ctor public LongSparseArrayKt();
+    method @RequiresApi(16) public static operator <T> boolean contains(android.util.LongSparseArray<T>, long key);
+    method @RequiresApi(16) public static <T> boolean containsKey(android.util.LongSparseArray<T>, long key);
+    method @RequiresApi(16) public static <T> boolean containsValue(android.util.LongSparseArray<T>, T! value);
+    method @RequiresApi(16) public static <T> void forEach(android.util.LongSparseArray<T>, kotlin.jvm.functions.Function2<? super Long,? super T,kotlin.Unit> action);
+    method @RequiresApi(16) public static <T> T! getOrDefault(android.util.LongSparseArray<T>, long key, T! defaultValue);
+    method @RequiresApi(16) public static <T> T! getOrElse(android.util.LongSparseArray<T>, long key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+    method @RequiresApi(16) public static <T> int getSize(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static <T> boolean isEmpty(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static <T> boolean isNotEmpty(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static <T> kotlin.collections.LongIterator keyIterator(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static operator <T> android.util.LongSparseArray<T> plus(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+    method @RequiresApi(16) public static <T> void putAll(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+    method @RequiresApi(16) public static <T> boolean remove(android.util.LongSparseArray<T>, long key, T! value);
+    method @RequiresApi(16) public static operator <T> void set(android.util.LongSparseArray<T>, long key, T! value);
+    method @RequiresApi(16) public static <T> java.util.Iterator<T> valueIterator(android.util.LongSparseArray<T>);
+  }
+
+  public final class LruCacheKt {
+    ctor public LruCacheKt();
+    method public static <K, V> android.util.LruCache<K,V> lruCache(int maxSize, kotlin.jvm.functions.Function2<? super K,? super V,Integer> sizeOf = "{ _, _ -> 1 }", kotlin.jvm.functions.Function1<? super K,? extends V> create = "{ null as V? }", kotlin.jvm.functions.Function4<? super Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved = "{ _, _, _, _ -> }");
+  }
+
+  public final class PairKt {
+    ctor public PairKt();
+    method public static operator <F, S> F! component1(android.util.Pair<F,S>);
+    method public static operator <F, S> S! component2(android.util.Pair<F,S>);
+    method public static <F, S> android.util.Pair<F,S> toAndroidPair(kotlin.Pair<? extends F,? extends S>);
+    method public static <F, S> kotlin.Pair<F,S> toKotlinPair(android.util.Pair<F,S>);
+  }
+
+  public final class RangeKt {
+    ctor public RangeKt();
+    method @RequiresApi(21) public static infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> and(android.util.Range<T>, android.util.Range<T> other);
+    method @RequiresApi(21) public static operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, T value);
+    method @RequiresApi(21) public static operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, android.util.Range<T> other);
+    method @RequiresApi(21) public static infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> rangeTo(T, T that);
+    method @RequiresApi(21) public static <T extends java.lang.Comparable<? super T>> kotlin.ranges.ClosedRange<T> toClosedRange(android.util.Range<T>);
+    method @RequiresApi(21) public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> toRange(kotlin.ranges.ClosedRange<T>);
+  }
+
+  public final class SizeKt {
+    ctor public SizeKt();
+    method @RequiresApi(21) public static operator int component1(android.util.Size);
+    method @RequiresApi(21) public static operator float component1(android.util.SizeF);
+    method @RequiresApi(21) public static operator int component2(android.util.Size);
+    method @RequiresApi(21) public static operator float component2(android.util.SizeF);
+  }
+
+  public final class SparseArrayKt {
+    ctor public SparseArrayKt();
+    method public static operator <T> boolean contains(android.util.SparseArray<T>, int key);
+    method public static <T> boolean containsKey(android.util.SparseArray<T>, int key);
+    method public static <T> boolean containsValue(android.util.SparseArray<T>, T! value);
+    method public static <T> void forEach(android.util.SparseArray<T>, kotlin.jvm.functions.Function2<? super Integer,? super T,kotlin.Unit> action);
+    method public static <T> T! getOrDefault(android.util.SparseArray<T>, int key, T! defaultValue);
+    method public static <T> T! getOrElse(android.util.SparseArray<T>, int key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+    method public static <T> int getSize(android.util.SparseArray<T>);
+    method public static <T> boolean isEmpty(android.util.SparseArray<T>);
+    method public static <T> boolean isNotEmpty(android.util.SparseArray<T>);
+    method public static <T> kotlin.collections.IntIterator keyIterator(android.util.SparseArray<T>);
+    method public static operator <T> android.util.SparseArray<T> plus(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+    method public static <T> void putAll(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+    method public static <T> boolean remove(android.util.SparseArray<T>, int key, T! value);
+    method public static operator <T> void set(android.util.SparseArray<T>, int key, T! value);
+    method public static <T> java.util.Iterator<T> valueIterator(android.util.SparseArray<T>);
+  }
+
+  public final class SparseBooleanArrayKt {
+    ctor public SparseBooleanArrayKt();
+    method public static operator boolean contains(android.util.SparseBooleanArray, int key);
+    method public static boolean containsKey(android.util.SparseBooleanArray, int key);
+    method public static boolean containsValue(android.util.SparseBooleanArray, boolean value);
+    method public static void forEach(android.util.SparseBooleanArray, kotlin.jvm.functions.Function2<? super Integer,? super Boolean,kotlin.Unit> action);
+    method public static boolean getOrDefault(android.util.SparseBooleanArray, int key, boolean defaultValue);
+    method public static error.NonExistentClass getOrElse(android.util.SparseBooleanArray, int key, kotlin.jvm.functions.Function0<Boolean> defaultValue);
+    method public static int getSize(android.util.SparseBooleanArray);
+    method public static boolean isEmpty(android.util.SparseBooleanArray);
+    method public static boolean isNotEmpty(android.util.SparseBooleanArray);
+    method public static kotlin.collections.IntIterator keyIterator(android.util.SparseBooleanArray);
+    method public static operator android.util.SparseBooleanArray plus(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+    method public static void putAll(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+    method public static boolean remove(android.util.SparseBooleanArray, int key, boolean value);
+    method public static void removeAt(android.util.SparseBooleanArray, int index);
+    method public static operator void set(android.util.SparseBooleanArray, int key, boolean value);
+    method public static kotlin.collections.BooleanIterator valueIterator(android.util.SparseBooleanArray);
+  }
+
+  public final class SparseIntArrayKt {
+    ctor public SparseIntArrayKt();
+    method public static operator boolean contains(android.util.SparseIntArray, int key);
+    method public static boolean containsKey(android.util.SparseIntArray, int key);
+    method public static boolean containsValue(android.util.SparseIntArray, int value);
+    method public static void forEach(android.util.SparseIntArray, kotlin.jvm.functions.Function2<? super Integer,? super Integer,kotlin.Unit> action);
+    method public static int getOrDefault(android.util.SparseIntArray, int key, int defaultValue);
+    method public static error.NonExistentClass getOrElse(android.util.SparseIntArray, int key, kotlin.jvm.functions.Function0<Integer> defaultValue);
+    method public static int getSize(android.util.SparseIntArray);
+    method public static boolean isEmpty(android.util.SparseIntArray);
+    method public static boolean isNotEmpty(android.util.SparseIntArray);
+    method public static kotlin.collections.IntIterator keyIterator(android.util.SparseIntArray);
+    method public static operator android.util.SparseIntArray plus(android.util.SparseIntArray, android.util.SparseIntArray other);
+    method public static void putAll(android.util.SparseIntArray, android.util.SparseIntArray other);
+    method public static boolean remove(android.util.SparseIntArray, int key, int value);
+    method public static operator void set(android.util.SparseIntArray, int key, int value);
+    method public static kotlin.collections.IntIterator valueIterator(android.util.SparseIntArray);
+  }
+
+  public final class SparseLongArrayKt {
+    ctor public SparseLongArrayKt();
+    method @RequiresApi(18) public static operator boolean contains(android.util.SparseLongArray, int key);
+    method @RequiresApi(18) public static boolean containsKey(android.util.SparseLongArray, int key);
+    method @RequiresApi(18) public static boolean containsValue(android.util.SparseLongArray, long value);
+    method @RequiresApi(18) public static void forEach(android.util.SparseLongArray, kotlin.jvm.functions.Function2<? super Integer,? super Long,kotlin.Unit> action);
+    method @RequiresApi(18) public static long getOrDefault(android.util.SparseLongArray, int key, long defaultValue);
+    method @RequiresApi(18) public static error.NonExistentClass getOrElse(android.util.SparseLongArray, int key, kotlin.jvm.functions.Function0<Long> defaultValue);
+    method @RequiresApi(18) public static int getSize(android.util.SparseLongArray);
+    method @RequiresApi(18) public static boolean isEmpty(android.util.SparseLongArray);
+    method @RequiresApi(18) public static boolean isNotEmpty(android.util.SparseLongArray);
+    method @RequiresApi(18) public static kotlin.collections.IntIterator keyIterator(android.util.SparseLongArray);
+    method @RequiresApi(18) public static operator android.util.SparseLongArray plus(android.util.SparseLongArray, android.util.SparseLongArray other);
+    method @RequiresApi(18) public static void putAll(android.util.SparseLongArray, android.util.SparseLongArray other);
+    method @RequiresApi(18) public static boolean remove(android.util.SparseLongArray, int key, long value);
+    method @RequiresApi(18) public static operator void set(android.util.SparseLongArray, int key, long value);
+    method @RequiresApi(18) public static kotlin.collections.LongIterator valueIterator(android.util.SparseLongArray);
+  }
+
+}
+
+package androidx.view {
+
+  public final class MenuKt {
+    ctor public MenuKt();
+    method public static operator boolean contains(android.view.Menu, android.view.MenuItem item);
+    method public static void forEach(android.view.Menu, kotlin.jvm.functions.Function1<? super android.view.MenuItem,kotlin.Unit> action);
+    method public static void forEachIndexed(android.view.Menu, kotlin.jvm.functions.Function2<? super Integer,? super android.view.MenuItem,kotlin.Unit> action);
+    method public static operator android.view.MenuItem get(android.view.Menu, int index);
+    method public static int getSize(android.view.Menu);
+    method public static boolean isEmpty(android.view.Menu);
+    method public static boolean isNotEmpty(android.view.Menu);
+    method public static operator java.util.Iterator<android.view.MenuItem> iterator(android.view.Menu);
+  }
+
+  public final class ViewGroupKt {
+    ctor public ViewGroupKt();
+    method public static operator boolean contains(android.view.ViewGroup, android.view.View view);
+    method public static void forEach(android.view.ViewGroup, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static void forEachIndexed(android.view.ViewGroup, kotlin.jvm.functions.Function2<? super Integer,? super android.view.View,kotlin.Unit> action);
+    method public static operator android.view.View get(android.view.ViewGroup, int index);
+    method public static kotlin.sequences.Sequence<android.view.View> getChildren(android.view.ViewGroup);
+    method public static int getSize(android.view.ViewGroup);
+    method public static boolean isEmpty(android.view.ViewGroup);
+    method public static boolean isNotEmpty(android.view.ViewGroup);
+    method public static operator java.util.Iterator<android.view.View> iterator(android.view.ViewGroup);
+    method public static operator void minusAssign(android.view.ViewGroup, android.view.View view);
+    method public static operator void plusAssign(android.view.ViewGroup, android.view.View view);
+    method public static void setMargins(android.view.ViewGroup.MarginLayoutParams, @Px int size);
+    method public static void updateLayoutParams(android.view.ViewGroup, kotlin.jvm.functions.Function1<? super android.view.ViewGroup.LayoutParams,kotlin.Unit> block);
+    method public static void updateMargins(android.view.ViewGroup.MarginLayoutParams, @Px int left = "leftMargin", @Px int top = "topMargin", @Px int right = "rightMargin", @Px int bottom = "bottomMargin");
+    method @RequiresApi(17) public static void updateMarginsRelative(android.view.ViewGroup.MarginLayoutParams, @Px int start = "marginStart", @Px int top = "topMargin", @Px int end = "marginEnd", @Px int bottom = "bottomMargin");
+  }
+
+  public final class ViewKt {
+    ctor public ViewKt();
+    method public static void doOnLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static void doOnNextLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static void doOnPreDraw(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static boolean isGone(android.view.View);
+    method public static boolean isInvisible(android.view.View);
+    method public static boolean isVisible(android.view.View);
+    method public static Runnable postDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method @RequiresApi(16) public static Runnable postOnAnimationDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method public static void setGone(android.view.View, boolean value);
+    method public static void setInvisible(android.view.View, boolean value);
+    method public static void setPadding(android.view.View, @Px int size);
+    method public static void setVisible(android.view.View, boolean value);
+    method public static android.graphics.Bitmap toBitmap(android.view.View, android.graphics.Bitmap.Config config = "Bitmap.Config.ARGB_8888");
+    method public static void updatePadding(android.view.View, @Px int left = "paddingLeft", @Px int top = "paddingTop", @Px int right = "paddingRight", @Px int bottom = "paddingBottom");
+    method @RequiresApi(17) public static void updatePaddingRelative(android.view.View, @Px int start = "paddingStart", @Px int top = "paddingTop", @Px int end = "paddingEnd", @Px int bottom = "paddingBottom");
+  }
+
+}
+
diff --git a/core/ktx/api/current.txt b/core/ktx/api/current.txt
new file mode 100644
index 0000000..4c56ac9
--- /dev/null
+++ b/core/ktx/api/current.txt
@@ -0,0 +1,658 @@
+package androidx.core.animation {
+
+  public final class AnimatorKt {
+    ctor public AnimatorKt();
+    method public static android.animation.Animator.AnimatorListener addListener(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onEnd = "null", kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onStart = "null", kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onCancel = "null", kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onRepeat = "null");
+    method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener addPauseListener(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onResume = "null", kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit>? onPause = "null");
+    method public static android.animation.Animator.AnimatorListener doOnCancel(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static android.animation.Animator.AnimatorListener doOnEnd(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener doOnPause(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static android.animation.Animator.AnimatorListener doOnRepeat(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method @RequiresApi(19) public static android.animation.Animator.AnimatorPauseListener doOnResume(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static android.animation.Animator.AnimatorListener doOnStart(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+  }
+
+}
+
+package androidx.core.content {
+
+  public final class ContentValuesKt {
+    ctor public ContentValuesKt();
+    method public static error.NonExistentClass contentValuesOf(kotlin.Pair<java.lang.String,?>... pairs);
+  }
+
+  public final class ContextKt {
+    ctor public ContextKt();
+    method public static void withStyledAttributes(android.content.Context, android.util.AttributeSet? set = "null", int[] attrs, @AttrRes int defStyleAttr = "0", @StyleRes int defStyleRes = "0", kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+    method public static void withStyledAttributes(android.content.Context, @StyleRes int resourceId, int[] attrs, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+  }
+
+  public final class SharedPreferencesKt {
+    ctor public SharedPreferencesKt();
+    method public static void edit(android.content.SharedPreferences, boolean commit = "false", kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action);
+  }
+
+}
+
+package androidx.core.content.res {
+
+  public final class TypedArrayKt {
+    ctor public TypedArrayKt();
+    method public static boolean getBooleanOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method @ColorInt public static int getColorOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static android.content.res.ColorStateList getColorStateListOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static float getDimensionOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method @Dimension public static int getDimensionPixelOffsetOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method @Dimension public static int getDimensionPixelSizeOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static android.graphics.drawable.Drawable getDrawableOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static float getFloatOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method @RequiresApi(26) public static android.graphics.Typeface getFontOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static int getIntOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static int getIntegerOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method @AnyRes public static int getResourceIdOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static String getStringOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static CharSequence[] getTextArrayOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static CharSequence getTextOrThrow(android.content.res.TypedArray, @StyleableRes int index);
+    method public static <R> R! use(android.content.res.TypedArray, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,? extends R> block);
+  }
+
+}
+
+package androidx.core.database {
+
+  public final class CursorKt {
+    ctor public CursorKt();
+    method public static byte[] getBlob(android.database.Cursor, String columnName);
+    method public static byte[]? getBlobOrNull(android.database.Cursor, int index);
+    method public static error.NonExistentClass getBlobOrNull(android.database.Cursor, String columnName);
+    method public static double getDouble(android.database.Cursor, String columnName);
+    method public static Double? getDoubleOrNull(android.database.Cursor, int index);
+    method public static error.NonExistentClass getDoubleOrNull(android.database.Cursor, String columnName);
+    method public static float getFloat(android.database.Cursor, String columnName);
+    method public static Float? getFloatOrNull(android.database.Cursor, int index);
+    method public static error.NonExistentClass getFloatOrNull(android.database.Cursor, String columnName);
+    method public static int getInt(android.database.Cursor, String columnName);
+    method public static Integer? getIntOrNull(android.database.Cursor, int index);
+    method public static error.NonExistentClass getIntOrNull(android.database.Cursor, String columnName);
+    method public static long getLong(android.database.Cursor, String columnName);
+    method public static Long? getLongOrNull(android.database.Cursor, int index);
+    method public static error.NonExistentClass getLongOrNull(android.database.Cursor, String columnName);
+    method public static short getShort(android.database.Cursor, String columnName);
+    method public static Short? getShortOrNull(android.database.Cursor, int index);
+    method public static error.NonExistentClass getShortOrNull(android.database.Cursor, String columnName);
+    method public static String getString(android.database.Cursor, String columnName);
+    method public static String? getStringOrNull(android.database.Cursor, int index);
+    method public static error.NonExistentClass getStringOrNull(android.database.Cursor, String columnName);
+  }
+
+}
+
+package androidx.core.database.sqlite {
+
+  public final class SQLiteDatabaseKt {
+    ctor public SQLiteDatabaseKt();
+    method public static <T> T! transaction(android.database.sqlite.SQLiteDatabase, boolean exclusive = "true", kotlin.jvm.functions.Function1<? super android.database.sqlite.SQLiteDatabase,? extends T> body);
+  }
+
+}
+
+package androidx.core.graphics {
+
+  public final class BitmapKt {
+    ctor public BitmapKt();
+    method public static android.graphics.Bitmap applyCanvas(android.graphics.Bitmap, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static android.graphics.Bitmap createBitmap(int width, int height, android.graphics.Bitmap.Config config = "Bitmap.Config.ARGB_8888");
+    method @RequiresApi(26) public static android.graphics.Bitmap createBitmap(int width, int height, android.graphics.Bitmap.Config config = "Bitmap.Config.ARGB_8888", boolean hasAlpha = "true", android.graphics.ColorSpace colorSpace = "ColorSpace.get(ColorSpace.Named.SRGB)");
+    method public static operator int get(android.graphics.Bitmap, int x, int y);
+    method public static android.graphics.Bitmap scale(android.graphics.Bitmap, int width, int height, boolean filter = "true");
+    method public static operator void set(android.graphics.Bitmap, int x, int y, @ColorInt int color);
+  }
+
+  public final class CanvasKt {
+    ctor public CanvasKt();
+    method public static void withMatrix(android.graphics.Canvas, android.graphics.Matrix matrix = "Matrix()", kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static void withRotation(android.graphics.Canvas, float degrees = "0.0f", float pivotX = "0.0f", float pivotY = "0.0f", kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static void withSave(android.graphics.Canvas, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static void withScale(android.graphics.Canvas, float x = "1.0f", float y = "1.0f", float pivotX = "0.0f", float pivotY = "0.0f", kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static void withSkew(android.graphics.Canvas, float x = "0.0f", float y = "0.0f", kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static void withTranslation(android.graphics.Canvas, float x = "0.0f", float y = "0.0f", kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+  }
+
+  public final class ColorKt {
+    ctor public ColorKt();
+    method @RequiresApi(26) public static operator float component1(android.graphics.Color);
+    method public static operator int component1(int);
+    method @RequiresApi(26) public static operator float component1(long);
+    method @RequiresApi(26) public static operator float component2(android.graphics.Color);
+    method public static operator int component2(int);
+    method @RequiresApi(26) public static operator float component2(long);
+    method @RequiresApi(26) public static operator float component3(android.graphics.Color);
+    method public static operator int component3(int);
+    method @RequiresApi(26) public static operator float component3(long);
+    method @RequiresApi(26) public static operator float component4(android.graphics.Color);
+    method public static operator int component4(int);
+    method @RequiresApi(26) public static operator float component4(long);
+    method public static int getAlpha(int);
+    method @RequiresApi(26) public static float getAlpha(long);
+    method public static int getBlue(int);
+    method @RequiresApi(26) public static float getBlue(long);
+    method @RequiresApi(26) public static android.graphics.ColorSpace getColorSpace(long);
+    method public static int getGreen(int);
+    method @RequiresApi(26) public static float getGreen(long);
+    method @RequiresApi(26) public static float getLuminance(int);
+    method @RequiresApi(26) public static float getLuminance(long);
+    method public static int getRed(int);
+    method @RequiresApi(26) public static float getRed(long);
+    method @RequiresApi(26) public static boolean isSrgb(long);
+    method @RequiresApi(26) public static boolean isWideGamut(long);
+    method @RequiresApi(26) public static operator android.graphics.Color plus(android.graphics.Color, android.graphics.Color c);
+    method @RequiresApi(26) public static android.graphics.Color toColor(int);
+    method @RequiresApi(26) public static android.graphics.Color toColor(long);
+    method @RequiresApi(26) @ColorInt public static int toColorInt(long);
+    method @ColorInt public static int toColorInt(String);
+    method @RequiresApi(26) @ColorLong public static long toColorLong(int);
+  }
+
+  public final class MatrixKt {
+    ctor public MatrixKt();
+    method public static error.NonExistentClass rotationMatrix(float degrees, float px = "0.0f", float py = "0.0f");
+    method public static error.NonExistentClass scaleMatrix(float sx = "1.0f", float sy = "1.0f");
+    method public static operator error.NonExistentClass times(android.graphics.Matrix, android.graphics.Matrix m);
+    method public static error.NonExistentClass translationMatrix(float tx = "0.0f", float ty = "0.0f");
+    method public static error.NonExistentClass values(android.graphics.Matrix);
+  }
+
+  public final class PathKt {
+    ctor public PathKt();
+    method @RequiresApi(19) public static infix android.graphics.Path and(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(26) public static Iterable<androidx.core.graphics.PathSegment> flatten(android.graphics.Path, float error = "0.5f");
+    method @RequiresApi(19) public static operator android.graphics.Path minus(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static infix android.graphics.Path or(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static operator android.graphics.Path plus(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static infix android.graphics.Path xor(android.graphics.Path, android.graphics.Path p);
+  }
+
+  public final class PathSegment {
+    ctor public PathSegment(android.graphics.PointF start, float startFraction, android.graphics.PointF end, float endFraction);
+    method public android.graphics.PointF component1();
+    method public float component2();
+    method public android.graphics.PointF component3();
+    method public float component4();
+    method public androidx.core.graphics.PathSegment copy(android.graphics.PointF start, float startFraction, android.graphics.PointF end, float endFraction);
+    method public android.graphics.PointF getEnd();
+    method public float getEndFraction();
+    method public android.graphics.PointF getStart();
+    method public float getStartFraction();
+  }
+
+  public final class PictureKt {
+    ctor public PictureKt();
+    method public static android.graphics.Picture record(android.graphics.Picture, int width, int height, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+  }
+
+  public final class PointKt {
+    ctor public PointKt();
+    method public static operator int component1(android.graphics.Point);
+    method public static operator float component1(android.graphics.PointF);
+    method public static operator int component2(android.graphics.Point);
+    method public static operator float component2(android.graphics.PointF);
+    method public static operator android.graphics.Point minus(android.graphics.Point, android.graphics.Point p);
+    method public static operator android.graphics.PointF minus(android.graphics.PointF, android.graphics.PointF p);
+    method public static operator android.graphics.Point minus(android.graphics.Point, int xy);
+    method public static operator android.graphics.PointF minus(android.graphics.PointF, float xy);
+    method public static operator android.graphics.Point plus(android.graphics.Point, android.graphics.Point p);
+    method public static operator android.graphics.PointF plus(android.graphics.PointF, android.graphics.PointF p);
+    method public static operator android.graphics.Point plus(android.graphics.Point, int xy);
+    method public static operator android.graphics.PointF plus(android.graphics.PointF, float xy);
+    method public static android.graphics.Point toPoint(android.graphics.PointF);
+    method public static android.graphics.PointF toPointF(android.graphics.Point);
+    method public static operator android.graphics.Point unaryMinus(android.graphics.Point);
+    method public static operator android.graphics.PointF unaryMinus(android.graphics.PointF);
+  }
+
+  public final class PorterDuffKt {
+    ctor public PorterDuffKt();
+    method public static android.graphics.PorterDuffColorFilter toColorFilter(android.graphics.PorterDuff.Mode, int color);
+    method public static android.graphics.PorterDuffXfermode toXfermode(android.graphics.PorterDuff.Mode);
+  }
+
+  public final class RectKt {
+    ctor public RectKt();
+    method public static infix android.graphics.Rect and(android.graphics.Rect, android.graphics.Rect r);
+    method public static infix android.graphics.RectF and(android.graphics.RectF, android.graphics.RectF r);
+    method public static operator int component1(android.graphics.Rect);
+    method public static operator float component1(android.graphics.RectF);
+    method public static operator int component2(android.graphics.Rect);
+    method public static operator float component2(android.graphics.RectF);
+    method public static operator int component3(android.graphics.Rect);
+    method public static operator float component3(android.graphics.RectF);
+    method public static operator int component4(android.graphics.Rect);
+    method public static operator float component4(android.graphics.RectF);
+    method public static operator boolean contains(android.graphics.Rect, android.graphics.Point p);
+    method public static operator boolean contains(android.graphics.RectF, android.graphics.PointF p);
+    method public static operator android.graphics.Region minus(android.graphics.Rect, android.graphics.Rect r);
+    method public static operator android.graphics.Region minus(android.graphics.RectF, android.graphics.RectF r);
+    method public static operator android.graphics.Rect minus(android.graphics.Rect, int xy);
+    method public static operator android.graphics.RectF minus(android.graphics.RectF, float xy);
+    method public static operator android.graphics.Rect minus(android.graphics.Rect, android.graphics.Point xy);
+    method public static operator android.graphics.RectF minus(android.graphics.RectF, android.graphics.PointF xy);
+    method public static infix android.graphics.Rect or(android.graphics.Rect, android.graphics.Rect r);
+    method public static infix android.graphics.RectF or(android.graphics.RectF, android.graphics.RectF r);
+    method public static operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Rect r);
+    method public static operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.RectF r);
+    method public static operator android.graphics.Rect plus(android.graphics.Rect, int xy);
+    method public static operator android.graphics.RectF plus(android.graphics.RectF, float xy);
+    method public static operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Point xy);
+    method public static operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.PointF xy);
+    method public static android.graphics.Rect toRect(android.graphics.RectF);
+    method public static android.graphics.RectF toRectF(android.graphics.Rect);
+    method public static android.graphics.Region toRegion(android.graphics.Rect);
+    method public static android.graphics.Region toRegion(android.graphics.RectF);
+    method public static error.NonExistentClass transform(android.graphics.RectF, android.graphics.Matrix m);
+    method public static infix android.graphics.Region xor(android.graphics.Rect, android.graphics.Rect r);
+    method public static infix android.graphics.Region xor(android.graphics.RectF, android.graphics.RectF r);
+  }
+
+  public final class RegionKt {
+    ctor public RegionKt();
+    method public static infix android.graphics.Region and(android.graphics.Region, android.graphics.Rect r);
+    method public static infix android.graphics.Region and(android.graphics.Region, android.graphics.Region r);
+    method public static operator boolean contains(android.graphics.Region, android.graphics.Point p);
+    method public static void forEach(android.graphics.Region, kotlin.jvm.functions.Function1<? super android.graphics.Rect,kotlin.Unit> action);
+    method public static operator java.util.Iterator<android.graphics.Rect> iterator(android.graphics.Region);
+    method public static operator android.graphics.Region minus(android.graphics.Region, android.graphics.Rect r);
+    method public static operator android.graphics.Region minus(android.graphics.Region, android.graphics.Region r);
+    method public static operator android.graphics.Region not(android.graphics.Region);
+    method public static infix android.graphics.Region or(android.graphics.Region, android.graphics.Rect r);
+    method public static infix android.graphics.Region or(android.graphics.Region, android.graphics.Region r);
+    method public static operator android.graphics.Region plus(android.graphics.Region, android.graphics.Rect r);
+    method public static operator android.graphics.Region plus(android.graphics.Region, android.graphics.Region r);
+    method public static operator android.graphics.Region unaryMinus(android.graphics.Region);
+    method public static infix android.graphics.Region xor(android.graphics.Region, android.graphics.Rect r);
+    method public static infix android.graphics.Region xor(android.graphics.Region, android.graphics.Region r);
+  }
+
+  public final class ShaderKt {
+    ctor public ShaderKt();
+    method public static void transform(android.graphics.Shader, kotlin.jvm.functions.Function1<? super android.graphics.Matrix,kotlin.Unit> block);
+  }
+
+}
+
+package androidx.core.graphics.drawable {
+
+  public final class BitmapDrawableKt {
+    ctor public BitmapDrawableKt();
+    method public static android.graphics.drawable.BitmapDrawable toDrawable(android.graphics.Bitmap, android.content.res.Resources resources);
+  }
+
+  public final class ColorDrawableKt {
+    ctor public ColorDrawableKt();
+    method public static android.graphics.drawable.ColorDrawable toDrawable(int);
+    method @RequiresApi(26) public static android.graphics.drawable.ColorDrawable toDrawable(android.graphics.Color);
+  }
+
+  public final class DrawableKt {
+    ctor public DrawableKt();
+    method public static android.graphics.Bitmap toBitmap(android.graphics.drawable.Drawable, @Px int width = "intrinsicWidth", @Px int height = "intrinsicHeight", android.graphics.Bitmap.Config? config = "null");
+    method public static void updateBounds(android.graphics.drawable.Drawable, @Px int left = "bounds.left", @Px int top = "bounds.top", @Px int right = "bounds.right", @Px int bottom = "bounds.bottom");
+  }
+
+  public final class IconKt {
+    ctor public IconKt();
+    method @RequiresApi(26) public static android.graphics.drawable.Icon toAdaptiveIcon(android.graphics.Bitmap);
+    method @RequiresApi(26) public static android.graphics.drawable.Icon toIcon(android.graphics.Bitmap);
+    method @RequiresApi(26) public static android.graphics.drawable.Icon toIcon(android.net.Uri);
+    method @RequiresApi(26) public static android.graphics.drawable.Icon toIcon(byte[]);
+  }
+
+}
+
+package androidx.core.net {
+
+  public final class UriKt {
+    ctor public UriKt();
+    method public static java.io.File toFile(android.net.Uri);
+    method public static android.net.Uri toUri(String);
+    method public static android.net.Uri toUri(java.io.File);
+  }
+
+}
+
+package androidx.core.os {
+
+  public final class BundleKt {
+    ctor public BundleKt();
+    method public static error.NonExistentClass bundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+  }
+
+  public final class HandlerKt {
+    ctor public HandlerKt();
+    method public static Runnable postAtTime(android.os.Handler, long uptimeMillis, Object? token = "null", kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method public static Runnable postDelayed(android.os.Handler, long delayInMillis, Object? token = "null", kotlin.jvm.functions.Function0<kotlin.Unit> action);
+  }
+
+  public final class PersistableBundleKt {
+    ctor public PersistableBundleKt();
+    method @RequiresApi(21) public static error.NonExistentClass persistableBundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+  }
+
+  public final class TraceKt {
+    ctor public TraceKt();
+    method public static <T> T! trace(String sectionName, kotlin.jvm.functions.Function0<? extends T> block);
+  }
+
+}
+
+package androidx.core.preference {
+
+  public final class PreferenceGroupKt {
+    ctor public PreferenceGroupKt();
+    method public static operator boolean contains(android.preference.PreferenceGroup, android.preference.Preference preference);
+    method public static void forEach(android.preference.PreferenceGroup, kotlin.jvm.functions.Function1<? super android.preference.Preference,kotlin.Unit> action);
+    method public static void forEachIndexed(android.preference.PreferenceGroup, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.preference.Preference,kotlin.Unit> action);
+    method public static operator android.preference.Preference get(android.preference.PreferenceGroup, CharSequence key);
+    method public static operator android.preference.Preference get(android.preference.PreferenceGroup, int index);
+    method public static int getSize(android.preference.PreferenceGroup);
+    method public static boolean isEmpty(android.preference.PreferenceGroup);
+    method public static boolean isNotEmpty(android.preference.PreferenceGroup);
+    method public static operator java.util.Iterator<android.preference.Preference> iterator(android.preference.PreferenceGroup);
+    method public static operator void minusAssign(android.preference.PreferenceGroup, android.preference.Preference preference);
+    method public static operator void plusAssign(android.preference.PreferenceGroup, android.preference.Preference preference);
+  }
+
+}
+
+package androidx.core.text {
+
+  public final class CharSequenceKt {
+    ctor public CharSequenceKt();
+    method public static boolean isDigitsOnly(CharSequence);
+    method public static int trimmedLength(CharSequence);
+  }
+
+  public final class HtmlKt {
+    ctor public HtmlKt();
+    method public static android.text.Spanned parseAsHtml(String, int flags = "FROM_HTML_MODE_LEGACY", android.text.Html.ImageGetter? imageGetter = "null", android.text.Html.TagHandler? tagHandler = "null");
+    method public static String toHtml(android.text.Spanned, int option = "TO_HTML_PARAGRAPH_LINES_CONSECUTIVE");
+  }
+
+  public final class SpannableStringBuilderKt {
+    ctor public SpannableStringBuilderKt();
+    method public static android.text.SpannableStringBuilder backgroundColor(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder bold(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannedString buildSpannedString(kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder color(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object[] spans, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object span, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder italic(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder scale(android.text.SpannableStringBuilder, float proportion, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder strikeThrough(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static android.text.SpannableStringBuilder underline(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+  }
+
+  public final class SpannableStringKt {
+    ctor public SpannableStringKt();
+    method public static error.NonExistentClass clearSpans(android.text.Spannable);
+    method public static operator void minusAssign(android.text.Spannable, Object span);
+    method public static operator void plusAssign(android.text.Spannable, Object span);
+    method public static operator void set(android.text.Spannable, int start, int end, Object span);
+    method public static operator void set(android.text.Spannable, kotlin.ranges.IntRange range, Object span);
+    method public static android.text.Spannable toSpannable(CharSequence);
+  }
+
+  public final class SpannedStringKt {
+    ctor public SpannedStringKt();
+    method public static android.text.Spanned toSpanned(CharSequence);
+  }
+
+  public final class StringKt {
+    ctor public StringKt();
+    method public static String htmlEncode(String);
+  }
+
+}
+
+package androidx.core.transition {
+
+  public final class TransitionKt {
+    ctor public TransitionKt();
+    method @RequiresApi(19) public static void addListener(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit>? onEnd = "null", kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit>? onStart = "null", kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit>? onCancel = "null", kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit>? onResume = "null", kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit>? onPause = "null");
+    method @RequiresApi(19) public static void doOnCancel(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static void doOnEnd(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static void doOnPause(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static void doOnResume(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static void doOnStart(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+  }
+
+}
+
+package androidx.core.util {
+
+  public final class ArrayMapKt {
+    ctor public ArrayMapKt();
+    method @RequiresApi(19) public static <K, V> android.util.ArrayMap<K,V> arrayMapOf();
+    method @RequiresApi(19) public static <K, V> android.util.ArrayMap<K,V> arrayMapOf(kotlin.Pair<? extends K,? extends V>... pairs);
+  }
+
+  public final class ArraySetKt {
+    ctor public ArraySetKt();
+    method @RequiresApi(23) public static <T> android.util.ArraySet<T> arraySetOf();
+    method @RequiresApi(23) public static <T> android.util.ArraySet<T> arraySetOf(T... values);
+  }
+
+  public final class AtomicFileKt {
+    ctor public AtomicFileKt();
+    method @RequiresApi(17) public static byte[] readBytes(android.util.AtomicFile);
+    method @RequiresApi(17) public static String readText(android.util.AtomicFile, java.nio.charset.Charset charset = "Charsets.UTF_8");
+    method @RequiresApi(17) public static void tryWrite(android.util.AtomicFile, kotlin.jvm.functions.Function1<? super java.io.FileOutputStream,kotlin.Unit> block);
+    method @RequiresApi(17) public static void writeBytes(android.util.AtomicFile, byte[] array);
+    method @RequiresApi(17) public static void writeText(android.util.AtomicFile, String text, java.nio.charset.Charset charset = "Charsets.UTF_8");
+  }
+
+  public final class HalfKt {
+    ctor public HalfKt();
+    method @RequiresApi(26) public static android.util.Half toHalf(short);
+    method @RequiresApi(26) public static android.util.Half toHalf(float);
+    method @RequiresApi(26) public static android.util.Half toHalf(double);
+    method @RequiresApi(26) public static android.util.Half toHalf(String);
+  }
+
+  public final class LocaleKt {
+    ctor public LocaleKt();
+    method @RequiresApi(17) public static int getLayoutDirection(java.util.Locale);
+  }
+
+  public final class LongSparseArrayKt {
+    ctor public LongSparseArrayKt();
+    method @RequiresApi(16) public static operator <T> boolean contains(android.util.LongSparseArray<T>, long key);
+    method @RequiresApi(16) public static <T> boolean containsKey(android.util.LongSparseArray<T>, long key);
+    method @RequiresApi(16) public static <T> boolean containsValue(android.util.LongSparseArray<T>, T! value);
+    method @RequiresApi(16) public static <T> void forEach(android.util.LongSparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Long,? super T,kotlin.Unit> action);
+    method @RequiresApi(16) public static <T> T! getOrDefault(android.util.LongSparseArray<T>, long key, T! defaultValue);
+    method @RequiresApi(16) public static <T> T! getOrElse(android.util.LongSparseArray<T>, long key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+    method @RequiresApi(16) public static <T> int getSize(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static <T> boolean isEmpty(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static <T> boolean isNotEmpty(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static <T> kotlin.collections.LongIterator keyIterator(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static operator <T> android.util.LongSparseArray<T> plus(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+    method @RequiresApi(16) public static <T> void putAll(android.util.LongSparseArray<T>, android.util.LongSparseArray<T> other);
+    method @RequiresApi(16) public static <T> boolean remove(android.util.LongSparseArray<T>, long key, T! value);
+    method @RequiresApi(16) public static operator <T> void set(android.util.LongSparseArray<T>, long key, T! value);
+    method @RequiresApi(16) public static <T> java.util.Iterator<T> valueIterator(android.util.LongSparseArray<T>);
+  }
+
+  public final class LruCacheKt {
+    ctor public LruCacheKt();
+    method public static <K, V> android.util.LruCache<K,V> lruCache(int maxSize, kotlin.jvm.functions.Function2<? super K,? super V,java.lang.Integer> sizeOf = "{ _, _ -> 1 }", kotlin.jvm.functions.Function1<? super K,? extends V> create = "{ null as V? }", kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved = "{ _, _, _, _ -> }");
+  }
+
+  public final class PairKt {
+    ctor public PairKt();
+    method public static operator <F, S> F! component1(android.util.Pair<F,S>);
+    method public static operator <F, S> S! component2(android.util.Pair<F,S>);
+    method public static <F, S> android.util.Pair<F,S> toAndroidPair(kotlin.Pair<? extends F,? extends S>);
+    method public static <F, S> kotlin.Pair<F,S> toKotlinPair(android.util.Pair<F,S>);
+  }
+
+  public final class RangeKt {
+    ctor public RangeKt();
+    method @RequiresApi(21) public static infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> and(android.util.Range<T>, android.util.Range<T> other);
+    method @RequiresApi(21) public static operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, T value);
+    method @RequiresApi(21) public static operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, android.util.Range<T> other);
+    method @RequiresApi(21) public static infix <T extends java.lang.Comparable<? super T>> android.util.Range<T> rangeTo(T, T that);
+    method @RequiresApi(21) public static <T extends java.lang.Comparable<? super T>> kotlin.ranges.ClosedRange<T> toClosedRange(android.util.Range<T>);
+    method @RequiresApi(21) public static <T extends java.lang.Comparable<? super T>> android.util.Range<T> toRange(kotlin.ranges.ClosedRange<T>);
+  }
+
+  public final class SizeKt {
+    ctor public SizeKt();
+    method @RequiresApi(21) public static operator int component1(android.util.Size);
+    method @RequiresApi(21) public static operator float component1(android.util.SizeF);
+    method @RequiresApi(21) public static operator int component2(android.util.Size);
+    method @RequiresApi(21) public static operator float component2(android.util.SizeF);
+  }
+
+  public final class SparseArrayKt {
+    ctor public SparseArrayKt();
+    method public static operator <T> boolean contains(android.util.SparseArray<T>, int key);
+    method public static <T> boolean containsKey(android.util.SparseArray<T>, int key);
+    method public static <T> boolean containsValue(android.util.SparseArray<T>, T! value);
+    method public static <T> void forEach(android.util.SparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,kotlin.Unit> action);
+    method public static <T> T! getOrDefault(android.util.SparseArray<T>, int key, T! defaultValue);
+    method public static <T> T! getOrElse(android.util.SparseArray<T>, int key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+    method public static <T> int getSize(android.util.SparseArray<T>);
+    method public static <T> boolean isEmpty(android.util.SparseArray<T>);
+    method public static <T> boolean isNotEmpty(android.util.SparseArray<T>);
+    method public static <T> kotlin.collections.IntIterator keyIterator(android.util.SparseArray<T>);
+    method public static operator <T> android.util.SparseArray<T> plus(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+    method public static <T> void putAll(android.util.SparseArray<T>, android.util.SparseArray<T> other);
+    method public static <T> boolean remove(android.util.SparseArray<T>, int key, T! value);
+    method public static operator <T> void set(android.util.SparseArray<T>, int key, T! value);
+    method public static <T> java.util.Iterator<T> valueIterator(android.util.SparseArray<T>);
+  }
+
+  public final class SparseBooleanArrayKt {
+    ctor public SparseBooleanArrayKt();
+    method public static operator boolean contains(android.util.SparseBooleanArray, int key);
+    method public static boolean containsKey(android.util.SparseBooleanArray, int key);
+    method public static boolean containsValue(android.util.SparseBooleanArray, boolean value);
+    method public static void forEach(android.util.SparseBooleanArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Boolean,kotlin.Unit> action);
+    method public static boolean getOrDefault(android.util.SparseBooleanArray, int key, boolean defaultValue);
+    method public static error.NonExistentClass getOrElse(android.util.SparseBooleanArray, int key, kotlin.jvm.functions.Function0<java.lang.Boolean> defaultValue);
+    method public static int getSize(android.util.SparseBooleanArray);
+    method public static boolean isEmpty(android.util.SparseBooleanArray);
+    method public static boolean isNotEmpty(android.util.SparseBooleanArray);
+    method public static kotlin.collections.IntIterator keyIterator(android.util.SparseBooleanArray);
+    method public static operator android.util.SparseBooleanArray plus(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+    method public static void putAll(android.util.SparseBooleanArray, android.util.SparseBooleanArray other);
+    method public static boolean remove(android.util.SparseBooleanArray, int key, boolean value);
+    method public static operator void set(android.util.SparseBooleanArray, int key, boolean value);
+    method public static kotlin.collections.BooleanIterator valueIterator(android.util.SparseBooleanArray);
+  }
+
+  public final class SparseIntArrayKt {
+    ctor public SparseIntArrayKt();
+    method public static operator boolean contains(android.util.SparseIntArray, int key);
+    method public static boolean containsKey(android.util.SparseIntArray, int key);
+    method public static boolean containsValue(android.util.SparseIntArray, int value);
+    method public static void forEach(android.util.SparseIntArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+    method public static int getOrDefault(android.util.SparseIntArray, int key, int defaultValue);
+    method public static error.NonExistentClass getOrElse(android.util.SparseIntArray, int key, kotlin.jvm.functions.Function0<java.lang.Integer> defaultValue);
+    method public static int getSize(android.util.SparseIntArray);
+    method public static boolean isEmpty(android.util.SparseIntArray);
+    method public static boolean isNotEmpty(android.util.SparseIntArray);
+    method public static kotlin.collections.IntIterator keyIterator(android.util.SparseIntArray);
+    method public static operator android.util.SparseIntArray plus(android.util.SparseIntArray, android.util.SparseIntArray other);
+    method public static void putAll(android.util.SparseIntArray, android.util.SparseIntArray other);
+    method public static boolean remove(android.util.SparseIntArray, int key, int value);
+    method public static operator void set(android.util.SparseIntArray, int key, int value);
+    method public static kotlin.collections.IntIterator valueIterator(android.util.SparseIntArray);
+  }
+
+  public final class SparseLongArrayKt {
+    ctor public SparseLongArrayKt();
+    method @RequiresApi(18) public static operator boolean contains(android.util.SparseLongArray, int key);
+    method @RequiresApi(18) public static boolean containsKey(android.util.SparseLongArray, int key);
+    method @RequiresApi(18) public static boolean containsValue(android.util.SparseLongArray, long value);
+    method @RequiresApi(18) public static void forEach(android.util.SparseLongArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Long,kotlin.Unit> action);
+    method @RequiresApi(18) public static long getOrDefault(android.util.SparseLongArray, int key, long defaultValue);
+    method @RequiresApi(18) public static error.NonExistentClass getOrElse(android.util.SparseLongArray, int key, kotlin.jvm.functions.Function0<java.lang.Long> defaultValue);
+    method @RequiresApi(18) public static int getSize(android.util.SparseLongArray);
+    method @RequiresApi(18) public static boolean isEmpty(android.util.SparseLongArray);
+    method @RequiresApi(18) public static boolean isNotEmpty(android.util.SparseLongArray);
+    method @RequiresApi(18) public static kotlin.collections.IntIterator keyIterator(android.util.SparseLongArray);
+    method @RequiresApi(18) public static operator android.util.SparseLongArray plus(android.util.SparseLongArray, android.util.SparseLongArray other);
+    method @RequiresApi(18) public static void putAll(android.util.SparseLongArray, android.util.SparseLongArray other);
+    method @RequiresApi(18) public static boolean remove(android.util.SparseLongArray, int key, long value);
+    method @RequiresApi(18) public static operator void set(android.util.SparseLongArray, int key, long value);
+    method @RequiresApi(18) public static kotlin.collections.LongIterator valueIterator(android.util.SparseLongArray);
+  }
+
+}
+
+package androidx.core.view {
+
+  public final class MenuKt {
+    ctor public MenuKt();
+    method public static operator boolean contains(android.view.Menu, android.view.MenuItem item);
+    method public static void forEach(android.view.Menu, kotlin.jvm.functions.Function1<? super android.view.MenuItem,kotlin.Unit> action);
+    method public static void forEachIndexed(android.view.Menu, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.view.MenuItem,kotlin.Unit> action);
+    method public static operator android.view.MenuItem get(android.view.Menu, int index);
+    method public static int getSize(android.view.Menu);
+    method public static boolean isEmpty(android.view.Menu);
+    method public static boolean isNotEmpty(android.view.Menu);
+    method public static operator java.util.Iterator<android.view.MenuItem> iterator(android.view.Menu);
+  }
+
+  public final class ViewGroupKt {
+    ctor public ViewGroupKt();
+    method public static operator boolean contains(android.view.ViewGroup, android.view.View view);
+    method public static void forEach(android.view.ViewGroup, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static void forEachIndexed(android.view.ViewGroup, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.view.View,kotlin.Unit> action);
+    method public static operator android.view.View get(android.view.ViewGroup, int index);
+    method public static kotlin.sequences.Sequence<android.view.View> getChildren(android.view.ViewGroup);
+    method public static int getSize(android.view.ViewGroup);
+    method public static boolean isEmpty(android.view.ViewGroup);
+    method public static boolean isNotEmpty(android.view.ViewGroup);
+    method public static operator java.util.Iterator<android.view.View> iterator(android.view.ViewGroup);
+    method public static operator void minusAssign(android.view.ViewGroup, android.view.View view);
+    method public static operator void plusAssign(android.view.ViewGroup, android.view.View view);
+    method public static void setMargins(android.view.ViewGroup.MarginLayoutParams, @Px int size);
+    method public static void updateMargins(android.view.ViewGroup.MarginLayoutParams, @Px int left = "leftMargin", @Px int top = "topMargin", @Px int right = "rightMargin", @Px int bottom = "bottomMargin");
+    method @RequiresApi(17) public static void updateMarginsRelative(android.view.ViewGroup.MarginLayoutParams, @Px int start = "marginStart", @Px int top = "topMargin", @Px int end = "marginEnd", @Px int bottom = "bottomMargin");
+  }
+
+  public final class ViewKt {
+    ctor public ViewKt();
+    method @RequiresApi(16) public static void announceForAccessibility(android.view.View, @StringRes int resource);
+    method public static void doOnLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static void doOnNextLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static void doOnPreDraw(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static boolean isGone(android.view.View);
+    method public static boolean isInvisible(android.view.View);
+    method public static boolean isVisible(android.view.View);
+    method public static Runnable postDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method @RequiresApi(16) public static Runnable postOnAnimationDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method public static void setGone(android.view.View, boolean value);
+    method public static void setInvisible(android.view.View, boolean value);
+    method public static void setPadding(android.view.View, @Px int size);
+    method public static void setVisible(android.view.View, boolean value);
+    method public static android.graphics.Bitmap toBitmap(android.view.View, android.graphics.Bitmap.Config config = "Bitmap.Config.ARGB_8888");
+    method public static void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super android.view.ViewGroup.LayoutParams,kotlin.Unit> block);
+    method public static void updatePadding(android.view.View, @Px int left = "paddingLeft", @Px int top = "paddingTop", @Px int right = "paddingRight", @Px int bottom = "paddingBottom");
+    method @RequiresApi(17) public static void updatePaddingRelative(android.view.View, @Px int start = "paddingStart", @Px int top = "paddingTop", @Px int end = "paddingEnd", @Px int bottom = "paddingBottom");
+  }
+
+}
+
+package androidx.core.widget {
+
+  public final class ToastKt {
+    ctor public ToastKt();
+    method public static android.widget.Toast toast(android.content.Context, CharSequence text, int duration = "Toast.LENGTH_SHORT");
+    method public static android.widget.Toast toast(android.content.Context, @StringRes int resId, int duration = "Toast.LENGTH_SHORT");
+  }
+
+}
+
diff --git a/core/ktx/build.gradle b/core/ktx/build.gradle
new file mode 100644
index 0000000..bce0757
--- /dev/null
+++ b/core/ktx/build.gradle
@@ -0,0 +1,37 @@
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+    id("org.jetbrains.kotlin.android")
+}
+
+android {
+    buildTypes {
+        debug {
+            testCoverageEnabled = false // Breaks Kotlin compiler.
+        }
+    }
+}
+
+dependencies {
+    api(KOTLIN_STDLIB)
+    api(project(":annotation"))
+    api(project(":core"))
+
+    androidTestImplementation(JUNIT)
+    androidTestImplementation(TEST_RUNNER)
+    androidTestImplementation(TEST_RULES)
+    androidTestImplementation(TRUTH)
+    androidTestImplementation(project(":internal-testutils-ktx"))
+}
+
+supportLibrary {
+    name = "Core Kotlin Extensions"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.CORE
+    inceptionYear = "2018"
+    description = "Kotlin extensions for 'core' artifact"
+}
diff --git a/core/ktx/src/androidTest/AndroidManifest.xml b/core/ktx/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..259b616
--- /dev/null
+++ b/core/ktx/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,7 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="androidx.core.ktx.test">
+    <application>
+        <activity android:name="androidx.core.TestActivity"/>
+        <activity android:name="androidx.core.TestPreferenceActivity"/>
+    </application>
+</manifest>
diff --git a/core/ktx/src/androidTest/assets/red.png b/core/ktx/src/androidTest/assets/red.png
new file mode 100644
index 0000000..6292f4b
--- /dev/null
+++ b/core/ktx/src/androidTest/assets/red.png
Binary files differ
diff --git a/core/ktx/src/androidTest/font_licenses.txt b/core/ktx/src/androidTest/font_licenses.txt
new file mode 100644
index 0000000..0b83a9a
--- /dev/null
+++ b/core/ktx/src/androidTest/font_licenses.txt
@@ -0,0 +1,93 @@
+Copyright 2006 The Inconsolata Project Authors

+

+This Font Software is licensed under the SIL Open Font License, Version 1.1.

+This license is copied below, and is also available with a FAQ at:

+http://scripts.sil.org/OFL

+

+

+-----------------------------------------------------------

+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007

+-----------------------------------------------------------

+

+PREAMBLE

+The goals of the Open Font License (OFL) are to stimulate worldwide

+development of collaborative font projects, to support the font creation

+efforts of academic and linguistic communities, and to provide a free and

+open framework in which fonts may be shared and improved in partnership

+with others.

+

+The OFL allows the licensed fonts to be used, studied, modified and

+redistributed freely as long as they are not sold by themselves. The

+fonts, including any derivative works, can be bundled, embedded, 

+redistributed and/or sold with any software provided that any reserved

+names are not used by derivative works. The fonts and derivatives,

+however, cannot be released under any other type of license. The

+requirement for fonts to remain under this license does not apply

+to any document created using the fonts or their derivatives.

+

+DEFINITIONS

+"Font Software" refers to the set of files released by the Copyright

+Holder(s) under this license and clearly marked as such. This may

+include source files, build scripts and documentation.

+

+"Reserved Font Name" refers to any names specified as such after the

+copyright statement(s).

+

+"Original Version" refers to the collection of Font Software components as

+distributed by the Copyright Holder(s).

+

+"Modified Version" refers to any derivative made by adding to, deleting,

+or substituting -- in part or in whole -- any of the components of the

+Original Version, by changing formats or by porting the Font Software to a

+new environment.

+

+"Author" refers to any designer, engineer, programmer, technical

+writer or other person who contributed to the Font Software.

+

+PERMISSION & CONDITIONS

+Permission is hereby granted, free of charge, to any person obtaining

+a copy of the Font Software, to use, study, copy, merge, embed, modify,

+redistribute, and sell modified and unmodified copies of the Font

+Software, subject to the following conditions:

+

+1) Neither the Font Software nor any of its individual components,

+in Original or Modified Versions, may be sold by itself.

+

+2) Original or Modified Versions of the Font Software may be bundled,

+redistributed and/or sold with any software, provided that each copy

+contains the above copyright notice and this license. These can be

+included either as stand-alone text files, human-readable headers or

+in the appropriate machine-readable metadata fields within text or

+binary files as long as those fields can be easily viewed by the user.

+

+3) No Modified Version of the Font Software may use the Reserved Font

+Name(s) unless explicit written permission is granted by the corresponding

+Copyright Holder. This restriction only applies to the primary font name as

+presented to the users.

+

+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font

+Software shall not be used to promote, endorse or advertise any

+Modified Version, except to acknowledge the contribution(s) of the

+Copyright Holder(s) and the Author(s) or with their explicit written

+permission.

+

+5) The Font Software, modified or unmodified, in part or in whole,

+must be distributed entirely under this license, and must not be

+distributed under any other license. The requirement for fonts to

+remain under this license does not apply to any document created

+using the Font Software.

+

+TERMINATION

+This license becomes null and void if any of the above conditions are

+not met.

+

+DISCLAIMER

+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF

+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT

+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE

+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,

+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL

+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING

+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM

+OTHER DEALINGS IN THE FONT SOFTWARE.

diff --git a/core/ktx/src/androidTest/java/androidx/core/TestActivity.kt b/core/ktx/src/androidTest/java/androidx/core/TestActivity.kt
new file mode 100644
index 0000000..b0132ab
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/TestActivity.kt
@@ -0,0 +1,28 @@
+/*
+ * 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 androidx.core
+
+import android.app.Activity
+import android.os.Bundle
+import androidx.core.ktx.test.R
+
+class TestActivity : Activity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.test_activity)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/TestPreferenceActivity.kt b/core/ktx/src/androidTest/java/androidx/core/TestPreferenceActivity.kt
new file mode 100644
index 0000000..43e3dee
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/TestPreferenceActivity.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 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 androidx.core
+
+import android.app.Activity
+import android.os.Bundle
+import android.preference.PreferenceFragment
+import androidx.core.ktx.test.R
+
+class TestPreferenceActivity : Activity() {
+
+    companion object {
+        const val TAG = "TestPreferenceActivity"
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        fragmentManager.beginTransaction()
+            .add(android.R.id.content, TestPreferenceFragment(), TAG)
+            .commitNow()
+    }
+
+    class TestPreferenceFragment : PreferenceFragment() {
+        override fun onCreate(savedInstanceState: Bundle?) {
+            super.onCreate(savedInstanceState)
+            addPreferencesFromResource(R.xml.preferences)
+        }
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/animation/AnimatorTest.kt b/core/ktx/src/androidTest/java/androidx/core/animation/AnimatorTest.kt
new file mode 100644
index 0000000..de298a5
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/animation/AnimatorTest.kt
@@ -0,0 +1,115 @@
+/*
+ * 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 androidx.core.animation
+
+import android.animation.Animator
+import android.animation.ObjectAnimator
+import android.support.test.InstrumentationRegistry
+import android.support.test.annotation.UiThreadTest
+import android.support.test.filters.SdkSuppress
+import android.support.test.runner.AndroidJUnit4
+import android.view.View
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class AnimatorTest {
+    private val context = InstrumentationRegistry.getContext()
+    private val view = View(context)
+
+    private lateinit var animator: Animator
+
+    @Before fun before() {
+        animator = ObjectAnimator.ofFloat(view, View.ALPHA, 0f, 1f)
+    }
+
+    @Test fun testDoOnStart() {
+        var called = false
+        animator.doOnStart {
+            called = true
+        }
+
+        animator.listeners.forEach { it.onAnimationStart(animator) }
+        assertTrue(called)
+    }
+
+    @Test fun testDoOnEnd() {
+        var called = false
+        animator.doOnEnd {
+            called = true
+        }
+
+        animator.listeners.forEach { it.onAnimationEnd(animator) }
+        assertTrue(called)
+    }
+
+    @Test fun testDoOnCancel() {
+        var cancelCalled = false
+        animator.doOnCancel {
+            cancelCalled = true
+        }
+
+        animator.listeners.forEach { it.onAnimationCancel(animator) }
+        assertTrue(cancelCalled)
+    }
+
+    @Test fun testDoOnRepeat() {
+        var called = false
+        animator.doOnRepeat {
+            called = true
+        }
+
+        animator.listeners.forEach { it.onAnimationRepeat(animator) }
+        assertTrue(called)
+    }
+
+    @UiThreadTest
+    @SdkSuppress(minSdkVersion = 19)
+    @Test fun testDoOnPause() {
+        var called = false
+        animator.doOnPause {
+            called = true
+        }
+
+        // Start and pause and assert doOnPause was called
+        animator.start()
+        animator.pause()
+        assertTrue(called)
+
+        animator.cancel()
+    }
+
+    @UiThreadTest
+    @SdkSuppress(minSdkVersion = 19)
+    @Test fun testDoOnResume() {
+        var called = false
+        animator.doOnResume {
+            called = true
+        }
+
+        animator.start()
+        animator.pause()
+
+        // Now resume and assert doOnResume was called
+        animator.resume()
+        assertTrue(called)
+
+        animator.cancel()
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/content/ContentValuesTest.kt b/core/ktx/src/androidTest/java/androidx/core/content/ContentValuesTest.kt
new file mode 100644
index 0000000..746a634
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/content/ContentValuesTest.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.content
+
+import androidx.testutils.assertThrows
+import org.junit.Assert.assertArrayEquals
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Test
+import java.util.concurrent.atomic.AtomicInteger
+
+class ContentValuesTest {
+    @Test fun valuesOfValid() {
+        val values = contentValuesOf(
+            "null" to null,
+            "string" to "string",
+            "byte" to 1.toByte(),
+            "short" to 1.toShort(),
+            "int" to 1,
+            "long" to 1L,
+            "float" to 1f,
+            "double" to 1.0,
+            "boolean" to true,
+            "byteArray" to byteArrayOf()
+        )
+        assertEquals(10, values.size())
+        assertNull(values.get("null"))
+        assertEquals("string", values.get("string"))
+        assertEquals(1.toByte(), values.get("byte"))
+        assertEquals(1.toShort(), values.get("short"))
+        assertEquals(1, values.get("int"))
+        assertEquals(1L, values.get("long"))
+        assertEquals(1f, values.get("float"))
+        assertEquals(1.0, values.get("double"))
+        assertEquals(true, values.get("boolean"))
+        assertArrayEquals(byteArrayOf(), values.get("byteArray") as ByteArray)
+    }
+
+    @Test fun valuesOfInvalid() {
+        assertThrows<IllegalArgumentException> {
+            contentValuesOf("nope" to AtomicInteger(1))
+        }.hasMessageThat().isEqualTo(
+            "Illegal value type java.util.concurrent.atomic.AtomicInteger for key \"nope\"")
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/content/ContextTest.kt b/core/ktx/src/androidTest/java/androidx/core/content/ContextTest.kt
new file mode 100644
index 0000000..09d2355
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/content/ContextTest.kt
@@ -0,0 +1,73 @@
+/*
+ * 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 androidx.core.content
+
+import android.content.ContextWrapper
+import android.support.test.InstrumentationRegistry
+import android.support.test.filters.SdkSuppress
+import androidx.core.ktx.test.R
+import androidx.core.getAttributeSet
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertSame
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class ContextTest {
+    private val context = InstrumentationRegistry.getContext()
+
+    @SdkSuppress(minSdkVersion = 23)
+    @Test fun systemService() {
+        var lookup: Class<*>? = null
+        val context = object : ContextWrapper(context) {
+            override fun getSystemServiceName(serviceClass: Class<*>): String? {
+                lookup = serviceClass
+                return if (serviceClass == Unit::class.java) "unit" else null
+            }
+
+            override fun getSystemService(name: String): Any? {
+                return if (name == "unit") Unit else null
+            }
+        }
+        val actual = context.systemService<Unit>()
+        assertEquals(Unit::class.java, lookup)
+        assertSame(Unit, actual)
+    }
+
+    @Test fun withStyledAttributes() {
+        context.withStyledAttributes(attrs = intArrayOf(android.R.attr.textColorPrimary)) {
+            val resourceId = getResourceId(0, -1)
+            assertTrue(resourceId != 1)
+        }
+
+        context.withStyledAttributes(
+            android.R.style.Theme_Light,
+            intArrayOf(android.R.attr.textColorPrimary)
+        ) {
+            val resourceId = getResourceId(0, -1)
+            assertTrue(resourceId != 1)
+        }
+
+        val attrs = context.getAttributeSet(R.layout.test_attrs)
+        context.withStyledAttributes(attrs, R.styleable.SampleAttrs) {
+            assertTrue(getInt(R.styleable.SampleAttrs_sample, -1) != -1)
+        }
+
+        context.withStyledAttributes(attrs, R.styleable.SampleAttrs, 0, 0) {
+            assertTrue(getInt(R.styleable.SampleAttrs_sample, -1) != -1)
+        }
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/content/SharedPreferencesTest.kt b/core/ktx/src/androidTest/java/androidx/core/content/SharedPreferencesTest.kt
new file mode 100644
index 0000000..bf1e67d
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/content/SharedPreferencesTest.kt
@@ -0,0 +1,48 @@
+/*
+ * 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 androidx.core.content
+
+import android.support.test.InstrumentationRegistry
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class SharedPreferencesTest {
+    private val context = InstrumentationRegistry.getContext()
+
+    @Test fun editApply() {
+        val preferences = context.getSharedPreferences("prefs", 0)
+
+        preferences.edit {
+            putString("test_key1", "test_value")
+            putInt("test_key2", 100)
+        }
+
+        assertEquals("test_value", preferences.getString("test_key1", null))
+        assertEquals(100, preferences.getInt("test_key2", 0))
+    }
+
+    @Test fun editCommit() {
+        val preferences = context.getSharedPreferences("prefs", 0)
+        preferences.edit(commit = true) {
+            putString("test_key1", "test_value")
+            putInt("test_key2", 100)
+        }
+
+        assertEquals("test_value", preferences.getString("test_key1", null))
+        assertEquals(100, preferences.getInt("test_key2", 0))
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/content/res/TypedArrayTest.kt b/core/ktx/src/androidTest/java/androidx/core/content/res/TypedArrayTest.kt
new file mode 100644
index 0000000..fe576df
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/content/res/TypedArrayTest.kt
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.content.res
+
+import android.graphics.Color
+import android.support.test.InstrumentationRegistry
+import android.support.test.filters.SdkSuppress
+import androidx.core.ktx.test.R
+import androidx.testutils.assertThrows
+import androidx.core.getAttributeSet
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class TypedArrayTest {
+    private val context = InstrumentationRegistry.getContext()
+
+    @Test fun boolean() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+
+        assertTrue(array.getBooleanOrThrow(R.styleable.TypedArrayTypes_boolean_present))
+
+        assertThrows<IllegalArgumentException> {
+            array.getBooleanOrThrow(R.styleable.TypedArrayTypes_boolean_absent)
+        }.hasMessageThat().isEqualTo("Attribute not defined in set.")
+    }
+
+    @Test fun color() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+
+        assertEquals(Color.WHITE, array.getColorOrThrow(R.styleable.TypedArrayTypes_color_present))
+
+        assertThrows<IllegalArgumentException> {
+            array.getColorOrThrow(R.styleable.TypedArrayTypes_color_absent)
+        }.hasMessageThat().isEqualTo("Attribute not defined in set.")
+    }
+
+    @Test fun colorStateList() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+        val stateList = array.getColorStateListOrThrow(R.styleable.TypedArrayTypes_color_present)
+
+        assertEquals(Color.WHITE, stateList.defaultColor)
+
+        assertThrows<IllegalArgumentException> {
+            array.getColorStateListOrThrow(R.styleable.TypedArrayTypes_color_absent)
+        }.hasMessageThat().isEqualTo("Attribute not defined in set.")
+    }
+
+    @Test fun dimension() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+
+        assertEquals(1f, array.getDimensionOrThrow(R.styleable.TypedArrayTypes_dimension_present))
+
+        assertThrows<IllegalArgumentException> {
+            array.getDimensionOrThrow(R.styleable.TypedArrayTypes_dimension_absent)
+        }.hasMessageThat().isEqualTo("Attribute not defined in set.")
+    }
+
+    @Test fun dimensionPixelSize() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+
+        assertEquals(1,
+            array.getDimensionPixelSizeOrThrow(R.styleable.TypedArrayTypes_dimension_present))
+
+        assertThrows<IllegalArgumentException> {
+            array.getDimensionPixelSizeOrThrow(R.styleable.TypedArrayTypes_dimension_absent)
+        }.hasMessageThat().isEqualTo("Attribute not defined in set.")
+    }
+
+    @Test fun dimensionPixelOffset() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+
+        assertEquals(1,
+            array.getDimensionPixelOffsetOrThrow(R.styleable.TypedArrayTypes_dimension_present))
+
+        assertThrows<IllegalArgumentException> {
+            array.getDimensionPixelOffsetOrThrow(R.styleable.TypedArrayTypes_dimension_absent)
+        }.hasMessageThat().isEqualTo("Attribute not defined in set.")
+    }
+
+    @Test fun drawable() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+
+        assertNotNull(array.getDrawableOrThrow(R.styleable.TypedArrayTypes_drawable_present))
+
+        assertThrows<IllegalArgumentException> {
+            array.getDrawableOrThrow(R.styleable.TypedArrayTypes_drawable_absent)
+        }.hasMessageThat().isEqualTo("Attribute not defined in set.")
+    }
+
+    @Test fun float() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+
+        assertEquals(0.1f, array.getFloatOrThrow(R.styleable.TypedArrayTypes_float_present))
+
+        assertThrows<IllegalArgumentException> {
+            array.getFloatOrThrow(R.styleable.TypedArrayTypes_float_absent)
+        }.hasMessageThat().isEqualTo("Attribute not defined in set.")
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun font() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+
+        assertNotNull(array.getFontOrThrow(R.styleable.TypedArrayTypes_font_present))
+
+        assertThrows<IllegalArgumentException> {
+            array.getFontOrThrow(R.styleable.TypedArrayTypes_font_absent)
+        }.hasMessageThat().isEqualTo("Attribute not defined in set.")
+    }
+
+    @Test fun int() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+
+        assertEquals(1, array.getIntOrThrow(R.styleable.TypedArrayTypes_integer_present))
+
+        assertThrows<IllegalArgumentException> {
+            array.getIntOrThrow(R.styleable.TypedArrayTypes_integer_absent)
+        }.hasMessageThat().isEqualTo("Attribute not defined in set.")
+    }
+
+    @Test fun integer() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+
+        assertEquals(1, array.getIntegerOrThrow(R.styleable.TypedArrayTypes_integer_present))
+
+        assertThrows<IllegalArgumentException> {
+            array.getIntegerOrThrow(R.styleable.TypedArrayTypes_integer_absent)
+        }.hasMessageThat().isEqualTo("Attribute not defined in set.")
+    }
+
+    @Test
+    fun resourceId() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+
+        assertEquals(
+            R.font.inconsolata_regular,
+            array.getResourceIdOrThrow(R.styleable.TypedArrayTypes_resource_present)
+        )
+
+        assertThrows<IllegalArgumentException> {
+            array.getResourceIdOrThrow(R.styleable.TypedArrayTypes_resource_absent)
+        }.hasMessageThat().isEqualTo("Attribute not defined in set.")
+    }
+
+    @Test fun string() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+
+        assertEquals("Hello", array.getStringOrThrow(R.styleable.TypedArrayTypes_string_present))
+
+        assertThrows<IllegalArgumentException> {
+            array.getStringOrThrow(R.styleable.TypedArrayTypes_string_absent)
+        }.hasMessageThat().isEqualTo("Attribute not defined in set.")
+    }
+
+    @Test fun text() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+
+        assertEquals("Hello", array.getTextOrThrow(R.styleable.TypedArrayTypes_string_present))
+
+        assertThrows<IllegalArgumentException> {
+            array.getTextOrThrow(R.styleable.TypedArrayTypes_string_absent)
+        }.hasMessageThat().isEqualTo("Attribute not defined in set.")
+    }
+
+    @Test fun textArray() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+
+        val text = array.getTextArrayOrThrow(R.styleable.TypedArrayTypes_text_array_present)
+        assertEquals("Hello", text[0].toString())
+        assertEquals("World", text[1].toString())
+
+        assertThrows<IllegalArgumentException> {
+            array.getTextOrThrow(R.styleable.TypedArrayTypes_text_array_absent)
+        }.hasMessageThat().isEqualTo("Attribute not defined in set.")
+    }
+
+    @Test fun useRecyclesArray() {
+        val attrs = context.getAttributeSet(R.layout.typed_array)
+        val array = context.obtainStyledAttributes(attrs, R.styleable.TypedArrayTypes)
+
+        val result = array.use {
+            it.getBoolean(R.styleable.TypedArrayTypes_boolean_present, false)
+        }
+        assertTrue(result)
+
+        assertThrows<RuntimeException> {
+            array.recycle()
+        }
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/database/CursorTest.kt b/core/ktx/src/androidTest/java/androidx/core/database/CursorTest.kt
new file mode 100644
index 0000000..86d0731
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/database/CursorTest.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.database
+
+import android.database.Cursor
+import android.database.MatrixCursor
+import org.junit.Assert.assertArrayEquals
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Test
+
+class CursorTest {
+    @Test fun blobByName() {
+        val cursor = scalarCursor(byteArrayOf(0x01))
+        val blob = cursor.getBlob("data")
+        assertArrayEquals(byteArrayOf(0x01), blob)
+    }
+
+    @Test fun doubleByName() {
+        val cursor = scalarCursor(1.5)
+        val double = cursor.getDouble("data")
+        assertEquals(1.5, double, 0.0)
+    }
+
+    @Test fun floatByName() {
+        val cursor = scalarCursor(1.5f)
+        val float = cursor.getFloat("data")
+        assertEquals(1.5f, float, 0f)
+    }
+
+    @Test fun intByName() {
+        val cursor = scalarCursor(1)
+        val int = cursor.getInt("data")
+        assertEquals(1, int)
+    }
+
+    @Test fun longByName() {
+        val cursor = scalarCursor(1L)
+        val long = cursor.getLong("data")
+        assertEquals(1L, long)
+    }
+
+    @Test fun shortByName() {
+        val cursor = scalarCursor(1.toShort())
+        val short = cursor.getShort("data")
+        assertEquals(1.toShort(), short)
+    }
+
+    @Test fun stringByName() {
+        val cursor = scalarCursor("hey")
+        val string = cursor.getString("data")
+        assertEquals("hey", string)
+    }
+
+    @Test fun blobOrNullByIndex() {
+        val cursor = scalarCursor(null)
+        val blob = cursor.getBlobOrNull(0)
+        assertNull(blob)
+    }
+
+    @Test fun doubleOrNullByIndex() {
+        val cursor = scalarCursor(null)
+        val double = cursor.getDoubleOrNull(0)
+        assertNull(double)
+    }
+
+    @Test fun floatOrNullByIndex() {
+        val cursor = scalarCursor(null)
+        val float = cursor.getFloatOrNull(0)
+        assertNull(float)
+    }
+
+    @Test fun intOrNullByIndex() {
+        val cursor = scalarCursor(null)
+        val int = cursor.getIntOrNull(0)
+        assertNull(int)
+    }
+
+    @Test fun longOrNullByIndex() {
+        val cursor = scalarCursor(null)
+        val long = cursor.getLongOrNull(0)
+        assertNull(long)
+    }
+
+    @Test fun shortOrNullByIndex() {
+        val cursor = scalarCursor(null)
+        val short = cursor.getShortOrNull(0)
+        assertNull(short)
+    }
+
+    @Test fun stringOrNullByIndex() {
+        val cursor = scalarCursor(null)
+        val string = cursor.getStringOrNull(0)
+        assertNull(string)
+    }
+
+    @Test fun blobOrNullByName() {
+        val cursor = scalarCursor(null)
+        val blob = cursor.getBlobOrNull("data")
+        assertNull(blob)
+    }
+
+    @Test fun doubleOrNullByName() {
+        val cursor = scalarCursor(null)
+        val double = cursor.getDoubleOrNull("data")
+        assertNull(double)
+    }
+
+    @Test fun floatOrNullByName() {
+        val cursor = scalarCursor(null)
+        val float = cursor.getFloatOrNull("data")
+        assertNull(float)
+    }
+
+    @Test fun intOrNullByName() {
+        val cursor = scalarCursor(null)
+        val int = cursor.getIntOrNull("data")
+        assertNull(int)
+    }
+
+    @Test fun longOrNullByName() {
+        val cursor = scalarCursor(null)
+        val long = cursor.getLongOrNull("data")
+        assertNull(long)
+    }
+
+    @Test fun shortOrNullByName() {
+        val cursor = scalarCursor(null)
+        val short = cursor.getShortOrNull("data")
+        assertNull(short)
+    }
+
+    @Test fun stringOrNullByName() {
+        val cursor = scalarCursor(null)
+        val string = cursor.getStringOrNull("data")
+        assertNull(string)
+    }
+
+    private fun scalarCursor(item: Any?): Cursor = MatrixCursor(arrayOf("data")).apply {
+        addRow(arrayOf(item))
+        moveToFirst() // Prepare for consumers to read.
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/database/sqlite/SQLiteDatabaseTest.kt b/core/ktx/src/androidTest/java/androidx/core/database/sqlite/SQLiteDatabaseTest.kt
new file mode 100644
index 0000000..c8ed67d
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/database/sqlite/SQLiteDatabaseTest.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.database.sqlite
+
+import android.content.ContentValues
+import android.database.sqlite.SQLiteDatabase
+import android.database.sqlite.SQLiteOpenHelper
+import android.support.test.InstrumentationRegistry
+import androidx.testutils.assertThrows
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class SQLiteDatabaseTest {
+    private val context = InstrumentationRegistry.getContext()
+    private val openHelper = object : SQLiteOpenHelper(context, null, null, 1) {
+        override fun onCreate(db: SQLiteDatabase) {
+            db.execSQL("CREATE TABLE test(name TEXT)")
+        }
+
+        override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
+        }
+    }
+    private val db = openHelper.writableDatabase
+
+    @Test fun throwingBodyNotSuccessful() {
+        val exception = RuntimeException()
+        assertThrows<RuntimeException> {
+            db.transaction {
+                insert("test", null, ContentValues().apply { put("name", "Alice") })
+                throw exception
+            }
+        }.isSameAs(exception)
+
+        val query = db.rawQuery("SELECT COUNT(*) FROM test", emptyArray())
+        query.moveToFirst()
+        assertEquals(0L, query.getLong(0))
+        query.close()
+    }
+
+    @Test fun bodyReturnValue() {
+        val result = db.transaction {
+            "Hey"
+        }
+        assertEquals("Hey", result)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/extensions.kt b/core/ktx/src/androidTest/java/androidx/core/extensions.kt
new file mode 100644
index 0000000..dc07142
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/extensions.kt
@@ -0,0 +1,34 @@
+/*
+ * 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 androidx.core
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.util.AttributeSet
+import android.util.Xml
+import androidx.annotation.LayoutRes
+import org.xmlpull.v1.XmlPullParser
+
+@SuppressLint("ResourceType")
+fun Context.getAttributeSet(@LayoutRes layoutId: Int): AttributeSet {
+    val parser = resources.getXml(layoutId)
+    var type = parser.next()
+    while (type != XmlPullParser.START_TAG) {
+        type = parser.next()
+    }
+    return Xml.asAttributeSet(parser)
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/graphics/BitmapTest.kt b/core/ktx/src/androidTest/java/androidx/core/graphics/BitmapTest.kt
new file mode 100644
index 0000000..25b318b
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/graphics/BitmapTest.kt
@@ -0,0 +1,71 @@
+/*
+ * 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 androidx.core.graphics
+
+import android.graphics.Bitmap
+import android.graphics.ColorSpace
+import android.support.test.filters.SdkSuppress
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class BitmapTest {
+    @Test fun create() {
+        val bitmap = createBitmap(7, 9)
+        assertEquals(7, bitmap.width)
+        assertEquals(9, bitmap.height)
+        assertEquals(Bitmap.Config.ARGB_8888, bitmap.config)
+    }
+
+    @Test fun createWithConfig() {
+        val bitmap = createBitmap(7, 9, config = Bitmap.Config.RGB_565)
+        assertEquals(Bitmap.Config.RGB_565, bitmap.config)
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun createWithColorSpace() {
+        val colorSpace = ColorSpace.get(ColorSpace.Named.ADOBE_RGB)
+        val bitmap = createBitmap(7, 9, colorSpace = colorSpace)
+        assertEquals(colorSpace, bitmap.colorSpace)
+    }
+
+    @Test fun scale() {
+        val b = createBitmap(7, 9).scale(3, 5)
+        assertEquals(3, b.width)
+        assertEquals(5, b.height)
+    }
+
+    @Test fun applyCanvas() {
+        val p = createBitmap(2, 2).applyCanvas {
+            drawColor(0x40302010)
+        }.getPixel(1, 1)
+
+        assertEquals(0x40302010, p)
+    }
+
+    @Test fun getPixel() {
+        val b = createBitmap(2, 2).applyCanvas {
+            drawColor(0x40302010)
+        }
+        assertEquals(0x40302010, b[1, 1])
+    }
+
+    @Test fun setPixel() {
+        val b = createBitmap(2, 2)
+        b[1, 1] = 0x40302010
+        assertEquals(0x40302010, b[1, 1])
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/graphics/CanvasTest.kt b/core/ktx/src/androidTest/java/androidx/core/graphics/CanvasTest.kt
new file mode 100644
index 0000000..e940aa9
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/graphics/CanvasTest.kt
@@ -0,0 +1,127 @@
+/*
+ * 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 androidx.core.graphics
+
+import android.graphics.Canvas
+import android.graphics.Matrix
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class CanvasTest {
+    private val values = FloatArray(9)
+    private val canvas = Canvas(createBitmap(1, 1))
+
+    @Suppress("DEPRECATION")
+    @Test fun withSave() {
+        val beforeCount = canvas.saveCount
+
+        canvas.matrix.getValues(values)
+        val x = values[Matrix.MTRANS_X]
+        val y = values[Matrix.MTRANS_Y]
+
+        canvas.withSave {
+            assertThat(beforeCount).isLessThan(saveCount)
+            translate(10.0f, 10.0f)
+        }
+
+        canvas.matrix.getValues(values)
+        assertEquals(x, values[Matrix.MTRANS_X])
+        assertEquals(y, values[Matrix.MTRANS_Y])
+
+        assertEquals(beforeCount, canvas.saveCount)
+    }
+
+    @Test fun withTranslation() {
+        val beforeCount = canvas.saveCount
+        canvas.withTranslation(x = 16.0f, y = 32.0f) {
+            assertThat(beforeCount).isLessThan(saveCount)
+
+            @Suppress("DEPRECATION")
+            matrix.getValues(values) // will work for a software canvas
+
+            assertEquals(16.0f, values[Matrix.MTRANS_X])
+            assertEquals(32.0f, values[Matrix.MTRANS_Y])
+        }
+        assertEquals(beforeCount, canvas.saveCount)
+    }
+
+    @Test fun withRotation() {
+        val beforeCount = canvas.saveCount
+        canvas.withRotation(degrees = 90.0f, pivotX = 16.0f, pivotY = 32.0f) {
+            assertThat(beforeCount).isLessThan(saveCount)
+
+            @Suppress("DEPRECATION")
+            matrix.getValues(values) // will work for a software canvas
+
+            assertEquals(48.0f, values[Matrix.MTRANS_X])
+            assertEquals(16.0f, values[Matrix.MTRANS_Y])
+            assertEquals(-1.0f, values[Matrix.MSKEW_X])
+            assertEquals(1.0f, values[Matrix.MSKEW_Y])
+        }
+        assertEquals(beforeCount, canvas.saveCount)
+    }
+
+    @Test fun withScale() {
+        val beforeCount = canvas.saveCount
+        canvas.withScale(x = 2.0f, y = 4.0f, pivotX = 16.0f, pivotY = 32.0f) {
+            assertThat(beforeCount).isLessThan(saveCount)
+
+            @Suppress("DEPRECATION")
+            matrix.getValues(values) // will work for a software canvas
+
+            assertEquals(-16.0f, values[Matrix.MTRANS_X])
+            assertEquals(-96.0f, values[Matrix.MTRANS_Y])
+            assertEquals(2.0f, values[Matrix.MSCALE_X])
+            assertEquals(4.0f, values[Matrix.MSCALE_Y])
+        }
+        assertEquals(beforeCount, canvas.saveCount)
+    }
+
+    @Test fun withSkew() {
+        val beforeCount = canvas.saveCount
+        canvas.withSkew(x = 2.0f, y = 4.0f) {
+            assertThat(beforeCount).isLessThan(saveCount)
+
+            @Suppress("DEPRECATION")
+            matrix.getValues(values) // will work for a software canvas
+
+            assertEquals(2.0f, values[Matrix.MSKEW_X])
+            assertEquals(4.0f, values[Matrix.MSKEW_Y])
+        }
+        assertEquals(beforeCount, canvas.saveCount)
+    }
+
+    @Suppress("DEPRECATION")
+    @Test fun withMatrix() {
+        val originMatrix = canvas.matrix
+
+        val inputMatrix = Matrix()
+        inputMatrix.postTranslate(16.0f, 32.0f)
+        inputMatrix.postRotate(90.0f, 16.0f, 32.0f)
+        inputMatrix.postScale(2.0f, 4.0f, 16.0f, 32.0f)
+
+        val beforeCount = canvas.saveCount
+        canvas.withMatrix(inputMatrix) {
+            assertThat(beforeCount).isLessThan(saveCount)
+            assertEquals(inputMatrix, matrix)
+        }
+
+        assertEquals(originMatrix, canvas.matrix)
+        assertEquals(beforeCount, canvas.saveCount)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/graphics/ColorTest.kt b/core/ktx/src/androidTest/java/androidx/core/graphics/ColorTest.kt
new file mode 100644
index 0000000..5c647d1
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/graphics/ColorTest.kt
@@ -0,0 +1,127 @@
+/*
+ * 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 androidx.core.graphics
+
+import android.graphics.Color
+import android.graphics.ColorSpace
+import android.support.test.filters.SdkSuppress
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class ColorTest {
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun destructuringColor() {
+        val (r, g, b, a) = 0x337f3010.toColor()
+        assertEquals(0.5f, r, 1e-2f)
+        assertEquals(0.19f, g, 1e-2f)
+        assertEquals(0.06f, b, 1e-2f)
+        assertEquals(0.2f, a, 1e-2f)
+    }
+
+    @Test fun destructuringInt() {
+        val (a, r, g, b) = 0x337f3010
+        assertEquals(0x33, a)
+        assertEquals(0x7f, r)
+        assertEquals(0x30, g)
+        assertEquals(0x10, b)
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun intToColor() = assertEquals(Color.valueOf(0x337f3010), 0x337f3010.toColor())
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun intToColorLong() = assertEquals(Color.pack(0x337f3010), 0x337f3010.toColorLong())
+
+    @Test fun alpha() = assertEquals(0x33, 0x337f3010.alpha)
+    @Test fun red() = assertEquals(0x7f, 0x337f3010.red)
+    @Test fun green() = assertEquals(0x30, 0x337f3010.green)
+    @Test fun blue() = assertEquals(0x10, 0x337f3010.blue)
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun luminance() = assertEquals(0.212f, 0xff7f7f7f.toInt().luminance, 1e-3f)
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun longToColor() {
+        assertEquals(Color.valueOf(0x337f3010), Color.pack(0x337f3010).toColor())
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun longToColorInt() = assertEquals(0x337f3010, Color.pack(0x337f3010).toColorInt())
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun destructuringLong() {
+        val (r, g, b, a) = Color.pack(0x337f3010)
+        assertEquals(0.20f, a, 1e-2f)
+        assertEquals(0.50f, r, 1e-2f)
+        assertEquals(0.19f, g, 1e-2f)
+        assertEquals(0.06f, b, 1e-2f)
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun alphaLong() = assertEquals(0.20f, Color.pack(0x337f3010).alpha, 1e-2f)
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun redLong() = assertEquals(0.50f, Color.pack(0x337f3010).red, 1e-2f)
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun greenLong() = assertEquals(0.19f, Color.pack(0x337f3010).green, 1e-2f)
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun blueLong() = assertEquals(0.06f, Color.pack(0x337f3010).blue, 1e-2f)
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun luminanceLong() {
+        assertEquals(0.212f, Color.pack(0xff7f7f7f.toInt()).luminance, 1e-3f)
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun isSrgb() {
+        assertTrue(0x337f3010.toColorLong().isSrgb)
+        val c = Color.pack(1.0f, 0.0f, 0.0f, 1.0f, ColorSpace.get(ColorSpace.Named.BT2020))
+        assertFalse(c.isSrgb)
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun isWideGamut() {
+        assertFalse(0x337f3010.toColorLong().isWideGamut)
+        val c = Color.pack(1.0f, 0.0f, 0.0f, 1.0f, ColorSpace.get(ColorSpace.Named.BT2020))
+        assertTrue(c.isWideGamut)
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun getColorSpace() {
+        val sRGB = ColorSpace.get(ColorSpace.Named.SRGB)
+        assertEquals(sRGB, 0x337f3010.toColorLong().colorSpace)
+
+        val bt2020 = ColorSpace.get(ColorSpace.Named.BT2020)
+        val c = Color.pack(1.0f, 0.0f, 0.0f, 1.0f, bt2020)
+        assertEquals(bt2020, c.colorSpace)
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun addColorsSameColorSpace() {
+        val (r, g, b, a) = 0x7f7f0000.toColor() + 0x7f007f00.toColor()
+        assertEquals(0.16f, r, 1e-2f)
+        assertEquals(0.33f, g, 1e-2f)
+        assertEquals(0.00f, b, 1e-2f)
+        assertEquals(0.75f, a, 1e-2f)
+    }
+
+    @Test fun stringToColorInt() = assertEquals(Color.GREEN, "#00ff00".toColorInt())
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/graphics/MatrixTest.kt b/core/ktx/src/androidTest/java/androidx/core/graphics/MatrixTest.kt
new file mode 100644
index 0000000..61fce4f
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/graphics/MatrixTest.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.graphics
+
+import android.graphics.Matrix
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class MatrixTest {
+    @Test fun translationMatrix() {
+        val r = translationMatrix(2.0f, 3.0f).values()
+        assertEquals(1.0f, r[Matrix.MSCALE_X])
+        assertEquals(0.0f, r[Matrix.MSKEW_X])
+        assertEquals(2.0f, r[Matrix.MTRANS_X])
+        assertEquals(0.0f, r[Matrix.MSKEW_Y])
+        assertEquals(1.0f, r[Matrix.MSCALE_Y])
+        assertEquals(3.0f, r[Matrix.MTRANS_Y])
+    }
+
+    @Test fun scaleMatrix() {
+        val r = scaleMatrix(2.0f, 3.0f).values()
+        assertEquals(2.0f, r[Matrix.MSCALE_X])
+        assertEquals(0.0f, r[Matrix.MSKEW_X])
+        assertEquals(0.0f, r[Matrix.MTRANS_X])
+        assertEquals(0.0f, r[Matrix.MSKEW_Y])
+        assertEquals(3.0f, r[Matrix.MSCALE_Y])
+        assertEquals(0.0f, r[Matrix.MTRANS_Y])
+    }
+
+    @Test fun rotationMatrix() {
+        val r = rotationMatrix(90.0f, 2.0f, 3.0f).values()
+        assertEquals(0.0f, r[Matrix.MSCALE_X])
+        assertEquals(-1.0f, r[Matrix.MSKEW_X])
+        assertEquals(5.0f, r[Matrix.MTRANS_X])
+        assertEquals(1.0f, r[Matrix.MSKEW_Y])
+        assertEquals(0.0f, r[Matrix.MSCALE_Y])
+        assertEquals(1.0f, r[Matrix.MTRANS_Y])
+    }
+
+    @Test fun multiply() {
+        val t = translationMatrix(2.0f, 3.0f)
+        val s = scaleMatrix(2.0f, 3.0f)
+        val r = (s * t).values()
+
+        assertEquals(4.0f, r[Matrix.MTRANS_X], 1e-4f)
+        assertEquals(9.0f, r[Matrix.MTRANS_Y], 1e-4f)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/graphics/PathTest.kt b/core/ktx/src/androidTest/java/androidx/core/graphics/PathTest.kt
new file mode 100644
index 0000000..36f2cba
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/graphics/PathTest.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.graphics
+
+import android.graphics.Path
+import android.graphics.RectF
+import android.support.test.filters.SdkSuppress
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class PathTest {
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun testFlatten() {
+        val p = Path()
+
+        // Start with several moves
+        p.moveTo(5.0f, 5.0f)
+        p.moveTo(10.0f, 10.0f)
+        p.lineTo(20.0f, 20.0f)
+        p.lineTo(30.0f, 10.0f)
+        // Several moves in the middle
+        p.moveTo(40.0f, 10.0f)
+        p.moveTo(50.0f, 10.0f)
+        p.lineTo(60.0f, 20.0f)
+        // End with several moves
+        p.moveTo(10.0f, 10.0f)
+        p.moveTo(30.0f, 30.0f)
+
+        var count = 0
+        p.flatten().forEach {
+            count++
+            assertNotEquals(it.startFraction, it.endFraction)
+        }
+        assertEquals(3, count)
+    }
+
+    @SdkSuppress(minSdkVersion = 19)
+    @Test fun testUnion() {
+        val r1 = Path().apply { addRect(0.0f, 0.0f, 10.0f, 10.0f, Path.Direction.CW) }
+        val r2 = Path().apply { addRect(5.0f, 0.0f, 15.0f, 15.0f, Path.Direction.CW) }
+
+        val p = r1 + r2
+        val r = RectF()
+        p.computeBounds(r, true)
+
+        assertEquals(RectF(0.0f, 0.0f, 15.0f, 15.0f), r)
+    }
+
+    @SdkSuppress(minSdkVersion = 19)
+    @Test fun testAnd() {
+        val r1 = Path().apply { addRect(0.0f, 0.0f, 10.0f, 10.0f, Path.Direction.CW) }
+        val r2 = Path().apply { addRect(5.0f, 0.0f, 15.0f, 15.0f, Path.Direction.CW) }
+
+        val p = r1 and r2
+        val r = RectF()
+        p.computeBounds(r, true)
+
+        assertEquals(RectF(0.0f, 0.0f, 15.0f, 15.0f), r)
+    }
+
+    @SdkSuppress(minSdkVersion = 19)
+    @Test fun testDifference() {
+        val r1 = Path().apply { addRect(0.0f, 0.0f, 10.0f, 10.0f, Path.Direction.CW) }
+        val r2 = Path().apply { addRect(5.0f, 0.0f, 15.0f, 15.0f, Path.Direction.CW) }
+
+        val p = r1 - r2
+        val r = RectF()
+        p.computeBounds(r, true)
+
+        assertEquals(RectF(0.0f, 0.0f, 5.0f, 10.0f), r)
+    }
+
+    @SdkSuppress(minSdkVersion = 19)
+    @Test fun testIntersection() {
+        val r1 = Path().apply { addRect(0.0f, 0.0f, 10.0f, 10.0f, Path.Direction.CW) }
+        val r2 = Path().apply { addRect(5.0f, 0.0f, 15.0f, 15.0f, Path.Direction.CW) }
+
+        val p = r1 or r2
+        val r = RectF()
+        p.computeBounds(r, true)
+
+        assertEquals(RectF(5.0f, 0.0f, 10.0f, 10.0f), r)
+    }
+
+    @SdkSuppress(minSdkVersion = 19)
+    @Test fun testEmptyIntersection() {
+        val r1 = Path().apply { addRect(0.0f, 0.0f, 2.0f, 2.0f, Path.Direction.CW) }
+        val r2 = Path().apply { addRect(5.0f, 5.0f, 7.0f, 7.0f, Path.Direction.CW) }
+
+        val p = r1 or r2
+        assertTrue(p.isEmpty)
+    }
+
+    @SdkSuppress(minSdkVersion = 19)
+    @Test fun testXor() {
+        val r1 = Path().apply { addRect(0.0f, 0.0f, 10.0f, 10.0f, Path.Direction.CW) }
+        val r2 = Path().apply { addRect(5.0f, 5.0f, 15.0f, 15.0f, Path.Direction.CW) }
+
+        val p = r1 xor r2
+        val r = RectF()
+        p.computeBounds(r, true)
+
+        assertEquals(RectF(0.0f, 0.0f, 15.0f, 15.0f), r)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/graphics/PictureTest.kt b/core/ktx/src/androidTest/java/androidx/core/graphics/PictureTest.kt
new file mode 100644
index 0000000..6d0029f
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/graphics/PictureTest.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.graphics
+
+import android.graphics.Color
+import android.graphics.Picture
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class PictureTest {
+    @Test fun record() {
+        val p = Picture().record(1, 1) {
+            drawColor(Color.RED)
+        }
+        val v = createBitmap(1, 1).applyCanvas {
+            drawPicture(p)
+        }.getPixel(0, 0)
+        assertEquals(0xffff0000.toInt(), v)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/graphics/PointTest.kt b/core/ktx/src/androidTest/java/androidx/core/graphics/PointTest.kt
new file mode 100644
index 0000000..791d35f
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/graphics/PointTest.kt
@@ -0,0 +1,106 @@
+/*
+ * 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 androidx.core.graphics
+
+import android.graphics.Point
+import android.graphics.PointF
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class PointTest {
+    @Test fun destructuringInt() {
+        val (x, y) = Point(2, 3)
+        assertEquals(2, x)
+        assertEquals(3, y)
+    }
+
+    @Test fun destructuringFloat() {
+        val (x, y) = PointF(2.0f, 3.0f)
+        assertEquals(2.0f, x)
+        assertEquals(3.0f, y)
+    }
+
+    @Test fun offsetInt() {
+        val (x, y) = Point(2, 3) + 2
+        assertEquals(4, x)
+        assertEquals(5, y)
+    }
+
+    @Test fun offsetFloat() {
+        val (x, y) = PointF(2.0f, 3.0f) + 2.0f
+        assertEquals(4.0f, x)
+        assertEquals(5.0f, y)
+    }
+
+    @Test fun offsetPoint() {
+        val (x, y) = Point(2, 3) + Point(1, 2)
+        assertEquals(3, x)
+        assertEquals(5, y)
+    }
+
+    @Test fun offsetPointF() {
+        val (x, y) = PointF(2.0f, 3.0f) + PointF(1.0f, 2.0f)
+        assertEquals(3.0f, x)
+        assertEquals(5.0f, y)
+    }
+
+    @Test fun negativeOffsetInt() {
+        val (x, y) = Point(2, 3) - 2
+        assertEquals(0, x)
+        assertEquals(1, y)
+    }
+
+    @Test fun negativeOffsetFloat() {
+        val (x, y) = PointF(2.0f, 3.0f) - 2.0f
+        assertEquals(0.0f, x)
+        assertEquals(1.0f, y)
+    }
+
+    @Test fun negativeOffsetPoint() {
+        val (x, y) = Point(2, 3) - Point(1, 2)
+        assertEquals(1, x)
+        assertEquals(1, y)
+    }
+
+    @Test fun negativeOffsetPointF() {
+        val (x, y) = PointF(2.0f, 3.0f) - PointF(1.0f, 2.0f)
+        assertEquals(1.0f, x)
+        assertEquals(1.0f, y)
+    }
+
+    @Test fun negateInt() {
+        val (x, y) = -Point(2, 3)
+        assertEquals(-2, x)
+        assertEquals(-3, y)
+    }
+
+    @Test fun negateFloat() {
+        val (x, y) = -PointF(2.0f, 3.0f)
+        assertEquals(-2.0f, x)
+        assertEquals(-3.0f, y)
+    }
+
+    @Test fun toPointF() {
+        val pointF = Point(1, 2).toPointF()
+        assertEquals(1f, pointF.x, 0f)
+        assertEquals(2f, pointF.y, 0f)
+    }
+
+    @Test fun toPoint() {
+        assertEquals(Point(1, 2), PointF(1.1f, 2.8f).toPoint())
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/graphics/PorterDuffTest.kt b/core/ktx/src/androidTest/java/androidx/core/graphics/PorterDuffTest.kt
new file mode 100644
index 0000000..9b44a50
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/graphics/PorterDuffTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.graphics
+
+import android.graphics.Paint
+import android.graphics.PorterDuff
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class PorterDuffTest {
+    @Test fun xfermode() {
+        val p = createBitmap(1, 1).applyCanvas {
+            val p = Paint().apply { color = 0xffffffff.toInt() }
+            drawRect(0f, 0f, 1f, 1f, p)
+
+            p.color = 0x7f00ff00
+            p.xfermode = PorterDuff.Mode.SRC.toXfermode()
+            drawRect(0f, 0f, 1f, 1f, p)
+        }.getPixel(0, 0)
+
+        assertEquals(0x7f00ff00, p)
+    }
+
+    @Test fun colorFilter() {
+        val p = createBitmap(1, 1).applyCanvas {
+            val p = Paint().apply { color = 0xffffffff.toInt() }
+            drawRect(0f, 0f, 1f, 1f, p)
+
+            p.color = 0xff000000.toInt()
+            p.colorFilter = PorterDuff.Mode.SRC.toColorFilter(0xff00ff00.toInt())
+            drawRect(0f, 0f, 1f, 1f, p)
+        }.getPixel(0, 0)
+
+        assertEquals(0xff00ff00.toInt(), p)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/graphics/RectTest.kt b/core/ktx/src/androidTest/java/androidx/core/graphics/RectTest.kt
new file mode 100644
index 0000000..8b2613f
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/graphics/RectTest.kt
@@ -0,0 +1,232 @@
+/*
+ * 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 androidx.core.graphics
+
+import android.graphics.Matrix
+import android.graphics.Point
+import android.graphics.PointF
+import android.graphics.Rect
+import android.graphics.RectF
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class RectTest {
+    @Test fun destructuringInt() {
+        val (l, t, r, b) = Rect(4, 8, 16, 24)
+        assertEquals(4, l)
+        assertEquals(8, t)
+        assertEquals(16, r)
+        assertEquals(24, b)
+    }
+
+    @Test fun destructuringFloat() {
+        val (l, t, r, b) = RectF(4.0f, 8.0f, 16.0f, 24.0f)
+        assertEquals(4.0f, l)
+        assertEquals(8.0f, t)
+        assertEquals(16.0f, r)
+        assertEquals(24.0f, b)
+    }
+
+    @Test fun unionInt() {
+        val (l, t, r, b) = Rect(0, 0, 4, 4) + Rect(-1, -1, 6, 6)
+        assertEquals(-1, l)
+        assertEquals(-1, t)
+        assertEquals(6, r)
+        assertEquals(6, b)
+    }
+
+    @Test fun unionAsAndInt() {
+        val (l, t, r, b) = Rect(0, 0, 4, 4) and Rect(-1, -1, 6, 6)
+        assertEquals(-1, l)
+        assertEquals(-1, t)
+        assertEquals(6, r)
+        assertEquals(6, b)
+    }
+
+    @Test fun unionFloat() {
+        val (l, t, r, b) = RectF(0.0f, 0.0f, 4.0f, 4.0f) + RectF(-1.0f, -1.0f, 6.0f, 6.0f)
+        assertEquals(-1.0f, l)
+        assertEquals(-1.0f, t)
+        assertEquals(6.0f, r)
+        assertEquals(6.0f, b)
+    }
+
+    @Test fun unionAsAndFloat() {
+        val (l, t, r, b) = RectF(0.0f, 0.0f, 4.0f, 4.0f) and RectF(-1.0f, -1.0f, 6.0f, 6.0f)
+        assertEquals(-1.0f, l)
+        assertEquals(-1.0f, t)
+        assertEquals(6.0f, r)
+        assertEquals(6.0f, b)
+    }
+
+    @Test fun differenceInt() {
+        val r = Rect(0, 0, 4, 4) - Rect(-1, 2, 6, 6)
+        assertEquals(Rect(0, 0, 4, 2), r.bounds)
+    }
+
+    @Test fun differenceFloat() {
+        val r = RectF(0.0f, 0.0f, 4.0f, 4.0f) - RectF(-1.0f, 2.0f, 6.0f, 6.0f)
+        assertEquals(Rect(0, 0, 4, 2), r.bounds)
+    }
+
+    @Test fun intersectionAsOrInt() {
+        val (l, t, r, b) = Rect(0, 0, 4, 4) or Rect(2, 2, 6, 6)
+        assertEquals(2, l)
+        assertEquals(2, t)
+        assertEquals(4, r)
+        assertEquals(4, b)
+    }
+
+    @Test fun intersectionAsOrFloat() {
+        val (l, t, r, b) = RectF(0.0f, 0.0f, 4.0f, 4.0f) or RectF(2.0f, 2.0f, 6.0f, 6.0f)
+        assertEquals(2.0f, l)
+        assertEquals(2.0f, t)
+        assertEquals(4.0f, r)
+        assertEquals(4.0f, b)
+    }
+
+    @Test fun xorInt() {
+        val r = Rect(0, 0, 4, 4) xor Rect(2, 2, 6, 6)
+        assertEquals(Rect(0, 0, 4, 4) and Rect(2, 2, 6, 6), r.bounds)
+        assertFalse(r.contains(3, 3))
+    }
+
+    @Test fun xorFloat() {
+        val r = RectF(0.0f, 0.0f, 4.0f, 4.0f) xor RectF(2.0f, 2.0f, 6.0f, 6.0f)
+        assertEquals(Rect(0, 0, 4, 4) and Rect(2, 2, 6, 6), r.bounds)
+        assertFalse(r.contains(3, 3))
+    }
+
+    @Test fun offsetInt() {
+        val (l, t, r, b) = Rect(0, 0, 2, 2) + 2
+        assertEquals(l, 2)
+        assertEquals(t, 2)
+        assertEquals(r, 4)
+        assertEquals(b, 4)
+    }
+
+    @Test fun offsetPoint() {
+        val (l, t, r, b) = Rect(0, 0, 2, 2) + Point(1, 2)
+        assertEquals(l, 1)
+        assertEquals(t, 2)
+        assertEquals(r, 3)
+        assertEquals(b, 4)
+    }
+
+    @Test fun offsetFloat() {
+        val (l, t, r, b) = RectF(0.0f, 0.0f, 2.0f, 2.0f) + 2.0f
+        assertEquals(l, 2.0f)
+        assertEquals(t, 2.0f)
+        assertEquals(r, 4.0f)
+        assertEquals(b, 4.0f)
+    }
+
+    @Test fun offsetPointF() {
+        val (l, t, r, b) = RectF(0.0f, 0.0f, 2.0f, 2.0f) + PointF(1.0f, 2.0f)
+        assertEquals(l, 1.0f)
+        assertEquals(t, 2.0f)
+        assertEquals(r, 3.0f)
+        assertEquals(b, 4.0f)
+    }
+
+    @Test fun negativeOffsetInt() {
+        val (l, t, r, b) = Rect(0, 0, 2, 2) - 2
+        assertEquals(l, -2)
+        assertEquals(t, -2)
+        assertEquals(r, 0)
+        assertEquals(b, 0)
+    }
+
+    @Test fun negativeOffsetPoint() {
+        val (l, t, r, b) = Rect(0, 0, 2, 2) - Point(1, 2)
+        assertEquals(l, -1)
+        assertEquals(t, -2)
+        assertEquals(r, 1)
+        assertEquals(b, 0)
+    }
+
+    @Test fun negativeOffsetFloat() {
+        val (l, t, r, b) = RectF(0.0f, 0.0f, 2.0f, 2.0f) - 2.0f
+        assertEquals(l, -2.0f)
+        assertEquals(t, -2.0f)
+        assertEquals(r, 0.0f)
+        assertEquals(b, 0.0f)
+    }
+
+    @Test fun negativeOffsetPointF() {
+        val (l, t, r, b) = RectF(0.0f, 0.0f, 2.0f, 2.0f) - PointF(1.0f, 2.0f)
+        assertEquals(l, -1.0f)
+        assertEquals(t, -2.0f)
+        assertEquals(r, 1.0f)
+        assertEquals(b, 0.0f)
+    }
+
+    @Test fun pointInside() {
+        assertTrue(Point(1, 1) in Rect(0, 0, 2, 2))
+        assertTrue(PointF(1.0f, 1.0f) in RectF(0.0f, 0.0f, 2.0f, 2.0f))
+    }
+
+    @Test fun toRect() {
+        assertEquals(
+            Rect(0, 1, 2, 3),
+            RectF(0f, 1f, 2f, 3f).toRect())
+
+        assertEquals(
+            Rect(0, 1, 2, 3),
+            RectF(0.1f, 1.1f, 1.9f, 2.9f).toRect())
+    }
+
+    @Test fun toRectF() {
+        val rectF = Rect(0, 1, 2, 3).toRectF()
+        assertEquals(0f, rectF.left, 0f)
+        assertEquals(1f, rectF.top, 0f)
+        assertEquals(2f, rectF.right, 0f)
+        assertEquals(3f, rectF.bottom, 0f)
+    }
+
+    @Test fun toRegionInt() {
+        assertEquals(Rect(1, 1, 5, 5), Rect(1, 1, 5, 5).toRegion().bounds)
+    }
+
+    @Test fun toRegionFloat() {
+        assertEquals(Rect(1, 1, 5, 5), RectF(1.1f, 1.1f, 4.8f, 4.8f).toRegion().bounds)
+    }
+
+    @Test fun transformRectToRect() {
+        val m = Matrix()
+        m.setScale(2.0f, 2.0f)
+
+        val r = RectF(2.0f, 2.0f, 5.0f, 7.0f).transform(m)
+        assertEquals(4f, r.left, 0f)
+        assertEquals(4f, r.top, 0f)
+        assertEquals(10f, r.right, 0f)
+        assertEquals(14f, r.bottom, 0f)
+    }
+
+    @Test fun transformRectNotPreserved() {
+        val m = Matrix()
+        m.setRotate(45.0f)
+
+        val (l, t, r, b) = RectF(-1.0f, -1.0f, 1.0f, 1.0f).transform(m)
+        assertEquals(-1.414f, l, 1e-3f)
+        assertEquals(-1.414f, t, 1e-3f)
+        assertEquals( 1.414f, r, 1e-3f)
+        assertEquals( 1.414f, b, 1e-3f)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/graphics/RegionTest.kt b/core/ktx/src/androidTest/java/androidx/core/graphics/RegionTest.kt
new file mode 100644
index 0000000..21e6443
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/graphics/RegionTest.kt
@@ -0,0 +1,157 @@
+/*
+ * 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 androidx.core.graphics
+
+import android.graphics.Point
+import android.graphics.Rect
+import android.graphics.Region
+import androidx.testutils.assertThrows
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotSame
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class RegionTest {
+    @Test fun containsPoint() {
+        assertFalse(Point(1, 1) in Region())
+        assertTrue(Point(1, 1) in Region(0, 0, 2, 2))
+    }
+
+    @Test fun unionRect() {
+        val r = Region(0, 0, 2, 2) + Rect(4, 4, 6, 6)
+        assertFalse(Point(3, 3) in r)
+        assertTrue(Point(1, 1) in r)
+        assertTrue(Point(5, 5) in r)
+    }
+
+    @Test fun unionRegion() {
+        val r = Region(0, 0, 2, 2) + Region(4, 4, 6, 6)
+        assertFalse(Point(3, 3) in r)
+        assertTrue(Point(1, 1) in r)
+        assertTrue(Point(5, 5) in r)
+    }
+
+    @Test fun unionAsAndRect() {
+        val r = Region(0, 0, 2, 2) and Rect(4, 4, 6, 6)
+        assertFalse(Point(3, 3) in r)
+        assertTrue(Point(1, 1) in r)
+        assertTrue(Point(5, 5) in r)
+    }
+
+    @Test fun unionAsAndRegion() {
+        val r = Region(0, 0, 2, 2) and Region(4, 4, 6, 6)
+        assertFalse(Point(3, 3) in r)
+        assertTrue(Point(1, 1) in r)
+        assertTrue(Point(5, 5) in r)
+    }
+
+    @Test fun differenceRect() {
+        val r = Region(0, 0, 4, 4) - Rect(2, 2, 6, 6)
+        assertFalse(Point(3, 3) in r)
+        assertTrue(Point(1, 1) in r)
+        assertFalse(Point(5, 5) in r)
+    }
+
+    @Test fun differenceRegion() {
+        val r = Region(0, 0, 4, 4) - Region(2, 2, 6, 6)
+        assertFalse(Point(3, 3) in r)
+        assertTrue(Point(1, 1) in r)
+        assertFalse(Point(5, 5) in r)
+    }
+
+    @Test fun unaryMinus() {
+        val r = Rect(0, 0, 10, 10) - Rect(4, 4, 6, 6)
+        assertTrue(Point(1, 1) in r)
+        assertFalse(Point(5, 5) in r)
+
+        val i = -r
+        assertFalse(Point(1, 1) in i)
+        assertTrue(Point(5, 5) in i)
+    }
+
+    @Test fun not() {
+        val r = Rect(0, 0, 10, 10) - Rect(4, 4, 6, 6)
+        assertTrue(Point(1, 1) in r)
+        assertFalse(Point(5, 5) in r)
+
+        val i = !r
+        assertFalse(Point(1, 1) in i)
+        assertTrue(Point(5, 5) in i)
+    }
+
+    @Test fun orRect() {
+        val r = Region(0, 0, 4, 4) or Rect(2, 2, 6, 6)
+        assertFalse(Point(1, 1) in r)
+        assertTrue(Point(3, 3) in r)
+    }
+
+    @Test fun orRegion() {
+        val r = Region(0, 0, 4, 4) or Region(2, 2, 6, 6)
+        assertFalse(Point(1, 1) in r)
+        assertTrue(Point(3, 3) in r)
+    }
+
+    @Test fun xorRect() {
+        val r = Region(0, 0, 4, 4) xor Rect(2, 2, 6, 6)
+        assertFalse(Point(3, 3) in r)
+        assertTrue(Point(1, 1) in r)
+    }
+
+    @Test fun xorRegion() {
+        val r = Region(0, 0, 4, 4) xor Region(2, 2, 6, 6)
+        assertFalse(Point(3, 3) in r)
+        assertTrue(Point(1, 1) in r)
+    }
+
+    @Test fun iteratorForLoop() {
+        val region = Region(0, 0, 4, 4) -
+                Rect(2, 2, 6, 6)
+        var count = 0
+        var r = Rect()
+        for (rect in region) {
+            count++
+            assertNotSame(r, rect)
+            r = rect
+        }
+        assertEquals(2, count)
+    }
+
+    @Test fun iteratorOutOfBounds() {
+        val region = Region(0, 0, 4, 4) -
+                Rect(2, 2, 6, 6)
+        val it = region.iterator()
+        it.next()
+        it.next()
+        assertThrows<IndexOutOfBoundsException> {
+            it.next()
+        }
+    }
+
+    @Test fun iteratorForEach() {
+        val region = Region(0, 0, 4, 4) -
+                Rect(2, 2, 6, 6)
+        var count = 0
+        var r = Rect()
+        region.forEach {
+            count++
+            assertNotSame(r, it)
+            r = it
+        }
+        assertEquals(2, count)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/graphics/ShaderTest.kt b/core/ktx/src/androidTest/java/androidx/core/graphics/ShaderTest.kt
new file mode 100644
index 0000000..ad2b63c
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/graphics/ShaderTest.kt
@@ -0,0 +1,44 @@
+/*
+ * 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 androidx.core.graphics
+
+import android.graphics.Matrix
+import android.graphics.Shader
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class ShaderTest {
+    @Test
+    fun testTransform() {
+        @Suppress("DEPRECATION")
+        val shader = Shader()
+        val values = FloatArray(9)
+        val matrix = Matrix()
+
+        shader.transform {
+            setTranslate(10f, 30f)
+        }
+
+        // Now read matrix from Shader
+        shader.getLocalMatrix(matrix)
+        matrix.getValues(values)
+
+        // Assert that the values are as expected
+        assertEquals(10f, values[Matrix.MTRANS_X])
+        assertEquals(30f, values[Matrix.MTRANS_Y])
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/graphics/drawable/BitmapDrawableTest.kt b/core/ktx/src/androidTest/java/androidx/core/graphics/drawable/BitmapDrawableTest.kt
new file mode 100644
index 0000000..4c4ceb6
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/graphics/drawable/BitmapDrawableTest.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.graphics.drawable
+
+import android.support.test.InstrumentationRegistry
+import androidx.core.graphics.createBitmap
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class BitmapDrawableTest {
+    private val context = InstrumentationRegistry.getContext()
+
+    @Test fun fromBitmap() {
+        val b = createBitmap(1, 1)
+        val drawable = b.toDrawable(context.resources)
+        assertEquals(b, drawable.bitmap)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/graphics/drawable/ColorDrawableTest.kt b/core/ktx/src/androidTest/java/androidx/core/graphics/drawable/ColorDrawableTest.kt
new file mode 100644
index 0000000..ad7a39b
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/graphics/drawable/ColorDrawableTest.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.graphics.drawable
+
+import android.graphics.Color
+import android.support.test.filters.SdkSuppress
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class ColorDrawableTest {
+    @Test fun fromInt() {
+        val drawable = Color.CYAN.toDrawable()
+        assertEquals(Color.CYAN, drawable.color)
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test fun fromColor() {
+        val drawable = Color.valueOf(Color.CYAN).toDrawable()
+        assertEquals(Color.CYAN, drawable.color)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/graphics/drawable/DrawableTest.kt b/core/ktx/src/androidTest/java/androidx/core/graphics/drawable/DrawableTest.kt
new file mode 100644
index 0000000..6455d0a
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/graphics/drawable/DrawableTest.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.graphics.drawable
+
+import android.graphics.Bitmap.Config
+import android.graphics.Color
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.ColorDrawable
+import android.support.test.InstrumentationRegistry
+import androidx.core.graphics.createBitmap
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class DrawableTest {
+    private val context = InstrumentationRegistry.getContext()
+    private val resources = context.resources
+
+    @Test fun bitmapDrawableNoSizeNoConfig() {
+        val original = createBitmap(10, 10).apply {
+            eraseColor(Color.RED)
+        }
+        val drawable = BitmapDrawable(resources, original)
+
+        val bitmap = drawable.toBitmap()
+        assertEquals(10, bitmap.width)
+        assertEquals(10, bitmap.height)
+        assertEquals(Config.ARGB_8888, bitmap.config)
+        assertEquals(Color.RED, bitmap.getPixel(5, 5))
+    }
+
+    @Test fun bitmapDrawableNoSizeRetainedConfig() {
+        val original = createBitmap(10, 10).apply {
+            eraseColor(Color.RED)
+        }
+        val drawable = BitmapDrawable(resources, original)
+
+        val bitmap = drawable.toBitmap(config = Config.ARGB_8888)
+        assertEquals(10, bitmap.width)
+        assertEquals(10, bitmap.height)
+        assertEquals(Config.ARGB_8888, bitmap.config)
+        assertEquals(Color.RED, bitmap.getPixel(5, 5))
+    }
+
+    @Test fun bitmapDrawableNoSizeDifferentConfig() {
+        val original = createBitmap(10, 10).apply {
+            eraseColor(Color.RED)
+        }
+        val drawable = BitmapDrawable(resources, original)
+
+        val bitmap = drawable.toBitmap(config = Config.ARGB_8888)
+        assertEquals(10, bitmap.width)
+        assertEquals(10, bitmap.height)
+        assertEquals(Config.ARGB_8888, bitmap.config)
+        assertEquals(Color.RED, bitmap.getPixel(5, 5))
+    }
+
+    @Test fun bitmapDrawableDifferentSizeNoConfig() {
+        val original = createBitmap(10, 10).apply {
+            eraseColor(Color.RED)
+        }
+        val drawable = BitmapDrawable(resources, original)
+
+        val bitmap = drawable.toBitmap(20, 20)
+        assertEquals(20, bitmap.width)
+        assertEquals(20, bitmap.height)
+        assertEquals(Config.ARGB_8888, bitmap.config)
+        assertEquals(Color.RED, bitmap.getPixel(10, 10))
+    }
+
+    @Test fun bitmapDrawableDifferentSizeDifferentConfig() {
+        val original = createBitmap(10, 10).apply {
+            eraseColor(Color.RED)
+        }
+        val drawable = BitmapDrawable(resources, original)
+
+        val bitmap = drawable.toBitmap(20, 20, Config.ARGB_8888)
+        assertEquals(20, bitmap.width)
+        assertEquals(20, bitmap.height)
+        assertEquals(Config.ARGB_8888, bitmap.config)
+        assertEquals(Color.RED, bitmap.getPixel(10, 10))
+    }
+
+    @Test fun drawableNoConfig() {
+        val drawable = object : ColorDrawable(Color.RED) {
+            override fun getIntrinsicWidth() = 10
+            override fun getIntrinsicHeight() = 10
+        }
+
+        val bitmap = drawable.toBitmap()
+        assertEquals(10, bitmap.width)
+        assertEquals(10, bitmap.height)
+        assertEquals(Config.ARGB_8888, bitmap.config)
+        assertEquals(Color.RED, bitmap.getPixel(5, 5))
+    }
+
+    @Test fun drawableConfig() {
+        val drawable = object : ColorDrawable(Color.RED) {
+            override fun getIntrinsicWidth() = 10
+            override fun getIntrinsicHeight() = 10
+        }
+
+        val bitmap = drawable.toBitmap(config = Config.RGB_565)
+        assertEquals(10, bitmap.width)
+        assertEquals(10, bitmap.height)
+        assertEquals(Config.RGB_565, bitmap.config)
+        assertEquals(Color.RED, bitmap.getPixel(5, 5))
+    }
+
+    @Test fun drawableSize() {
+        val drawable = object : ColorDrawable(Color.RED) {
+            override fun getIntrinsicWidth() = 10
+            override fun getIntrinsicHeight() = 10
+        }
+
+        val bitmap = drawable.toBitmap(20, 20)
+        assertEquals(20, bitmap.width)
+        assertEquals(20, bitmap.height)
+        assertEquals(Config.ARGB_8888, bitmap.config)
+        assertEquals(Color.RED, bitmap.getPixel(10, 10))
+    }
+
+    @Test fun oldBoundsRestored() {
+        val drawable = object : ColorDrawable(Color.RED) {
+            override fun getIntrinsicWidth() = 10
+            override fun getIntrinsicHeight() = 10
+        }
+        drawable.setBounds(2, 2, 8, 8)
+
+        val bitmap = drawable.toBitmap()
+        assertEquals(10, bitmap.width)
+        assertEquals(10, bitmap.height)
+
+        assertEquals(2, drawable.bounds.left)
+        assertEquals(2, drawable.bounds.top)
+        assertEquals(8, drawable.bounds.right)
+        assertEquals(8, drawable.bounds.bottom)
+    }
+
+    @Test fun updateBoundsTest() {
+        val drawable = object : ColorDrawable(Color.RED) {
+            override fun getIntrinsicWidth() = 10
+            override fun getIntrinsicHeight() = 10
+        }
+        drawable.setBounds(0, 0, 10, 10)
+
+        drawable.updateBounds(1, 2, 3, 4)
+
+        assertEquals(1, drawable.bounds.left)
+        assertEquals(2, drawable.bounds.top)
+        assertEquals(3, drawable.bounds.right)
+        assertEquals(4, drawable.bounds.bottom)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/graphics/drawable/IconTest.kt b/core/ktx/src/androidTest/java/androidx/core/graphics/drawable/IconTest.kt
new file mode 100644
index 0000000..e2dd84c
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/graphics/drawable/IconTest.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.graphics.drawable
+
+import android.graphics.Bitmap
+import android.graphics.Bitmap.Config.ARGB_8888
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.drawable.Icon
+import android.support.test.InstrumentationRegistry
+import android.support.test.filters.SdkSuppress
+import androidx.core.graphics.createBitmap
+import androidx.core.net.toUri
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import java.io.File
+
+@SdkSuppress(minSdkVersion = 26)
+class IconTest {
+    private val context = InstrumentationRegistry.getContext()
+
+    @Test fun fromBitmapAdaptive() {
+        val density = context.resources.displayMetrics.density
+
+        val edge = (108.0f * density + 0.5f).toInt()
+        val bitmap = Bitmap.createBitmap(edge, edge, ARGB_8888).apply {
+            eraseColor(Color.RED)
+        }
+        val icon = bitmap.toAdaptiveIcon()
+
+        val rendered = icon.toIntrinsicBitmap()
+        val masked = (72.0f * density + 0.5f).toInt()
+        assertEquals(masked, rendered.width)
+        assertEquals(masked, rendered.height)
+        // Grab a pixel from the middle to ensure we are not being masked.
+        assertEquals(Color.RED, rendered.getPixel(masked / 2, masked / 2))
+    }
+
+    @Test fun fromBitmap() {
+        val bitmap = createBitmap(1, 1).apply {
+            eraseColor(Color.RED)
+        }
+        val icon = bitmap.toIcon()
+
+        val rendered = icon.toIntrinsicBitmap()
+        assertEquals(1, rendered.width)
+        assertEquals(1, rendered.height)
+        assertEquals(Color.RED, rendered.getPixel(0, 0))
+    }
+
+    @Test fun fromUri() {
+        // Icon can't read from file:///android_asset/red.png so copy to a real file.
+        val cacheFile = File(context.cacheDir, "red.png")
+        context.assets.open("red.png").use { cacheFile.writeBytes(it.readBytes()) }
+
+        val uri = cacheFile.toUri()
+        val icon = uri.toIcon()
+
+        val rendered = icon.toIntrinsicBitmap()
+        assertEquals(1, rendered.width)
+        assertEquals(1, rendered.height)
+        assertEquals(Color.RED, rendered.getPixel(0, 0))
+    }
+
+    @Test fun fromByteArray() {
+        val bytes = context.assets.open("red.png").use { it.readBytes() }
+        val icon = bytes.toIcon()
+
+        val rendered = icon.toIntrinsicBitmap()
+        assertEquals(1, rendered.width)
+        assertEquals(1, rendered.height)
+        assertEquals(Color.RED, rendered.getPixel(0, 0))
+    }
+
+    private fun Icon.toIntrinsicBitmap(): Bitmap {
+        val drawable = loadDrawable(context)
+        val bitmap = createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight)
+        drawable.setBounds(0, 0, drawable.intrinsicHeight, drawable.intrinsicHeight)
+        drawable.draw(Canvas(bitmap))
+        return bitmap
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/net/UriTest.kt b/core/ktx/src/androidTest/java/androidx/core/net/UriTest.kt
new file mode 100644
index 0000000..d25de35
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/net/UriTest.kt
@@ -0,0 +1,39 @@
+/*
+ * 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 androidx.core.net
+
+import android.net.Uri
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import java.io.File
+
+class UriTest {
+    @Test fun uriFromString() {
+        val string = "https://test.example.com/foo?bar#baz"
+        assertEquals(Uri.parse(string), string.toUri())
+    }
+
+    @Test fun uriFromFile() {
+        val file = File("/path/to/my/file")
+        assertEquals(Uri.fromFile(file), file.toUri())
+    }
+
+    @Test fun fileFromUri() {
+        val uri = Uri.parse("path/to/my/file")
+        assertEquals(File(uri.path), uri.toFile())
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/os/BundleTest.kt b/core/ktx/src/androidTest/java/androidx/core/os/BundleTest.kt
new file mode 100644
index 0000000..924e9ad
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/os/BundleTest.kt
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.os
+
+import android.graphics.Rect
+import android.os.Binder
+import android.os.Bundle
+import android.support.test.InstrumentationRegistry
+import android.support.test.filters.SdkSuppress
+import android.util.Size
+import android.util.SizeF
+import android.view.View
+import androidx.testutils.assertThrows
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertArrayEquals
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertSame
+import org.junit.Test
+import java.util.concurrent.atomic.AtomicInteger
+
+class BundleTest {
+    @Test fun bundleOfValid() {
+        val bundleValue = Bundle()
+        val charSequenceValue = "hey"
+        val parcelableValue = Rect(1, 2, 3, 4)
+        val serializableValue = AtomicInteger(1)
+
+        val bundle = bundleOf(
+            "null" to null,
+
+            "boolean" to true,
+            "byte" to 1.toByte(),
+            "char" to 'a',
+            "double" to 1.0,
+            "float" to 1f,
+            "int" to 1,
+            "long" to 1L,
+            "short" to 1.toShort(),
+
+            "bundle" to bundleValue,
+            "charSequence" to charSequenceValue,
+            "parcelable" to parcelableValue,
+
+            "booleanArray" to booleanArrayOf(),
+            "byteArray" to byteArrayOf(),
+            "charArray" to charArrayOf(),
+            "doubleArray" to doubleArrayOf(),
+            "floatArray" to floatArrayOf(),
+            "intArray" to intArrayOf(),
+            "longArray" to longArrayOf(),
+            "shortArray" to shortArrayOf(),
+
+            "parcelableArray" to arrayOf(parcelableValue),
+            "stringArray" to arrayOf("hey"),
+            "charSequenceArray" to arrayOf<CharSequence>("hey"),
+            "serializableArray" to arrayOf(serializableValue),
+
+            "serializable" to serializableValue
+        )
+
+        assertEquals(25, bundle.size())
+
+        assertNull(bundle["null"])
+
+        assertEquals(true, bundle["boolean"])
+        assertEquals(1.toByte(), bundle["byte"])
+        assertEquals('a', bundle["char"])
+        assertEquals(1.0, bundle["double"])
+        assertEquals(1f, bundle["float"])
+        assertEquals(1, bundle["int"])
+        assertEquals(1L, bundle["long"])
+        assertEquals(1.toShort(), bundle["short"])
+
+        assertSame(bundleValue, bundle["bundle"])
+        assertSame(charSequenceValue, bundle["charSequence"])
+        assertSame(parcelableValue, bundle["parcelable"])
+
+        assertArrayEquals(booleanArrayOf(), bundle["booleanArray"] as BooleanArray)
+        assertArrayEquals(byteArrayOf(), bundle["byteArray"] as ByteArray)
+        assertArrayEquals(charArrayOf(), bundle["charArray"] as CharArray)
+        assertArrayEquals(doubleArrayOf(), bundle["doubleArray"] as DoubleArray, 0.0)
+        assertArrayEquals(floatArrayOf(), bundle["floatArray"] as FloatArray, 0f)
+        assertArrayEquals(intArrayOf(), bundle["intArray"] as IntArray)
+        assertArrayEquals(longArrayOf(), bundle["longArray"] as LongArray)
+        assertArrayEquals(shortArrayOf(), bundle["shortArray"] as ShortArray)
+
+        assertThat(bundle["parcelableArray"] as Array<*>).asList().containsExactly(parcelableValue)
+        assertThat(bundle["stringArray"] as Array<*>).asList().containsExactly("hey")
+        assertThat(bundle["charSequenceArray"] as Array<*>).asList().containsExactly("hey")
+        assertThat(bundle["serializableArray"] as Array<*>).asList()
+            .containsExactly(serializableValue)
+
+        assertSame(serializableValue, bundle["serializable"])
+    }
+
+    @SdkSuppress(minSdkVersion = 18)
+    @Test fun bundleOfValidApi18() {
+        val binderValue = Binder()
+        val bundle = bundleOf("binder" to binderValue)
+        assertSame(binderValue, bundle["binder"])
+    }
+
+    @SdkSuppress(minSdkVersion = 21)
+    @Test fun bundleOfValidApi21() {
+        val sizeValue = Size(1, 1)
+        val sizeFValue = SizeF(1f, 1f)
+
+        val bundle = bundleOf(
+            "size" to sizeValue,
+            "sizeF" to sizeFValue
+        )
+
+        assertSame(sizeValue, bundle["size"])
+        assertSame(sizeFValue, bundle["sizeF"])
+    }
+
+    @Test fun bundleOfInvalid() {
+        assertThrows<IllegalArgumentException> {
+            bundleOf("nope" to View(InstrumentationRegistry.getContext()))
+        }.hasMessageThat().isEqualTo("Illegal value type android.view.View for key \"nope\"")
+
+        assertThrows<IllegalArgumentException> {
+            bundleOf("nopes" to arrayOf(View(InstrumentationRegistry.getContext())))
+        }.hasMessageThat().isEqualTo("Illegal value array type android.view.View for key \"nopes\"")
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/os/HandlerTest.kt b/core/ktx/src/androidTest/java/androidx/core/os/HandlerTest.kt
new file mode 100644
index 0000000..e0fdf4e
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/os/HandlerTest.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.os
+
+import android.os.Handler
+import android.os.HandlerThread
+import android.os.SystemClock
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeUnit.MILLISECONDS
+import java.util.concurrent.TimeUnit.SECONDS
+
+class HandlerTest {
+    private val handlerThread = HandlerThread("handler-test")
+    private lateinit var handler: Handler
+
+    @Before fun before() {
+        handlerThread.start()
+        handler = Handler(handlerThread.looper)
+    }
+
+    @After fun after() {
+        handlerThread.quit()
+    }
+
+    @Test fun postDelayedLambdaMillis() {
+        var called = 0
+        handler.postDelayed(10) {
+            called++
+        }
+
+        handler.await(20, MILLISECONDS)
+        assertEquals(1, called)
+    }
+
+    @Test fun postDelayedLambdaMillisRemoved() {
+        var called = 0
+        val runnable = handler.postDelayed(10) {
+            called++
+        }
+        handler.removeCallbacks(runnable)
+
+        handler.await(20, MILLISECONDS)
+        assertEquals(0, called)
+    }
+
+    @Test fun postAtTimeLambda() {
+        var called = 0
+        handler.postAtTime(SystemClock.uptimeMillis() + 10) {
+            called++
+        }
+
+        handler.await(20, MILLISECONDS)
+        assertEquals(1, called)
+    }
+
+    @Test fun postAtTimeLambdaRemoved() {
+        var called = 0
+        val runnable = handler.postAtTime(SystemClock.uptimeMillis() + 10) {
+            called++
+        }
+        handler.removeCallbacks(runnable)
+
+        handler.await(20, MILLISECONDS)
+        assertEquals(0, called)
+    }
+
+    @Test fun postAtTimeLambdaWithTokenRuns() {
+        val token = Any()
+        var called = 0
+        handler.postAtTime(SystemClock.uptimeMillis() + 10, token) {
+            called++
+        }
+
+        handler.await(20, MILLISECONDS)
+        assertEquals(1, called)
+    }
+
+    @Test fun postAtTimeLambdaWithTokenCancelWithToken() {
+        // This test uses the token to cancel the runnable as it's the only way we have to verify
+        // that the Runnable was actually posted with the token.
+
+        val token = Any()
+        var called = 0
+        handler.postAtTime(SystemClock.uptimeMillis() + 10, token) {
+            called++
+        }
+        handler.removeCallbacksAndMessages(token)
+
+        handler.await(20, MILLISECONDS)
+        assertEquals(0, called)
+    }
+
+    private fun Handler.await(amount: Long, unit: TimeUnit) {
+        val latch = CountDownLatch(1)
+        postDelayed(latch::countDown, unit.toMillis(amount))
+
+        // Wait up to 1s longer than desired to account for time skew.
+        val wait = unit.toMillis(amount) + SECONDS.toMillis(1)
+        assertTrue(latch.await(wait, MILLISECONDS))
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/os/PersistableBundleTest.kt b/core/ktx/src/androidTest/java/androidx/core/os/PersistableBundleTest.kt
new file mode 100644
index 0000000..8683155
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/os/PersistableBundleTest.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.os
+
+import android.support.test.InstrumentationRegistry
+import android.support.test.filters.SdkSuppress
+import android.view.View
+import androidx.testutils.assertThrows
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertArrayEquals
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Test
+
+@SdkSuppress(minSdkVersion = 21)
+class PersistableBundleTest {
+    @Test fun persistableBundleOfValid() {
+        val bundle = persistableBundleOf(
+            "null" to null,
+
+            "double" to 1.0,
+            "int" to 1,
+            "long" to 1L,
+
+            "string" to "hey",
+
+            "doubleArray" to doubleArrayOf(),
+            "intArray" to intArrayOf(),
+            "longArray" to longArrayOf(),
+
+            "stringArray" to arrayOf("hey")
+        )
+
+        assertEquals(9, bundle.size())
+
+        assertNull(bundle["null"])
+
+        assertEquals(1.0, bundle["double"])
+        assertEquals(1, bundle["int"])
+        assertEquals(1L, bundle["long"])
+
+        assertEquals("hey", bundle["string"])
+
+        assertArrayEquals(doubleArrayOf(), bundle["doubleArray"] as DoubleArray, 0.0)
+        assertArrayEquals(intArrayOf(), bundle["intArray"] as IntArray)
+        assertArrayEquals(longArrayOf(), bundle["longArray"] as LongArray)
+
+        assertThat(bundle["stringArray"] as Array<*>).asList().containsExactly("hey")
+    }
+
+    @SdkSuppress(minSdkVersion = 22)
+    @Test fun persistableBundleOfValidApi22() {
+        val bundle = persistableBundleOf(
+            "boolean" to true,
+            "booleanArray" to booleanArrayOf()
+        )
+
+        assertEquals(true, bundle["boolean"])
+        assertArrayEquals(booleanArrayOf(), bundle["booleanArray"] as BooleanArray)
+    }
+
+    @Test fun persistableBundleOfInvalid() {
+        assertThrows<IllegalArgumentException> {
+            persistableBundleOf("nope" to View(InstrumentationRegistry.getContext()))
+        }.hasMessageThat().isEqualTo("Illegal value type android.view.View for key \"nope\"")
+
+        assertThrows<IllegalArgumentException> {
+            persistableBundleOf("nopes" to arrayOf(View(InstrumentationRegistry.getContext())))
+        }.hasMessageThat().isEqualTo("Illegal value array type android.view.View for key \"nopes\"")
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/preference/PreferenceGroupTest.kt b/core/ktx/src/androidTest/java/androidx/core/preference/PreferenceGroupTest.kt
new file mode 100644
index 0000000..0653a28
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/preference/PreferenceGroupTest.kt
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.preference
+
+import android.preference.Preference
+import android.preference.PreferenceFragment
+import android.preference.PreferenceGroup
+import android.support.test.InstrumentationRegistry
+import android.support.test.rule.ActivityTestRule
+import androidx.core.TestPreferenceActivity
+import androidx.testutils.assertThrows
+import androidx.testutils.fail
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertSame
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+class PreferenceGroupTest {
+
+    @JvmField
+    @Rule
+    val rule = ActivityTestRule(TestPreferenceActivity::class.java)
+    private val context = InstrumentationRegistry.getContext()
+    private lateinit var preferenceGroup: PreferenceGroup
+
+    @Before fun setup() {
+        preferenceGroup = (rule
+            .activity
+            .fragmentManager
+            .findFragmentByTag(TestPreferenceActivity.TAG) as PreferenceFragment).preferenceScreen
+    }
+
+    @Test fun get() {
+        val key = "key"
+        val preference = Preference(context)
+        preference.key = key
+        preferenceGroup.addPreference(preference)
+        assertSame(preference, preferenceGroup[key])
+        assertSame(preference, preferenceGroup[0])
+    }
+
+    @Test fun contains() {
+        val preference = Preference(context)
+        assertFalse(preference in preferenceGroup)
+        assertTrue(preference !in preferenceGroup)
+        preferenceGroup.addPreference(preference)
+        assertFalse(preference !in preferenceGroup)
+        assertTrue(preference in preferenceGroup)
+        preferenceGroup.removePreference(preference)
+        assertFalse(preference in preferenceGroup)
+        assertTrue(preference !in preferenceGroup)
+    }
+
+    @Test fun plusAssign() {
+        assertEquals(0, preferenceGroup.preferenceCount)
+
+        val preference1 = Preference(context)
+        preferenceGroup += preference1
+        assertEquals(1, preferenceGroup.preferenceCount)
+        assertSame(preference1, preferenceGroup.getPreference(0))
+
+        val preference2 = Preference(context)
+        preferenceGroup += preference2
+        assertEquals(2, preferenceGroup.preferenceCount)
+        assertSame(preference2, preferenceGroup.getPreference(1))
+    }
+
+    @Test fun minusAssign() {
+        val preference1 = Preference(context)
+        preferenceGroup.addPreference(preference1)
+        val preference2 = Preference(context)
+        preferenceGroup.addPreference(preference2)
+
+        assertEquals(2, preferenceGroup.preferenceCount)
+
+        preferenceGroup -= preference2
+        assertEquals(1, preferenceGroup.preferenceCount)
+        assertSame(preference1, preferenceGroup.getPreference(0))
+
+        preferenceGroup -= preference1
+        assertEquals(0, preferenceGroup.preferenceCount)
+    }
+
+    @Test fun size() {
+        assertEquals(0, preferenceGroup.size)
+
+        val preference = Preference(context)
+        preferenceGroup.addPreference(preference)
+        assertEquals(1, preferenceGroup.size)
+
+        preferenceGroup.removePreference(preference)
+        assertEquals(0, preferenceGroup.size)
+    }
+
+    @Test fun isEmpty() {
+        assertTrue(preferenceGroup.isEmpty())
+        preferenceGroup.addPreference(Preference(context))
+        assertFalse(preferenceGroup.isEmpty())
+    }
+
+    @Test fun isNotEmpty() {
+        assertFalse(preferenceGroup.isNotEmpty())
+        preferenceGroup.addPreference(Preference(context))
+        assertTrue(preferenceGroup.isNotEmpty())
+    }
+
+    @Test fun forEach() {
+        preferenceGroup.forEach {
+            fail("Empty preference group should not invoke lambda")
+        }
+
+        val preference1 = Preference(context).apply { key = "ASD" }
+        preferenceGroup.addPreference(preference1)
+        val preference2 = Preference(context)
+        preferenceGroup.addPreference(preference2)
+
+        val preferences = mutableListOf<Preference>()
+        preferenceGroup.forEach {
+            preferences += it
+        }
+        assertThat(preferences).containsExactly(preference1, preference2)
+    }
+
+    @Test fun forEachIndexed() {
+        preferenceGroup.forEach {
+            fail("Empty preference group should not invoke lambda")
+        }
+
+        val preference1 = Preference(context)
+        preferenceGroup.addPreference(preference1)
+        val preference2 = Preference(context)
+        preferenceGroup.addPreference(preference2)
+
+        val preferences = mutableListOf<Preference>()
+        preferenceGroup.forEachIndexed { index, preference ->
+            assertEquals(index, preferences.size)
+            preferences += preference
+        }
+        assertThat(preferences).containsExactly(preference1, preference2)
+    }
+
+    @Test fun iterator() {
+        val preference1 = Preference(context)
+        preferenceGroup.addPreference(preference1)
+        val preference2 = Preference(context)
+        preferenceGroup.addPreference(preference2)
+
+        val iterator = preferenceGroup.iterator()
+        assertTrue(iterator.hasNext())
+        assertSame(preference1, iterator.next())
+        assertTrue(iterator.hasNext())
+        assertSame(preference2, iterator.next())
+        assertFalse(iterator.hasNext())
+        assertThrows<IndexOutOfBoundsException> {
+            iterator.next()
+        }
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/text/CharSequenceTest.kt b/core/ktx/src/androidTest/java/androidx/core/text/CharSequenceTest.kt
new file mode 100644
index 0000000..0ce0a3c
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/text/CharSequenceTest.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.text
+
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class CharSequenceTest {
+    @Test fun isDigitsOnly() {
+        assertTrue("012345".isDigitsOnly())
+        assertFalse("0123 abc".isDigitsOnly())
+    }
+
+    @Test fun trimmedLength() {
+        assertEquals(6, "string    ".trimmedLength())
+        assertEquals(6, "    string".trimmedLength())
+        assertEquals(6, "string".trimmedLength())
+        assertEquals(0, "".trimmedLength())
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/text/HtmlTest.kt b/core/ktx/src/androidTest/java/androidx/core/text/HtmlTest.kt
new file mode 100644
index 0000000..0fef5ed
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/text/HtmlTest.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.text
+
+import android.text.Html.FROM_HTML_MODE_COMPACT
+import android.text.Html.ImageGetter
+import android.text.Html.TagHandler
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class HtmlTest {
+    private val imageGetter = ImageGetter { null }
+    private val tagHandler = TagHandler { _, _, _, _ -> }
+
+    @Test fun parseAsHtml() {
+        val parsed = "<b>Hi</b> © > <".parseAsHtml().toString()
+        assertEquals("Hi \u00a9 > <", parsed)
+    }
+
+    @Test fun parseAsHtmlFlags() {
+        val parsed = "<b>Hi</b> © > <".parseAsHtml(FROM_HTML_MODE_COMPACT).toString()
+        assertEquals("Hi \u00a9 > <", parsed)
+    }
+
+    @Test fun parseAsHtmlImageGetterTagHandler() {
+        val parsed = "<b>Hi</b> © > <"
+            .parseAsHtml(FROM_HTML_MODE_COMPACT, imageGetter, tagHandler)
+            .toString()
+        assertEquals("Hi \u00a9 > <", parsed)
+    }
+
+    @Test fun parseAsHtmlFlagsImageGetterTagHandler() {
+        val parsed = "<b>Hi</b> © > <"
+            .parseAsHtml(imageGetter = imageGetter, tagHandler = tagHandler)
+            .toString()
+        assertEquals("Hi \u00a9 > <", parsed)
+    }
+
+    @Test fun convertToHtml() {
+        val html = buildSpannedString {
+            bold {
+                append("Hi")
+            }
+        }.toHtml()
+        assertTrue(html, html.contains("<b>Hi</b>"))
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/text/SpannableStringBuilderTest.kt b/core/ktx/src/androidTest/java/androidx/core/text/SpannableStringBuilderTest.kt
new file mode 100644
index 0000000..5d67e83
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/text/SpannableStringBuilderTest.kt
@@ -0,0 +1,267 @@
+/*
+ * 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 androidx.core.text
+
+import android.graphics.Color.RED
+import android.graphics.Color.YELLOW
+import android.graphics.Typeface.BOLD
+import android.graphics.Typeface.ITALIC
+import android.text.SpannedString
+import android.text.style.BackgroundColorSpan
+import android.text.style.BulletSpan
+import android.text.style.ForegroundColorSpan
+import android.text.style.RelativeSizeSpan
+import android.text.style.StrikethroughSpan
+import android.text.style.StyleSpan
+import android.text.style.SubscriptSpan
+import android.text.style.SuperscriptSpan
+import android.text.style.UnderlineSpan
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertSame
+import org.junit.Test
+
+class SpannableStringBuilderTest {
+    @Test fun builder() {
+        val result: SpannedString = buildSpannedString {
+            append("Hello,")
+            append(" World")
+        }
+        assertEquals("Hello, World", result.toString())
+    }
+
+    @Test fun builderInSpan() {
+        val bold = StyleSpan(BOLD)
+        val result: SpannedString = buildSpannedString {
+            append("Hello, ")
+            inSpans(bold) {
+                append("World")
+            }
+        }
+        assertEquals("Hello, World", result.toString())
+
+        val spans = result.getSpans<Any>()
+        assertEquals(1, spans.size)
+
+        val boldSpan = spans.filterIsInstance<StyleSpan>().single()
+        assertSame(bold, boldSpan)
+        assertEquals(7, result.getSpanStart(bold))
+        assertEquals(12, result.getSpanEnd(bold))
+    }
+
+    @Test fun builderBold() {
+        val result: SpannedString = buildSpannedString {
+            append("Hello, ")
+            bold {
+                append("World")
+            }
+        }
+        assertEquals("Hello, World", result.toString())
+
+        val spans = result.getSpans<Any>()
+        assertEquals(1, spans.size)
+
+        val bold = spans.filterIsInstance<StyleSpan>().single()
+        assertEquals(BOLD, bold.style)
+        assertEquals(7, result.getSpanStart(bold))
+        assertEquals(12, result.getSpanEnd(bold))
+    }
+
+    @Test fun builderItalic() {
+        val result: SpannedString = buildSpannedString {
+            append("Hello, ")
+            italic {
+                append("World")
+            }
+        }
+        assertEquals("Hello, World", result.toString())
+
+        val spans = result.getSpans<Any>()
+        assertEquals(1, spans.size)
+
+        val italic = spans.filterIsInstance<StyleSpan>().single()
+        assertEquals(ITALIC, italic.style)
+        assertEquals(7, result.getSpanStart(italic))
+        assertEquals(12, result.getSpanEnd(italic))
+    }
+
+    @Test fun builderUnderline() {
+        val result: SpannedString = buildSpannedString {
+            append("Hello, ")
+            underline {
+                append("World")
+            }
+        }
+        assertEquals("Hello, World", result.toString())
+
+        val spans = result.getSpans<Any>()
+        assertEquals(1, spans.size)
+
+        val underline = spans.filterIsInstance<UnderlineSpan>().single()
+        assertEquals(7, result.getSpanStart(underline))
+        assertEquals(12, result.getSpanEnd(underline))
+    }
+
+    @Test fun builderColor() {
+        val result: SpannedString = buildSpannedString {
+            append("Hello, ")
+            color(RED) {
+                append("World")
+            }
+        }
+        assertEquals("Hello, World", result.toString())
+
+        val spans = result.getSpans<Any>()
+        assertEquals(1, spans.size)
+
+        val color = spans.filterIsInstance<ForegroundColorSpan>().single()
+        assertEquals(RED, color.foregroundColor)
+        assertEquals(7, result.getSpanStart(color))
+        assertEquals(12, result.getSpanEnd(color))
+    }
+
+    @Test fun builderBackgroundColor() {
+        val result: SpannedString = buildSpannedString {
+            append("Hello, ")
+            backgroundColor(RED) {
+                append("World")
+            }
+        }
+        assertEquals("Hello, World", result.toString())
+
+        val spans = result.getSpans<Any>()
+        assertEquals(1, spans.size)
+
+        val color = spans.filterIsInstance<BackgroundColorSpan>().single()
+        assertEquals(RED, color.backgroundColor)
+        assertEquals(7, result.getSpanStart(color))
+        assertEquals(12, result.getSpanEnd(color))
+    }
+
+    @Test fun builderStrikeThrough() {
+        val result: SpannedString = buildSpannedString {
+            append("Hello, ")
+            strikeThrough {
+                append("World")
+            }
+        }
+        assertEquals("Hello, World", result.toString())
+
+        val spans = result.getSpans<Any>()
+        assertEquals(1, spans.size)
+
+        val strikeThrough = spans.filterIsInstance<StrikethroughSpan>().single()
+        assertEquals(7, result.getSpanStart(strikeThrough))
+        assertEquals(12, result.getSpanEnd(strikeThrough))
+    }
+
+    @Test fun builderScale() {
+        val result: SpannedString = buildSpannedString {
+            append("Hello, ")
+            scale(2f) {
+                append("World")
+            }
+        }
+        assertEquals("Hello, World", result.toString())
+
+        val spans = result.getSpans<Any>()
+        assertEquals(1, spans.size)
+
+        val scale = spans.filterIsInstance<RelativeSizeSpan>().single()
+        assertEquals(2f, scale.sizeChange)
+        assertEquals(7, result.getSpanStart(scale))
+        assertEquals(12, result.getSpanEnd(scale))
+    }
+
+    @Test fun nested() {
+        val result: SpannedString = buildSpannedString {
+            color(RED) {
+                append('H')
+                inSpans(SubscriptSpan()) {
+                    append('e')
+                }
+                append('l')
+                inSpans(SuperscriptSpan()) {
+                    append('l')
+                }
+                append('o')
+            }
+            append(", ")
+            backgroundColor(YELLOW) {
+                append('W')
+                underline {
+                    append('o')
+                    bold {
+                        append('r')
+                    }
+                    append('l')
+                }
+                append('d')
+            }
+        }
+        assertEquals("Hello, World", result.toString())
+
+        val spans = result.getSpans<Any>()
+        assertEquals(6, spans.size)
+
+        val color = spans.filterIsInstance<ForegroundColorSpan>().single()
+        assertEquals(RED, color.foregroundColor)
+        assertEquals(0, result.getSpanStart(color))
+        assertEquals(5, result.getSpanEnd(color))
+
+        val subscript = spans.filterIsInstance<SubscriptSpan>().single()
+        assertEquals(1, result.getSpanStart(subscript))
+        assertEquals(2, result.getSpanEnd(subscript))
+
+        val superscript = spans.filterIsInstance<SuperscriptSpan>().single()
+        assertEquals(3, result.getSpanStart(superscript))
+        assertEquals(4, result.getSpanEnd(superscript))
+
+        val backgroundColor = spans.filterIsInstance<BackgroundColorSpan>().single()
+        assertEquals(YELLOW, backgroundColor.backgroundColor)
+        assertEquals(7, result.getSpanStart(backgroundColor))
+        assertEquals(12, result.getSpanEnd(backgroundColor))
+
+        val underline = spans.filterIsInstance<UnderlineSpan>().single()
+        assertEquals(8, result.getSpanStart(underline))
+        assertEquals(11, result.getSpanEnd(underline))
+
+        val bold = spans.filterIsInstance<StyleSpan>().single()
+        assertEquals(BOLD, bold.style)
+        assertEquals(9, result.getSpanStart(bold))
+        assertEquals(10, result.getSpanEnd(bold))
+    }
+
+    @Test fun multipleSpans() {
+        val result: SpannedString = buildSpannedString {
+            append("Hello, ")
+            inSpans(BulletSpan(), UnderlineSpan()) {
+                append("World")
+            }
+        }
+        assertEquals("Hello, World", result.toString())
+
+        val spans = result.getSpans<Any>()
+        assertEquals(2, spans.size)
+
+        val bullet = spans.filterIsInstance<BulletSpan>().single()
+        assertEquals(7, result.getSpanStart(bullet))
+        assertEquals(12, result.getSpanEnd(bullet))
+        val underline = spans.filterIsInstance<UnderlineSpan>().single()
+        assertEquals(7, result.getSpanStart(underline))
+        assertEquals(12, result.getSpanEnd(underline))
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/text/SpannableStringTest.kt b/core/ktx/src/androidTest/java/androidx/core/text/SpannableStringTest.kt
new file mode 100644
index 0000000..5fe3c5d
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/text/SpannableStringTest.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.text
+
+import android.graphics.Typeface.BOLD
+import android.text.SpannableString
+import android.text.style.StyleSpan
+import android.text.style.UnderlineSpan
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class SpannableStringTest {
+
+    @Test fun toSpannableString() = assertTrue("Hello, World".toSpannable() is SpannableString)
+
+    @Test fun plusAssign() {
+        val s = "Hello, World".toSpannable()
+
+        val bold = StyleSpan(BOLD)
+        s += bold
+        assertEquals(0, s.getSpanStart(bold))
+        assertEquals(s.length, s.getSpanEnd(bold))
+    }
+
+    @Test fun minusAssign() {
+        val s = "Hello, World".toSpannable()
+        val bold = StyleSpan(BOLD)
+        s += bold
+        assertTrue(s.getSpans<Any>().isNotEmpty())
+        s -= bold
+        assertTrue(s.getSpans<Any>().isEmpty())
+    }
+
+    @Test fun clearSpans() {
+        val s = "Hello, World".toSpannable()
+        s += StyleSpan(BOLD)
+        s += UnderlineSpan()
+        assertTrue(s.getSpans<Any>().isNotEmpty())
+        s.clearSpans()
+        assertTrue(s.getSpans<Any>().isEmpty())
+    }
+
+    @Test fun setIndices() {
+        val s = "Hello, World".toSpannable()
+        s[0, 5] = StyleSpan(BOLD)
+        s[7, 12] = UnderlineSpan()
+
+        val spans = s.getSpans<Any>()
+
+        val bold = spans.filterIsInstance<StyleSpan>().single()
+        assertEquals(0, s.getSpanStart(bold))
+        assertEquals(5, s.getSpanEnd(bold))
+
+        val underline = spans.filterIsInstance<UnderlineSpan>().single()
+        assertEquals(7, s.getSpanStart(underline))
+        assertEquals(12, s.getSpanEnd(underline))
+    }
+
+    @Test fun setRange() {
+        val s = "Hello, World".toSpannable()
+        s[0..5] = StyleSpan(BOLD)
+        s[7..12] = UnderlineSpan()
+
+        val spans = s.getSpans<Any>()
+
+        val bold = spans.filterIsInstance<StyleSpan>().single()
+        assertEquals(0, s.getSpanStart(bold))
+        assertEquals(5, s.getSpanEnd(bold))
+
+        val underline = spans.filterIsInstance<UnderlineSpan>().single()
+        assertEquals(7, s.getSpanStart(underline))
+        assertEquals(12, s.getSpanEnd(underline))
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/text/SpannedStringTest.kt b/core/ktx/src/androidTest/java/androidx/core/text/SpannedStringTest.kt
new file mode 100644
index 0000000..cb8930a
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/text/SpannedStringTest.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.text
+
+import android.graphics.Typeface.BOLD
+import android.text.Spanned.SPAN_INCLUSIVE_EXCLUSIVE
+import android.text.SpannedString
+import android.text.style.StyleSpan
+import android.text.style.UnderlineSpan
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertSame
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class SpannedStringTest {
+
+    @Test fun toSpanned() = assertTrue("Hello, World".toSpanned() is SpannedString)
+
+    @Test fun getSpans() {
+        val bold = StyleSpan(BOLD)
+        val underline = UnderlineSpan()
+
+        val s = "Hello, World".toSpannable()
+        s.setSpan(bold, 0, 5, SPAN_INCLUSIVE_EXCLUSIVE)
+        s.setSpan(underline, 7, 12, SPAN_INCLUSIVE_EXCLUSIVE)
+
+        assertSame(bold, s.getSpans<StyleSpan>().single())
+        assertSame(underline, s.getSpans<UnderlineSpan>().single())
+        assertEquals(s.getSpans<Any>().size, 2)
+
+        assertSame(bold, s.getSpans<Any>(0, 6).single())
+        assertSame(underline, s.getSpans<Any>(6, 12).single())
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/text/StringTest.kt b/core/ktx/src/androidTest/java/androidx/core/text/StringTest.kt
new file mode 100644
index 0000000..2812799
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/text/StringTest.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.text
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class StringTest {
+    @Test fun htmlEncode() {
+        assertEquals("&lt;&gt; &amp; &quot; &#39;", """<> & " '""".htmlEncode())
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/transition/TransitionTest.kt b/core/ktx/src/androidTest/java/androidx/core/transition/TransitionTest.kt
new file mode 100644
index 0000000..c3a2d22
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/transition/TransitionTest.kt
@@ -0,0 +1,95 @@
+/*
+ * 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 androidx.core.transition
+
+import android.support.test.InstrumentationRegistry
+import android.support.test.filters.SdkSuppress
+import android.support.test.rule.ActivityTestRule
+import android.transition.Fade
+import android.transition.Transition
+import android.transition.TransitionManager
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import androidx.core.TestActivity
+import androidx.core.ktx.test.R
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.atomic.AtomicBoolean
+
+@SdkSuppress(minSdkVersion = 19)
+class TransitionTest {
+    @JvmField @Rule val rule = ActivityTestRule<TestActivity>(TestActivity::class.java)
+
+    private lateinit var transition: Transition
+
+    @Before fun setup() {
+        transition = Fade().setDuration(50)
+    }
+
+    @Test fun testDoOnStart() {
+        val called = AtomicBoolean()
+        transition.doOnStart {
+            called.set(true)
+        }
+
+        startTransition(transition)
+        assertTrue(called.get())
+    }
+
+    @Test fun testDoOnEnd() {
+        val called = AtomicBoolean()
+        transition.doOnEnd {
+            called.set(true)
+        }
+
+        val latch = CountDownLatch(1)
+        transition.addListener(object : Transition.TransitionListener {
+            override fun onTransitionEnd(transition: Transition?) {
+                latch.countDown()
+            }
+
+            override fun onTransitionResume(transition: Transition?) = Unit
+            override fun onTransitionPause(transition: Transition?) = Unit
+            override fun onTransitionCancel(transition: Transition?) = Unit
+            override fun onTransitionStart(transition: Transition?) = Unit
+        })
+
+        startTransition(transition)
+
+        assertTrue(latch.await(1, TimeUnit.SECONDS))
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+
+        assertTrue(called.get())
+    }
+
+    private fun startTransition(t: Transition) {
+        rule.runOnUiThread {
+            val sceneRoot = rule.activity.findViewById<ViewGroup>(R.id.root)
+            val view = rule.activity.findViewById<ImageView>(R.id.image_view)
+
+            TransitionManager.beginDelayedTransition(sceneRoot, t)
+
+            view.visibility = View.INVISIBLE
+        }
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/util/ArrayMapTest.kt b/core/ktx/src/androidTest/java/androidx/core/util/ArrayMapTest.kt
new file mode 100644
index 0000000..5eddef2
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/util/ArrayMapTest.kt
@@ -0,0 +1,40 @@
+/*
+ * 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 androidx.core.util
+
+import android.support.test.filters.SdkSuppress
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+@SdkSuppress(minSdkVersion = 19)
+class ArrayMapTest {
+    @Test fun empty() {
+        val map = arrayMapOf<String, String>()
+        assertEquals(0, map.size)
+    }
+
+    @Test fun nonEmpty() {
+        val map = arrayMapOf("foo" to "bar", "bar" to "baz")
+        assertThat(map).containsExactly("foo", "bar", "bar", "baz")
+    }
+
+    @Test fun duplicateKeyKeepsLast() {
+        val map = arrayMapOf("foo" to "bar", "foo" to "baz")
+        assertThat(map).containsExactly("foo", "baz")
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/util/ArraySetTest.kt b/core/ktx/src/androidTest/java/androidx/core/util/ArraySetTest.kt
new file mode 100644
index 0000000..934f18c
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/util/ArraySetTest.kt
@@ -0,0 +1,35 @@
+/*
+ * 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 androidx.core.util
+
+import android.support.test.filters.SdkSuppress
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+@SdkSuppress(minSdkVersion = 23)
+class ArraySetTest {
+    @Test fun empty() {
+        val set = arraySetOf<String>()
+        assertEquals(0, set.size)
+    }
+
+    @Test fun nonEmpty() {
+        val set = arraySetOf("foo", "bar", "baz")
+        assertThat(set).containsExactly("foo", "bar", "baz")
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/util/AtomicFileTest.kt b/core/ktx/src/androidTest/java/androidx/core/util/AtomicFileTest.kt
new file mode 100644
index 0000000..59fc8d9
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/util/AtomicFileTest.kt
@@ -0,0 +1,109 @@
+/*
+ * 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 androidx.core.util
+
+import android.support.test.filters.SdkSuppress
+import android.util.AtomicFile
+import androidx.testutils.assertThrows
+import org.junit.Assert.assertArrayEquals
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TemporaryFolder
+import java.io.IOException
+
+@SdkSuppress(minSdkVersion = 17)
+class AtomicFileTest {
+    @get:Rule val temporaryFolder = TemporaryFolder()
+
+    private lateinit var file: AtomicFile
+
+    @Before fun before() {
+        file = AtomicFile(temporaryFolder.newFile())
+    }
+
+    @Test fun tryWriteSuccess() {
+        file.tryWrite {
+            it.write(byteArrayOf(0, 1, 2))
+        }
+        val bytes = file.openRead().use { it.readBytes() }
+        assertArrayEquals(byteArrayOf(0, 1, 2), bytes)
+    }
+
+    @Test fun tryWriteFail() {
+        val os = file.startWrite()
+        os.write(byteArrayOf(0, 1, 2))
+        file.finishWrite(os)
+
+        val failure = IOException("Broken!")
+        assertThrows<IOException> {
+            file.tryWrite {
+                it.write(byteArrayOf(3, 4, 5))
+                throw failure
+            }
+        }.isSameAs(failure)
+
+        val bytes = file.openRead().use { it.readBytes() }
+        assertArrayEquals(byteArrayOf(0, 1, 2), bytes)
+    }
+
+    @Test fun writeBytes() {
+        file.writeBytes(byteArrayOf(0, 1, 2))
+
+        val bytes = file.openRead().use { it.readBytes() }
+        assertArrayEquals(byteArrayOf(0, 1, 2), bytes)
+    }
+
+    @Test fun writeText() {
+        file.writeText("Hey")
+
+        val bytes = file.openRead().use { it.readBytes() }
+        assertArrayEquals(byteArrayOf(72, 101, 121), bytes)
+    }
+
+    @Test fun writeTextCharset() {
+        file.writeText("Hey", charset = Charsets.UTF_16LE)
+
+        val bytes = file.openRead().use { it.readBytes() }
+        assertArrayEquals(byteArrayOf(72, 0, 101, 0, 121, 0), bytes)
+    }
+
+    @Test fun readBytes() {
+        val os = file.startWrite()
+        os.write(byteArrayOf(0, 1, 2))
+        file.finishWrite(os)
+
+        assertArrayEquals(byteArrayOf(0, 1, 2), file.readBytes())
+    }
+
+    @Test fun readText() {
+        val os = file.startWrite()
+        os.write(byteArrayOf(72, 101, 121))
+        file.finishWrite(os)
+
+        assertEquals("Hey", file.readText())
+    }
+
+    @Test fun readTextCharset() {
+        val os = file.startWrite()
+        os.write(byteArrayOf(72, 0, 101, 0, 121, 0))
+        file.finishWrite(os)
+
+        assertEquals("Hey", file.readText(charset = Charsets.UTF_16LE))
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/util/HalfTest.kt b/core/ktx/src/androidTest/java/androidx/core/util/HalfTest.kt
new file mode 100644
index 0000000..b79e064
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/util/HalfTest.kt
@@ -0,0 +1,33 @@
+/*
+ * 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 androidx.core.util
+
+import android.support.test.filters.SdkSuppress
+import android.util.Half
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+@SdkSuppress(minSdkVersion = 26)
+class HalfTest {
+    @Test fun shortToHalf() = assertEquals(Half(1.toShort()), 1.toShort().toHalf())
+
+    @Test fun floatToHalf() = assertEquals(Half(1f), 1f.toHalf())
+
+    @Test fun doubleToHalf() = assertEquals(Half(1.0), 1.0.toHalf())
+
+    @Test fun stringToHalf() = assertEquals(Half("1"), "1".toHalf())
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/util/LocaleTest.kt b/core/ktx/src/androidTest/java/androidx/core/util/LocaleTest.kt
new file mode 100644
index 0000000..0a345f0
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/util/LocaleTest.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.util
+
+import android.view.View
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import java.util.Locale
+
+class LocaleTest {
+    @Test fun layoutDirectionWithLTR() {
+        val ltrLocale = Locale.Builder().setLanguage("en").build()
+        assertEquals(View.LAYOUT_DIRECTION_LTR, ltrLocale.layoutDirection)
+    }
+
+    @Test fun layoutDirectionWithRTL() {
+        val rtlLocale = Locale.Builder().setLanguage("ar").build()
+        assertEquals(View.LAYOUT_DIRECTION_RTL, rtlLocale.layoutDirection)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/util/LongSparseArrayTest.kt b/core/ktx/src/androidTest/java/androidx/core/util/LongSparseArrayTest.kt
new file mode 100644
index 0000000..c2289e6
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/util/LongSparseArrayTest.kt
@@ -0,0 +1,200 @@
+/*
+ * 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 androidx.core.util
+
+import android.support.test.filters.SdkSuppress
+import android.util.LongSparseArray
+import androidx.testutils.fail
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertSame
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+@SdkSuppress(minSdkVersion = 16)
+class LongSparseArrayTest {
+    @Test fun sizeProperty() {
+        val array = LongSparseArray<String>()
+        assertEquals(0, array.size)
+        array.put(1L, "one")
+        assertEquals(1, array.size)
+    }
+
+    @Test fun containsOperator() {
+        val array = LongSparseArray<String>()
+        assertFalse(1L in array)
+        array.put(1L, "one")
+        assertTrue(1L in array)
+    }
+
+    @Test fun containsOperatorWithValue() {
+        val array = LongSparseArray<String>()
+
+        array.put(1L, "one")
+        assertFalse(2L in array)
+
+        array.put(2L, "two")
+        assertTrue(2L in array)
+    }
+
+    @Test fun setOperator() {
+        val array = LongSparseArray<String>()
+        array[1L] = "one"
+        assertEquals("one", array.get(1L))
+    }
+
+    @Test fun plusOperator() {
+        val first = LongSparseArray<String>().apply { put(1L, "one") }
+        val second = LongSparseArray<String>().apply { put(2L, "two") }
+        val combined = first + second
+        assertEquals(2, combined.size())
+        assertEquals(1L, combined.keyAt(0))
+        assertEquals("one", combined.valueAt(0))
+        assertEquals(2L, combined.keyAt(1))
+        assertEquals("two", combined.valueAt(1))
+    }
+
+    @Test fun containsKey() {
+        val array = LongSparseArray<String>()
+        assertFalse(array.containsKey(1L))
+        array.put(1L, "one")
+        assertTrue(array.containsKey(1L))
+    }
+
+    @Test fun containsKeyWithValue() {
+        val array = LongSparseArray<String>()
+
+        array.put(1L, "one")
+        assertFalse(array.containsKey(2L))
+
+        array.put(2L, "one")
+        assertTrue(array.containsKey(2L))
+    }
+
+    @Test fun containsValue() {
+        val array = LongSparseArray<String>()
+        assertFalse(array.containsValue("one"))
+        array.put(1L, "one")
+        assertTrue(array.containsValue("one"))
+    }
+
+    @Test fun getOrDefault() {
+        val array = LongSparseArray<Any>()
+        val default = Any()
+        assertSame(default, array.getOrDefault(1L, default))
+        array.put(1L, "one")
+        assertEquals("one", array.getOrDefault(1L, default))
+    }
+
+    @Test fun getOrElse() {
+        val array = LongSparseArray<Any>()
+        val default = Any()
+        assertSame(default, array.getOrElse(1L) { default })
+        array.put(1L, "one")
+        assertEquals("one", array.getOrElse(1L) { fail() })
+    }
+
+    @Test fun isEmpty() {
+        val array = LongSparseArray<String>()
+        assertTrue(array.isEmpty())
+        array.put(1L, "one")
+        assertFalse(array.isEmpty())
+    }
+
+    @Test fun isNotEmpty() {
+        val array = LongSparseArray<String>()
+        assertFalse(array.isNotEmpty())
+        array.put(1L, "one")
+        assertTrue(array.isNotEmpty())
+    }
+
+    @Test fun removeValue() {
+        val array = LongSparseArray<String>()
+        array.put(1L, "one")
+        assertFalse(array.remove(0L, "one"))
+        assertEquals(1, array.size())
+        assertFalse(array.remove(1L, "two"))
+        assertEquals(1, array.size())
+        assertTrue(array.remove(1L, "one"))
+        assertEquals(0, array.size())
+    }
+
+    @Test fun putAll() {
+        val dest = LongSparseArray<String>()
+        val source = LongSparseArray<String>()
+        source.put(1L, "one")
+
+        assertEquals(0, dest.size())
+        dest.putAll(source)
+        assertEquals(1, dest.size())
+    }
+
+    @Test fun forEach() {
+        val array = LongSparseArray<String>()
+        array.forEach { _, _ -> fail() }
+
+        array.put(1L, "one")
+        array.put(2L, "two")
+        array.put(6L, "six")
+
+        val keys = mutableListOf<Long>()
+        val values = mutableListOf<String>()
+        array.forEach { key, value ->
+            keys.add(key)
+            values.add(value)
+        }
+        assertThat(keys).containsExactly(1L, 2L, 6L)
+        assertThat(values).containsExactly("one", "two", "six")
+    }
+
+    @Test fun keyIterator() {
+        val array = LongSparseArray<String>()
+        assertFalse(array.keyIterator().hasNext())
+
+        array.put(1L, "one")
+        array.put(2L, "two")
+        array.put(6L, "six")
+
+        val iterator = array.keyIterator()
+        assertTrue(iterator.hasNext())
+        assertEquals(1L, iterator.nextLong())
+        assertTrue(iterator.hasNext())
+        assertEquals(2L, iterator.nextLong())
+        assertTrue(iterator.hasNext())
+        assertEquals(6L, iterator.nextLong())
+        assertFalse(iterator.hasNext())
+    }
+
+    @Test fun valueIterator() {
+        val array = LongSparseArray<String>()
+        assertFalse(array.valueIterator().hasNext())
+
+        array.put(1L, "one")
+        array.put(2L, "two")
+        array.put(6L, "six")
+
+        val iterator = array.valueIterator()
+        assertTrue(iterator.hasNext())
+        assertEquals("one", iterator.next())
+        assertTrue(iterator.hasNext())
+        assertEquals("two", iterator.next())
+        assertTrue(iterator.hasNext())
+        assertEquals("six", iterator.next())
+        assertFalse(iterator.hasNext())
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/util/LruCacheTest.kt b/core/ktx/src/androidTest/java/androidx/core/util/LruCacheTest.kt
new file mode 100644
index 0000000..198e13d
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/util/LruCacheTest.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.util
+
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class LruCacheTest {
+    private data class TestData(val x: String = "bla")
+
+    @Test fun size() {
+        val cache = lruCache<String, TestData>(200, { k, (x) -> k.length * x.length })
+        cache.put("long", TestData())
+        assertEquals(cache.size(), 12)
+    }
+
+    @Test fun create() {
+        val cache = lruCache<String, TestData>(200, create = { key -> TestData("$key foo") })
+        assertEquals(cache.get("kung"), TestData("kung foo"))
+    }
+
+    @Test fun onEntryRemoved() {
+        var wasCalled = false
+
+        val cache = lruCache<String, TestData>(200, onEntryRemoved = { _, _, _, _ ->
+            wasCalled = true
+        })
+        val initial = TestData()
+        cache.put("a", initial)
+        cache.remove("a")
+        assertTrue(wasCalled)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/util/PairTest.kt b/core/ktx/src/androidTest/java/androidx/core/util/PairTest.kt
new file mode 100644
index 0000000..e3fac39
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/util/PairTest.kt
@@ -0,0 +1,50 @@
+/*
+ * 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 androidx.core.util
+
+import android.util.Pair
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertSame
+import org.junit.Test
+
+class PairTest {
+    @Test fun destructuringNonNull() {
+        val pair = Pair("one", "two")
+        val (first: String, second: String) = pair
+        assertSame(pair.first, first)
+        assertSame(pair.second, second)
+    }
+
+    @Test fun destructuringNullable() {
+        val pair = Pair("one", "two")
+        val (first: String?, second: String?) = pair
+        assertSame(pair.first, first)
+        assertSame(pair.second, second)
+    }
+
+    @Test fun toKotlin() {
+        val android = Pair("one", "two")
+        val kotlin = android.toKotlinPair()
+        assertEquals(android.first to android.second, kotlin)
+    }
+
+    @Test fun toAndroid() {
+        val kotlin = kotlin.Pair("one", "two")
+        val android = kotlin.toAndroidPair()
+        assertEquals(Pair(kotlin.first, kotlin.second), android)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/util/RangeTest.kt b/core/ktx/src/androidTest/java/androidx/core/util/RangeTest.kt
new file mode 100644
index 0000000..ec5d238
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/util/RangeTest.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.util
+
+import android.support.test.filters.SdkSuppress
+import android.util.Range
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+@SdkSuppress(minSdkVersion = 21)
+class RangeTest {
+    @Test fun infixFactory() {
+        val range: Range<String> = "a" rangeTo "c"
+        assertEquals("a", range.lower)
+        assertEquals("c", range.upper)
+    }
+
+    @Test fun extendValue() {
+        val range = ("a" rangeTo "c") + "e"
+        assertEquals("a", range.lower)
+        assertEquals("e", range.upper)
+    }
+
+    @Test fun extendRange() {
+        val range = ("a" rangeTo "c") + ("e" rangeTo "g")
+        assertEquals("a", range.lower)
+        assertEquals("g", range.upper)
+    }
+
+    @Test fun intersection() {
+        val range = ("a" rangeTo "e") and ("c" rangeTo "g")
+        assertEquals("c", range.lower)
+        assertEquals("e", range.upper)
+    }
+
+    @Test fun kotlinToAndroid() {
+        val range: Range<Int> = (1..3).toRange()
+        assertEquals(1, range.lower)
+        assertEquals(3, range.upper)
+    }
+
+    @Test fun androidToKotlin() {
+        val range: ClosedRange<String> = Range<String>("a", "c").toClosedRange()
+        assertEquals("a", range.start)
+        assertEquals("c", range.endInclusive)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/util/SizeTest.kt b/core/ktx/src/androidTest/java/androidx/core/util/SizeTest.kt
new file mode 100644
index 0000000..b38c747
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/util/SizeTest.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.util
+
+import android.support.test.filters.SdkSuppress
+import android.util.Size
+import android.util.SizeF
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+@SdkSuppress(minSdkVersion = 21)
+class SizeTest {
+    @Test fun destructuringSize() {
+        val (w, h) = Size(320, 240)
+        assertEquals(320, w)
+        assertEquals(240, h)
+    }
+
+    @Test fun destructuringSizeF() {
+        val (w, h) = SizeF(1920.0f, 1080.0f)
+        assertEquals(1920.0f, w)
+        assertEquals(1080.0f, h)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/util/SparseArrayTest.kt b/core/ktx/src/androidTest/java/androidx/core/util/SparseArrayTest.kt
new file mode 100644
index 0000000..4a49214
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/util/SparseArrayTest.kt
@@ -0,0 +1,188 @@
+/*
+ * 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 androidx.core.util
+
+import android.util.SparseArray
+import androidx.testutils.fail
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertSame
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class SparseArrayTest {
+    @Test fun sizeProperty() {
+        val array = SparseArray<String>()
+        assertEquals(0, array.size)
+        array.put(1, "one")
+        assertEquals(1, array.size)
+    }
+
+    @Test fun containsOperator() {
+        val array = SparseArray<String>()
+        assertFalse(1 in array)
+        array.put(1, "one")
+        assertTrue(1 in array)
+    }
+
+    @Test fun containsOperatorWithItem() {
+        val array = SparseArray<String>()
+
+        array.put(1, "one")
+        assertFalse(2 in array)
+
+        array.put(2, "two")
+        assertTrue(2 in array)
+    }
+
+    @Test fun setOperator() {
+        val array = SparseArray<String>()
+        array[1] = "one"
+        assertEquals("one", array.get(1))
+    }
+
+    @Test fun plusOperator() {
+        val first = SparseArray<String>().apply { put(1, "one") }
+        val second = SparseArray<String>().apply { put(2, "two") }
+        val combined = first + second
+        assertEquals(2, combined.size())
+        assertEquals(1, combined.keyAt(0))
+        assertEquals("one", combined.valueAt(0))
+        assertEquals(2, combined.keyAt(1))
+        assertEquals("two", combined.valueAt(1))
+    }
+
+    @Test fun containsKey() {
+        val array = SparseArray<String>()
+        assertFalse(array.containsKey(1))
+        array.put(1, "one")
+        assertTrue(array.containsKey(1))
+    }
+
+    @Test fun containsValue() {
+        val array = SparseArray<String>()
+        assertFalse(array.containsValue("one"))
+        array.put(1, "one")
+        assertTrue(array.containsValue("one"))
+    }
+
+    @Test fun getOrDefault() {
+        val array = SparseArray<Any>()
+        val default = Any()
+        assertSame(default, array.getOrDefault(1, default))
+        array.put(1, "one")
+        assertEquals("one", array.getOrDefault(1, default))
+    }
+
+    @Test fun getOrElse() {
+        val array = SparseArray<Any>()
+        val default = Any()
+        assertSame(default, array.getOrElse(1) { default })
+        array.put(1, "one")
+        assertEquals("one", array.getOrElse(1) { fail() })
+    }
+
+    @Test fun isEmpty() {
+        val array = SparseArray<String>()
+        assertTrue(array.isEmpty())
+        array.put(1, "one")
+        assertFalse(array.isEmpty())
+    }
+
+    @Test fun isNotEmpty() {
+        val array = SparseArray<String>()
+        assertFalse(array.isNotEmpty())
+        array.put(1, "one")
+        assertTrue(array.isNotEmpty())
+    }
+
+    @Test fun removeValue() {
+        val array = SparseArray<String>()
+        array.put(1, "one")
+        assertFalse(array.remove(0, "one"))
+        assertEquals(1, array.size())
+        assertFalse(array.remove(1, "two"))
+        assertEquals(1, array.size())
+        assertTrue(array.remove(1, "one"))
+        assertEquals(0, array.size())
+    }
+
+    @Test fun putAll() {
+        val dest = SparseArray<String>()
+        val source = SparseArray<String>()
+        source.put(1, "one")
+
+        assertEquals(0, dest.size())
+        dest.putAll(source)
+        assertEquals(1, dest.size())
+    }
+
+    @Test fun forEach() {
+        val array = SparseArray<String>()
+        array.forEach { _, _ -> fail() }
+
+        array.put(1, "one")
+        array.put(2, "two")
+        array.put(6, "six")
+
+        val keys = mutableListOf<Int>()
+        val values = mutableListOf<String>()
+        array.forEach { key, value ->
+            keys.add(key)
+            values.add(value)
+        }
+        assertThat(keys).containsExactly(1, 2, 6)
+        assertThat(values).containsExactly("one", "two", "six")
+    }
+
+    @Test fun keyIterator() {
+        val array = SparseArray<String>()
+        assertFalse(array.keyIterator().hasNext())
+
+        array.put(1, "one")
+        array.put(2, "two")
+        array.put(6, "six")
+
+        val iterator = array.keyIterator()
+        assertTrue(iterator.hasNext())
+        assertEquals(1, iterator.nextInt())
+        assertTrue(iterator.hasNext())
+        assertEquals(2, iterator.nextInt())
+        assertTrue(iterator.hasNext())
+        assertEquals(6, iterator.nextInt())
+        assertFalse(iterator.hasNext())
+    }
+
+    @Test fun valueIterator() {
+        val array = SparseArray<String>()
+        assertFalse(array.valueIterator().hasNext())
+
+        array.put(1, "one")
+        array.put(2, "two")
+        array.put(6, "six")
+
+        val iterator = array.valueIterator()
+        assertTrue(iterator.hasNext())
+        assertEquals("one", iterator.next())
+        assertTrue(iterator.hasNext())
+        assertEquals("two", iterator.next())
+        assertTrue(iterator.hasNext())
+        assertEquals("six", iterator.next())
+        assertFalse(iterator.hasNext())
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/util/SparseBooleanArrayTest.kt b/core/ktx/src/androidTest/java/androidx/core/util/SparseBooleanArrayTest.kt
new file mode 100644
index 0000000..1d67493
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/util/SparseBooleanArrayTest.kt
@@ -0,0 +1,195 @@
+/*
+ * 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 androidx.core.util
+
+import android.util.SparseBooleanArray
+import androidx.testutils.fail
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class SparseBooleanArrayTest {
+    @Test fun sizeProperty() {
+        val array = SparseBooleanArray()
+        assertEquals(0, array.size)
+        array.put(1, true)
+        assertEquals(1, array.size)
+    }
+
+    @Test fun containsOperator() {
+        val array = SparseBooleanArray()
+        assertFalse(1 in array)
+        array.put(1, true)
+        assertTrue(1 in array)
+    }
+
+    @Test fun containsOperatorWithValue() {
+        val array = SparseBooleanArray()
+
+        array.put(1, true)
+        assertFalse(2 in array)
+
+        array.put(2, true)
+        assertTrue(2 in array)
+    }
+
+    @Test fun setOperator() {
+        val array = SparseBooleanArray()
+        array[1] = true
+        assertTrue(array.get(1))
+    }
+
+    @Test fun plusOperator() {
+        val first = SparseBooleanArray().apply { put(1, true) }
+        val second = SparseBooleanArray().apply { put(2, false) }
+        val combined = first + second
+        assertEquals(2, combined.size())
+        assertEquals(1, combined.keyAt(0))
+        assertTrue(combined.valueAt(0))
+        assertEquals(2, combined.keyAt(1))
+        assertFalse(combined.valueAt(1))
+    }
+
+    @Test fun containsKey() {
+        val array = SparseBooleanArray()
+        assertFalse(array.containsKey(1))
+        array.put(1, true)
+        assertTrue(array.containsKey(1))
+    }
+
+    @Test fun containsKeyWithValue() {
+        val array = SparseBooleanArray()
+
+        array.put(1, true)
+        assertFalse(array.containsKey(2))
+
+        array.put(2, true)
+        assertTrue(array.containsKey(2))
+    }
+
+    @Test fun containsValue() {
+        val array = SparseBooleanArray()
+        assertFalse(array.containsValue(true))
+        array.put(1, true)
+        assertTrue(array.containsValue(true))
+    }
+
+    @Test fun getOrDefault() {
+        val array = SparseBooleanArray()
+        assertFalse(array.getOrDefault(1, false))
+        array.put(1, true)
+        assertTrue(array.getOrDefault(1, false))
+    }
+
+    @Test fun getOrElse() {
+        val array = SparseBooleanArray()
+        assertFalse(array.getOrElse(1) { false })
+        array.put(1, true)
+        assertTrue(array.getOrElse(1) { fail() })
+    }
+
+    @Test fun isEmpty() {
+        val array = SparseBooleanArray()
+        assertTrue(array.isEmpty())
+        array.put(1, true)
+        assertFalse(array.isEmpty())
+    }
+
+    @Test fun isNotEmpty() {
+        val array = SparseBooleanArray()
+        assertFalse(array.isNotEmpty())
+        array.put(1, true)
+        assertTrue(array.isNotEmpty())
+    }
+
+    @Test fun removeValue() {
+        val array = SparseBooleanArray()
+        array.put(1, true)
+        assertFalse(array.remove(0, true))
+        assertEquals(1, array.size())
+        assertFalse(array.remove(1, false))
+        assertEquals(1, array.size())
+        assertTrue(array.remove(1, true))
+        assertEquals(0, array.size())
+    }
+
+    @Test fun putAll() {
+        val dest = SparseBooleanArray()
+        val source = SparseBooleanArray()
+        source.put(1, true)
+
+        assertEquals(0, dest.size())
+        dest.putAll(source)
+        assertEquals(1, dest.size())
+    }
+
+    @Test fun forEach() {
+        val array = SparseBooleanArray()
+        array.forEach { _, _ -> fail() }
+
+        array.put(1, true)
+        array.put(2, false)
+        array.put(6, true)
+
+        val keys = mutableListOf<Int>()
+        val values = mutableListOf<Boolean>()
+        array.forEach { key, value ->
+            keys.add(key)
+            values.add(value)
+        }
+        assertThat(keys).containsExactly(1, 2, 6)
+        assertThat(values).containsExactly(true, false, true)
+    }
+
+    @Test fun keyIterator() {
+        val array = SparseBooleanArray()
+        assertFalse(array.keyIterator().hasNext())
+
+        array.put(1, true)
+        array.put(2, false)
+        array.put(6, true)
+
+        val iterator = array.keyIterator()
+        assertTrue(iterator.hasNext())
+        assertEquals(1, iterator.nextInt())
+        assertTrue(iterator.hasNext())
+        assertEquals(2, iterator.nextInt())
+        assertTrue(iterator.hasNext())
+        assertEquals(6, iterator.nextInt())
+        assertFalse(iterator.hasNext())
+    }
+
+    @Test fun valueIterator() {
+        val array = SparseBooleanArray()
+        assertFalse(array.valueIterator().hasNext())
+
+        array.put(1, true)
+        array.put(2, false)
+        array.put(6, true)
+
+        val iterator = array.valueIterator()
+        assertTrue(iterator.hasNext())
+        assertTrue(iterator.nextBoolean())
+        assertTrue(iterator.hasNext())
+        assertFalse(iterator.nextBoolean())
+        assertTrue(iterator.hasNext())
+        assertTrue(iterator.nextBoolean())
+        assertFalse(iterator.hasNext())
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/util/SparseIntArrayTest.kt b/core/ktx/src/androidTest/java/androidx/core/util/SparseIntArrayTest.kt
new file mode 100644
index 0000000..40794c1
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/util/SparseIntArrayTest.kt
@@ -0,0 +1,195 @@
+/*
+ * 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 androidx.core.util
+
+import android.util.SparseIntArray
+import androidx.testutils.fail
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class SparseIntArrayTest {
+    @Test fun sizeProperty() {
+        val array = SparseIntArray()
+        assertEquals(0, array.size)
+        array.put(1, 11)
+        assertEquals(1, array.size)
+    }
+
+    @Test fun containsOperator() {
+        val array = SparseIntArray()
+        assertFalse(1 in array)
+        array.put(1, 11)
+        assertTrue(1 in array)
+    }
+
+    @Test fun containsOperatorWithValue() {
+        val array = SparseIntArray()
+
+        array.put(1, 11)
+        assertFalse(2 in array)
+
+        array.put(2, 22)
+        assertTrue(2 in array)
+    }
+
+    @Test fun setOperator() {
+        val array = SparseIntArray()
+        array[1] = 11
+        assertEquals(11, array.get(1))
+    }
+
+    @Test fun plusOperator() {
+        val first = SparseIntArray().apply { put(1, 11) }
+        val second = SparseIntArray().apply { put(2, 22) }
+        val combined = first + second
+        assertEquals(2, combined.size())
+        assertEquals(1, combined.keyAt(0))
+        assertEquals(11, combined.valueAt(0))
+        assertEquals(2, combined.keyAt(1))
+        assertEquals(22, combined.valueAt(1))
+    }
+
+    @Test fun containsKey() {
+        val array = SparseIntArray()
+        assertFalse(array.containsKey(1))
+        array.put(1, 11)
+        assertTrue(array.containsKey(1))
+    }
+
+    @Test fun containsKeyWithValue() {
+        val array = SparseIntArray()
+
+        array.put(1, 11)
+        assertFalse(array.containsKey(2))
+
+        array.put(2, 22)
+        assertTrue(array.containsKey(2))
+    }
+
+    @Test fun containsValue() {
+        val array = SparseIntArray()
+        assertFalse(array.containsValue(11))
+        array.put(1, 11)
+        assertTrue(array.containsValue(11))
+    }
+
+    @Test fun getOrDefault() {
+        val array = SparseIntArray()
+        assertEquals(22, array.getOrDefault(1, 22))
+        array.put(1, 11)
+        assertEquals(11, array.getOrDefault(1, 22))
+    }
+
+    @Test fun getOrElse() {
+        val array = SparseIntArray()
+        assertEquals(22, array.getOrElse(1) { 22 })
+        array.put(1, 11)
+        assertEquals(11, array.getOrElse(1) { fail() })
+    }
+
+    @Test fun isEmpty() {
+        val array = SparseIntArray()
+        assertTrue(array.isEmpty())
+        array.put(1, 11)
+        assertFalse(array.isEmpty())
+    }
+
+    @Test fun isNotEmpty() {
+        val array = SparseIntArray()
+        assertFalse(array.isNotEmpty())
+        array.put(1, 11)
+        assertTrue(array.isNotEmpty())
+    }
+
+    @Test fun removeValue() {
+        val array = SparseIntArray()
+        array.put(1, 11)
+        assertFalse(array.remove(0, 11))
+        assertEquals(1, array.size())
+        assertFalse(array.remove(1, 22))
+        assertEquals(1, array.size())
+        assertTrue(array.remove(1, 11))
+        assertEquals(0, array.size())
+    }
+
+    @Test fun putAll() {
+        val dest = SparseIntArray()
+        val source = SparseIntArray()
+        source.put(1, 11)
+
+        assertEquals(0, dest.size())
+        dest.putAll(source)
+        assertEquals(1, dest.size())
+    }
+
+    @Test fun forEach() {
+        val array = SparseIntArray()
+        array.forEach { _, _ -> fail() }
+
+        array.put(1, 11)
+        array.put(2, 22)
+        array.put(6, 66)
+
+        val keys = mutableListOf<Int>()
+        val values = mutableListOf<Int>()
+        array.forEach { key, value ->
+            keys.add(key)
+            values.add(value)
+        }
+        assertThat(keys).containsExactly(1, 2, 6)
+        assertThat(values).containsExactly(11, 22, 66)
+    }
+
+    @Test fun keyIterator() {
+        val array = SparseIntArray()
+        assertFalse(array.keyIterator().hasNext())
+
+        array.put(1, 11)
+        array.put(2, 22)
+        array.put(6, 66)
+
+        val iterator = array.keyIterator()
+        assertTrue(iterator.hasNext())
+        assertEquals(1, iterator.nextInt())
+        assertTrue(iterator.hasNext())
+        assertEquals(2, iterator.nextInt())
+        assertTrue(iterator.hasNext())
+        assertEquals(6, iterator.nextInt())
+        assertFalse(iterator.hasNext())
+    }
+
+    @Test fun valueIterator() {
+        val array = SparseIntArray()
+        assertFalse(array.valueIterator().hasNext())
+
+        array.put(1, 11)
+        array.put(2, 22)
+        array.put(6, 66)
+
+        val iterator = array.valueIterator()
+        assertTrue(iterator.hasNext())
+        assertEquals(11, iterator.nextInt())
+        assertTrue(iterator.hasNext())
+        assertEquals(22, iterator.nextInt())
+        assertTrue(iterator.hasNext())
+        assertEquals(66, iterator.nextInt())
+        assertFalse(iterator.hasNext())
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/util/SparseLongArrayTest.kt b/core/ktx/src/androidTest/java/androidx/core/util/SparseLongArrayTest.kt
new file mode 100644
index 0000000..c65c2ad
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/util/SparseLongArrayTest.kt
@@ -0,0 +1,197 @@
+/*
+ * 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 androidx.core.util
+
+import android.support.test.filters.SdkSuppress
+import android.util.SparseLongArray
+import androidx.testutils.fail
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+@SdkSuppress(minSdkVersion = 18)
+class SparseLongArrayTest {
+    @Test fun sizeProperty() {
+        val array = SparseLongArray()
+        assertEquals(0, array.size)
+        array.put(1, 11L)
+        assertEquals(1, array.size)
+    }
+
+    @Test fun containsOperator() {
+        val array = SparseLongArray()
+        assertFalse(1 in array)
+        array.put(1, 11L)
+        assertTrue(1 in array)
+    }
+
+    @Test fun containsOperatorWithValue() {
+        val array = SparseLongArray()
+
+        array.put(1, 11L)
+        assertFalse(2 in array)
+
+        array.put(2, 22L)
+        assertTrue(2 in array)
+    }
+
+    @Test fun setOperator() {
+        val array = SparseLongArray()
+        array[1] = 11L
+        assertEquals(11L, array.get(1))
+    }
+
+    @Test fun plusOperator() {
+        val first = SparseLongArray().apply { put(1, 11L) }
+        val second = SparseLongArray().apply { put(2, 22L) }
+        val combined = first + second
+        assertEquals(2, combined.size())
+        assertEquals(1, combined.keyAt(0))
+        assertEquals(11L, combined.valueAt(0))
+        assertEquals(2, combined.keyAt(1))
+        assertEquals(22L, combined.valueAt(1))
+    }
+
+    @Test fun containsKey() {
+        val array = SparseLongArray()
+        assertFalse(array.containsKey(1))
+        array.put(1, 11L)
+        assertTrue(array.containsKey(1))
+    }
+
+    @Test fun containsKeyWithValue() {
+        val array = SparseLongArray()
+
+        array.put(1, 11L)
+        assertFalse(array.containsKey(2))
+
+        array.put(2, 22L)
+        assertTrue(array.containsKey(2))
+    }
+
+    @Test fun containsValue() {
+        val array = SparseLongArray()
+        assertFalse(array.containsValue(11L))
+        array.put(1, 11L)
+        assertTrue(array.containsValue(11L))
+    }
+
+    @Test fun getOrDefault() {
+        val array = SparseLongArray()
+        assertEquals(22L, array.getOrDefault(1, 22L))
+        array.put(1, 11L)
+        assertEquals(11L, array.getOrDefault(1, 22L))
+    }
+
+    @Test fun getOrElse() {
+        val array = SparseLongArray()
+        assertEquals(22L, array.getOrElse(1) { 22L })
+        array.put(1, 11L)
+        assertEquals(11L, array.getOrElse(1) { fail() })
+    }
+
+    @Test fun isEmpty() {
+        val array = SparseLongArray()
+        assertTrue(array.isEmpty())
+        array.put(1, 11L)
+        assertFalse(array.isEmpty())
+    }
+
+    @Test fun isNotEmpty() {
+        val array = SparseLongArray()
+        assertFalse(array.isNotEmpty())
+        array.put(1, 11L)
+        assertTrue(array.isNotEmpty())
+    }
+
+    @Test fun removeValue() {
+        val array = SparseLongArray()
+        array.put(1, 11L)
+        assertFalse(array.remove(0, 11L))
+        assertEquals(1, array.size())
+        assertFalse(array.remove(1, 22L))
+        assertEquals(1, array.size())
+        assertTrue(array.remove(1, 11L))
+        assertEquals(0, array.size())
+    }
+
+    @Test fun putAll() {
+        val dest = SparseLongArray()
+        val source = SparseLongArray()
+        source.put(1, 11L)
+
+        assertEquals(0, dest.size())
+        dest.putAll(source)
+        assertEquals(1, dest.size())
+    }
+
+    @Test fun forEach() {
+        val array = SparseLongArray()
+        array.forEach { _, _ -> fail() }
+
+        array.put(1, 11L)
+        array.put(2, 22L)
+        array.put(6, 66L)
+
+        val keys = mutableListOf<Int>()
+        val values = mutableListOf<Long>()
+        array.forEach { key, value ->
+            keys.add(key)
+            values.add(value)
+        }
+        assertThat(keys).containsExactly(1, 2, 6)
+        assertThat(values).containsExactly(11L, 22L, 66L)
+    }
+
+    @Test fun keyIterator() {
+        val array = SparseLongArray()
+        assertFalse(array.keyIterator().hasNext())
+
+        array.put(1, 11L)
+        array.put(2, 22L)
+        array.put(6, 66L)
+
+        val iterator = array.keyIterator()
+        assertTrue(iterator.hasNext())
+        assertEquals(1, iterator.nextInt())
+        assertTrue(iterator.hasNext())
+        assertEquals(2, iterator.nextInt())
+        assertTrue(iterator.hasNext())
+        assertEquals(6, iterator.nextInt())
+        assertFalse(iterator.hasNext())
+    }
+
+    @Test fun valueIterator() {
+        val array = SparseLongArray()
+        assertFalse(array.valueIterator().hasNext())
+
+        array.put(1, 11L)
+        array.put(2, 22L)
+        array.put(6, 66L)
+
+        val iterator = array.valueIterator()
+        assertTrue(iterator.hasNext())
+        assertEquals(11, iterator.nextLong())
+        assertTrue(iterator.hasNext())
+        assertEquals(22, iterator.nextLong())
+        assertTrue(iterator.hasNext())
+        assertEquals(66, iterator.nextLong())
+        assertFalse(iterator.hasNext())
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/view/AccessibilityAnnouncementCapturingView.kt b/core/ktx/src/androidTest/java/androidx/core/view/AccessibilityAnnouncementCapturingView.kt
new file mode 100644
index 0000000..81996b8
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/view/AccessibilityAnnouncementCapturingView.kt
@@ -0,0 +1,14 @@
+package androidx.core.view
+
+import android.content.Context
+import android.view.View
+
+class AccessibilityAnnouncementCapturingView(context: Context?) : View(context) {
+
+    var announcement: CharSequence? = null
+
+    override fun announceForAccessibility(text: CharSequence?) {
+        super.announceForAccessibility(text)
+        announcement = text
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/view/MenuTest.kt b/core/ktx/src/androidTest/java/androidx/core/view/MenuTest.kt
new file mode 100644
index 0000000..18e1b56
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/view/MenuTest.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.view
+
+import android.support.test.InstrumentationRegistry
+import android.view.Menu.NONE
+import android.view.MenuItem
+import android.widget.Toolbar
+import androidx.testutils.assertThrows
+import androidx.testutils.fail
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertSame
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class MenuTest {
+    private val menu = Toolbar(InstrumentationRegistry.getContext()).menu
+
+    @Test fun get() {
+        val item = menu.add("")
+        assertSame(item, menu[0])
+    }
+
+    @Test fun contains() {
+        val item1 = menu.add("")
+        assertTrue(item1 in menu)
+
+        val item2 = menu.add("")
+        assertTrue(item2 in menu)
+    }
+
+    @Test fun size() {
+        assertEquals(0, menu.size)
+
+        menu.add("")
+        assertEquals(1, menu.size)
+
+        menu.add(NONE, 123, NONE, "")
+        assertEquals(2, menu.size)
+
+        menu.removeItem(123)
+        assertEquals(1, menu.size)
+    }
+
+    @Test fun isEmpty() {
+        assertTrue(menu.isEmpty())
+        menu.add("")
+        assertFalse(menu.isEmpty())
+    }
+
+    @Test fun isNotEmpty() {
+        assertFalse(menu.isNotEmpty())
+        menu.add("")
+        assertTrue(menu.isNotEmpty())
+    }
+
+    @Test fun forEach() {
+        menu.forEach {
+            fail("Empty menu should not invoke lambda")
+        }
+
+        val item1 = menu.add("")
+        val item2 = menu.add("")
+
+        val items = mutableListOf<MenuItem>()
+        menu.forEach {
+            items += it
+        }
+        assertThat(items).containsExactly(item1, item2)
+    }
+
+    @Test fun forEachIndexed() {
+        menu.forEachIndexed { _, _ ->
+            fail("Empty menu should not invoke lambda")
+        }
+
+        val item1 = menu.add("")
+        val item2 = menu.add("")
+
+        val items = mutableListOf<MenuItem>()
+        menu.forEachIndexed { index, item ->
+            assertEquals(index, items.size)
+            items += item
+        }
+        assertThat(items).containsExactly(item1, item2)
+    }
+
+    @Test fun iterator() {
+        val item1 = menu.add("")
+        val item2 = menu.add("")
+
+        val iterator = menu.iterator()
+        assertTrue(iterator.hasNext())
+        assertSame(item1, iterator.next())
+        assertTrue(iterator.hasNext())
+        assertSame(item2, iterator.next())
+        assertFalse(iterator.hasNext())
+        assertThrows<IndexOutOfBoundsException> {
+            iterator.next()
+        }
+    }
+
+    @Test fun iteratorRemoving() {
+        val item1 = menu.add("")
+        val item2 = menu.add("")
+
+        val iterator = menu.iterator()
+
+        assertSame(item1, iterator.next())
+        iterator.remove()
+        assertFalse(item1 in menu)
+        assertEquals(1, menu.size())
+
+        assertSame(item2, iterator.next())
+        iterator.remove()
+        assertFalse(item2 in menu)
+        assertEquals(0, menu.size())
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/view/ViewGroupTest.kt b/core/ktx/src/androidTest/java/androidx/core/view/ViewGroupTest.kt
new file mode 100644
index 0000000..7ec791d
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/view/ViewGroupTest.kt
@@ -0,0 +1,264 @@
+/*
+ * 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 androidx.core.view
+
+import android.support.test.InstrumentationRegistry
+import android.support.test.filters.SdkSuppress
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import androidx.testutils.assertThrows
+import androidx.testutils.fail
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertSame
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class ViewGroupTest {
+    private val context = InstrumentationRegistry.getContext()
+    private val viewGroup = LinearLayout(context)
+
+    @Test fun get() {
+        val view1 = View(context)
+        viewGroup.addView(view1)
+        val view2 = View(context)
+        viewGroup.addView(view2)
+
+        assertSame(view1, viewGroup[0])
+        assertSame(view2, viewGroup[1])
+
+        assertThrows<IndexOutOfBoundsException> {
+            viewGroup[-1]
+        }.hasMessageThat().isEqualTo("Index: -1, Size: 2")
+
+        assertThrows<IndexOutOfBoundsException> {
+            viewGroup[2]
+        }.hasMessageThat().isEqualTo("Index: 2, Size: 2")
+    }
+
+    @Test fun contains() {
+        val view1 = View(context)
+        viewGroup.addView(view1)
+        assertTrue(view1 in viewGroup)
+        assertFalse(view1 !in viewGroup)
+
+        val view2 = View(context)
+        assertFalse(view2 in viewGroup)
+        assertTrue(view2 !in viewGroup)
+    }
+
+    @Test fun plusAssign() {
+        assertEquals(0, viewGroup.childCount)
+
+        val view1 = View(context)
+        viewGroup += view1
+        assertEquals(1, viewGroup.childCount)
+        assertSame(view1, viewGroup.getChildAt(0))
+
+        val view2 = View(context)
+        viewGroup += view2
+        assertEquals(2, viewGroup.childCount)
+        assertSame(view2, viewGroup.getChildAt(1))
+    }
+
+    @Test fun minusAssign() {
+        val view1 = View(context)
+        viewGroup.addView(view1)
+        val view2 = View(context)
+        viewGroup.addView(view2)
+
+        assertEquals(2, viewGroup.childCount)
+
+        viewGroup -= view2
+        assertEquals(1, viewGroup.childCount)
+        assertSame(view1, viewGroup.getChildAt(0))
+
+        viewGroup -= view1
+        assertEquals(0, viewGroup.childCount)
+    }
+
+    @Test fun size() {
+        assertEquals(0, viewGroup.size)
+
+        viewGroup.addView(View(context))
+        assertEquals(1, viewGroup.size)
+
+        viewGroup.addView(View(context))
+        assertEquals(2, viewGroup.size)
+
+        viewGroup.removeViewAt(0)
+        assertEquals(1, viewGroup.size)
+    }
+
+    @Test fun isEmpty() {
+        assertTrue(viewGroup.isEmpty())
+        viewGroup.addView(View(context))
+        assertFalse(viewGroup.isEmpty())
+    }
+
+    @Test fun isNotEmpty() {
+        assertFalse(viewGroup.isNotEmpty())
+        viewGroup.addView(View(context))
+        assertTrue(viewGroup.isNotEmpty())
+    }
+
+    @Test fun forEach() {
+        viewGroup.forEach {
+            fail("Empty view group should not invoke lambda")
+        }
+
+        val view1 = View(context)
+        viewGroup.addView(view1)
+        val view2 = View(context)
+        viewGroup.addView(view2)
+
+        val views = mutableListOf<View>()
+        viewGroup.forEach {
+            views += it
+        }
+        assertThat(views).containsExactly(view1, view2)
+    }
+
+    @Test fun forEachIndexed() {
+        viewGroup.forEachIndexed { _, _ ->
+            fail("Empty view group should not invoke lambda")
+        }
+
+        val view1 = View(context)
+        viewGroup.addView(view1)
+        val view2 = View(context)
+        viewGroup.addView(view2)
+
+        val views = mutableListOf<View>()
+        viewGroup.forEachIndexed { index, view ->
+            assertEquals(index, views.size)
+            views += view
+        }
+        assertThat(views).containsExactly(view1, view2)
+    }
+
+    @Test fun iterator() {
+        val view1 = View(context)
+        viewGroup.addView(view1)
+        val view2 = View(context)
+        viewGroup.addView(view2)
+
+        val iterator = viewGroup.iterator()
+        assertTrue(iterator.hasNext())
+        assertSame(view1, iterator.next())
+        assertTrue(iterator.hasNext())
+        assertSame(view2, iterator.next())
+        assertFalse(iterator.hasNext())
+        assertThrows<IndexOutOfBoundsException> {
+            iterator.next()
+        }
+    }
+
+    @Test fun iteratorRemoving() {
+        val view1 = View(context)
+        viewGroup.addView(view1)
+        val view2 = View(context)
+        viewGroup.addView(view2)
+
+        val iterator = viewGroup.iterator()
+
+        assertSame(view1, iterator.next())
+        iterator.remove()
+        assertFalse(view1 in viewGroup)
+        assertEquals(1, viewGroup.childCount)
+
+        assertSame(view2, iterator.next())
+        iterator.remove()
+        assertFalse(view2 in viewGroup)
+        assertEquals(0, viewGroup.childCount)
+    }
+
+    @Test fun iteratorForEach() {
+        val views = listOf(View(context), View(context))
+        views.forEach(viewGroup::addView)
+
+        var index = 0
+        for (view in viewGroup) {
+            assertSame(views[index++], view)
+        }
+    }
+
+    @Test fun children() {
+        val views = listOf(View(context), View(context), View(context))
+        views.forEach { viewGroup.addView(it) }
+
+        viewGroup.children.forEachIndexed { index, child ->
+            assertSame(views[index], child)
+        }
+    }
+
+    @Test fun setMargins() {
+        val layoutParams = ViewGroup.MarginLayoutParams(100, 200)
+        layoutParams.setMargins(42)
+        assertEquals(42, layoutParams.leftMargin)
+        assertEquals(42, layoutParams.topMargin)
+        assertEquals(42, layoutParams.rightMargin)
+        assertEquals(42, layoutParams.bottomMargin)
+    }
+
+    @Test fun updateMargins() {
+        val layoutParams = ViewGroup.MarginLayoutParams(100, 200)
+        layoutParams.updateMargins(top = 10, right = 20)
+        assertEquals(0, layoutParams.leftMargin)
+        assertEquals(10, layoutParams.topMargin)
+        assertEquals(20, layoutParams.rightMargin)
+        assertEquals(0, layoutParams.bottomMargin)
+    }
+
+    @Test fun updateMarginsNoOp() {
+        val layoutParams = ViewGroup.MarginLayoutParams(100, 200)
+        layoutParams.setMargins(10, 20, 30, 40)
+        layoutParams.updateMargins()
+        assertEquals(10, layoutParams.leftMargin)
+        assertEquals(20, layoutParams.topMargin)
+        assertEquals(30, layoutParams.rightMargin)
+        assertEquals(40, layoutParams.bottomMargin)
+    }
+
+    @SdkSuppress(minSdkVersion = 17)
+    @Test fun updateMarginsRelative() {
+        val layoutParams = ViewGroup.MarginLayoutParams(100, 200)
+        layoutParams.updateMarginsRelative(start = 10, end = 20)
+        assertEquals(0, layoutParams.leftMargin)
+        assertEquals(0, layoutParams.topMargin)
+        assertEquals(0, layoutParams.rightMargin)
+        assertEquals(0, layoutParams.bottomMargin)
+        assertEquals(10, layoutParams.marginStart)
+        assertEquals(20, layoutParams.marginEnd)
+        assertTrue(layoutParams.isMarginRelative)
+    }
+
+    @SdkSuppress(minSdkVersion = 17)
+    @Test fun updateMarginsRelativeNoOp() {
+        val layoutParams = ViewGroup.MarginLayoutParams(100, 200)
+        layoutParams.setMargins(10, 20, 30, 40)
+        layoutParams.updateMarginsRelative()
+        assertEquals(10, layoutParams.leftMargin)
+        assertEquals(20, layoutParams.topMargin)
+        assertEquals(30, layoutParams.rightMargin)
+        assertEquals(40, layoutParams.bottomMargin)
+        assertEquals(10, layoutParams.marginStart)
+        assertEquals(30, layoutParams.marginEnd)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/view/ViewTest.kt b/core/ktx/src/androidTest/java/androidx/core/view/ViewTest.kt
new file mode 100644
index 0000000..0b7cfa2
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/view/ViewTest.kt
@@ -0,0 +1,248 @@
+/*
+ * 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 androidx.core.view
+
+import android.graphics.Bitmap
+import android.support.test.InstrumentationRegistry
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import android.widget.RelativeLayout
+import androidx.core.ktx.test.R
+import androidx.testutils.assertThrows
+import androidx.testutils.fail
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertSame
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class ViewTest {
+    private val context = InstrumentationRegistry.getContext()
+    private val view = View(context)
+
+    @Test
+    fun doOnNextLayout() {
+        var calls = 0
+        view.doOnNextLayout {
+            calls++
+        }
+        view.layout(0, 0, 10, 10)
+        assertEquals(1, calls)
+
+        // Now layout again and make sure that the listener was removed
+        view.layout(0, 0, 10, 10)
+        assertEquals(1, calls)
+    }
+
+    @Test
+    fun doOnLayoutBeforeLayout() {
+        var called = false
+        view.doOnLayout {
+            called = true
+        }
+        view.layout(0, 0, 10, 10)
+        assertTrue(called)
+    }
+
+    @Test
+    fun doOnLayoutAfterLayout() {
+        view.layout(0, 0, 10, 10)
+
+        var called = false
+        view.doOnLayout {
+            called = true
+        }
+        assertTrue(called)
+    }
+
+    @Test
+    fun doOnLayoutWhileLayoutRequested() {
+        // First layout the view
+        view.layout(0, 0, 10, 10)
+        // Then later a layout is requested
+        view.requestLayout()
+
+        var called = false
+        view.doOnLayout {
+            called = true
+        }
+
+        // Assert that we haven't been called while the layout pass is pending
+        assertFalse(called)
+
+        // Now layout the view and assert that we're called
+        view.layout(0, 0, 20, 20)
+        assertTrue(called)
+    }
+
+    @Test
+    fun doOnPreDraw() {
+        var calls = 0
+        view.doOnPreDraw {
+            calls++
+        }
+        view.viewTreeObserver.dispatchOnPreDraw()
+        assertEquals(1, calls)
+
+        // Now dispatch again to make sure that the listener was removed
+        view.viewTreeObserver.dispatchOnPreDraw()
+        assertEquals(1, calls)
+    }
+
+    @Test
+    fun setPadding() {
+        view.setPadding(42)
+        assertEquals(42, view.paddingLeft)
+        assertEquals(42, view.paddingTop)
+        assertEquals(42, view.paddingRight)
+        assertEquals(42, view.paddingBottom)
+    }
+
+    @Test
+    fun updatePadding() {
+        view.updatePadding(top = 10, right = 20)
+        assertEquals(0, view.paddingLeft)
+        assertEquals(10, view.paddingTop)
+        assertEquals(20, view.paddingRight)
+        assertEquals(0, view.paddingBottom)
+    }
+
+    @Test
+    fun updatePaddingNoOp() {
+        view.setPadding(10, 20, 30, 40)
+        view.updatePadding()
+        assertEquals(10, view.paddingLeft)
+        assertEquals(20, view.paddingTop)
+        assertEquals(30, view.paddingRight)
+        assertEquals(40, view.paddingBottom)
+    }
+
+    @Test
+    fun updatePaddingRelative() {
+        view.updatePaddingRelative(start = 10, end = 20)
+        assertEquals(10, view.paddingStart)
+        assertEquals(0, view.paddingTop)
+        assertEquals(20, view.paddingEnd)
+        assertEquals(0, view.paddingBottom)
+    }
+
+    @Test
+    fun updatePaddingRelativeNoOp() {
+        view.setPaddingRelative(10, 20, 30, 40)
+        view.updatePaddingRelative()
+        assertEquals(10, view.paddingStart)
+        assertEquals(20, view.paddingTop)
+        assertEquals(30, view.paddingEnd)
+        assertEquals(40, view.paddingBottom)
+    }
+
+    @Test
+    fun toBitmapBeforeLayout() {
+        assertThrows<IllegalStateException> {
+            view.toBitmap()
+        }
+    }
+
+    @Test
+    fun toBitmap() {
+        view.layout(0, 0, 100, 100)
+        val bitmap = view.toBitmap()
+
+        assertEquals(100, bitmap.width)
+        assertEquals(100, bitmap.height)
+    }
+
+    @Test
+    fun toBitmapCustomConfig() {
+        view.layout(0, 0, 100, 100)
+        val bitmap = view.toBitmap(Bitmap.Config.RGB_565)
+
+        assertSame(Bitmap.Config.RGB_565, bitmap.config)
+    }
+
+    @Test fun isVisible() {
+        view.isVisible = true
+        assertTrue(view.isVisible)
+        assertEquals(View.VISIBLE, view.visibility)
+
+        view.isVisible = false
+        assertFalse(view.isVisible)
+        assertEquals(View.GONE, view.visibility)
+    }
+
+    @Test fun isInvisible() {
+        view.isInvisible = true
+        assertTrue(view.isInvisible)
+        assertEquals(View.INVISIBLE, view.visibility)
+
+        view.isInvisible = false
+        assertFalse(view.isInvisible)
+        assertEquals(View.VISIBLE, view.visibility)
+    }
+
+    @Test fun isGone() {
+        view.isGone = true
+        assertTrue(view.isGone)
+        assertEquals(View.GONE, view.visibility)
+
+        view.isGone = false
+        assertFalse(view.isGone)
+        assertEquals(View.VISIBLE, view.visibility)
+    }
+
+    @Test fun updateLayoutParams() {
+        view.layoutParams = ViewGroup.LayoutParams(0, 0)
+        view.updateLayoutParams {
+            assertSame(view.layoutParams, this)
+
+            width = 500
+            height = 1000
+        }
+
+        assertEquals(500, view.layoutParams.width)
+        assertEquals(1000, view.layoutParams.height)
+    }
+
+    @Test fun updateLayoutParamsAsType() {
+        view.layoutParams = LinearLayout.LayoutParams(0, 0)
+        view.updateLayoutParams<LinearLayout.LayoutParams> {
+            assertSame(view.layoutParams, this)
+
+            weight = 2f
+        }
+
+        assertEquals(2f, (view.layoutParams as LinearLayout.LayoutParams).weight)
+    }
+
+    @Test fun updateLayoutParamsWrongType() {
+        assertThrows<ClassCastException> {
+            view.updateLayoutParams<RelativeLayout.LayoutParams> {
+                fail()
+            }
+        }
+    }
+
+    @Test fun announceForAccessibility() {
+        val testView = AccessibilityAnnouncementCapturingView(context)
+
+        testView.announceForAccessibility(R.string.text)
+
+        val resolvedText = context.getText(R.string.text)
+        assertEquals(testView.announcement, resolvedText)
+    }
+}
diff --git a/core/ktx/src/androidTest/java/androidx/core/widget/ToastTest.kt b/core/ktx/src/androidTest/java/androidx/core/widget/ToastTest.kt
new file mode 100644
index 0000000..f8e9931
--- /dev/null
+++ b/core/ktx/src/androidTest/java/androidx/core/widget/ToastTest.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.widget
+
+import android.support.test.InstrumentationRegistry
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import android.widget.Toast
+import androidx.core.ktx.test.R
+import androidx.core.view.forEach
+import androidx.core.view.isVisible
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+class ToastTest {
+    private val context = InstrumentationRegistry.getContext()
+    private val instrumentation = InstrumentationRegistry.getInstrumentation()
+
+    @Test
+    fun createToastWithTextShort() = instrumentation.runOnMainSync {
+        val toast = context.toast("Short Toast")
+        assertEquals(Toast.LENGTH_SHORT, toast.duration)
+        assertTrue(containsText(toast.view, "Short Toast"))
+        assertTrue(toast.view.isVisible)
+    }
+
+    @Test
+    fun createToastWithTextLong() = instrumentation.runOnMainSync {
+        val toast = context.toast("Long Toast", Toast.LENGTH_LONG)
+        assertEquals(Toast.LENGTH_LONG, toast.duration)
+        assertTrue(containsText(toast.view, "Long Toast"))
+        assertTrue(toast.view.isVisible)
+    }
+
+    @Test
+    fun createToastWithResIdShort() = instrumentation.runOnMainSync {
+        val toast = context.toast(R.string.text)
+        assertEquals(Toast.LENGTH_SHORT, toast.duration)
+        assertTrue(containsText(toast.view, context.getString(R.string.text)))
+        assertTrue(toast.view.isVisible)
+    }
+
+    @Test
+    fun createToastWithResIdLong() = instrumentation.runOnMainSync {
+        val toast = context.toast(R.string.text, Toast.LENGTH_LONG)
+        assertEquals(Toast.LENGTH_LONG, toast.duration)
+        assertTrue(containsText(toast.view, context.getString(R.string.text)))
+        assertTrue(toast.view.isVisible)
+    }
+
+    private fun containsText(view: View, text: String): Boolean {
+        if (view is TextView && view.text == text) {
+            return true
+        }
+        if (view is ViewGroup) {
+            view.forEach {
+                if (containsText(it, text)) {
+                    return true
+                }
+            }
+        }
+        return false
+    }
+}
diff --git a/core/ktx/src/androidTest/res/drawable/box.xml b/core/ktx/src/androidTest/res/drawable/box.xml
new file mode 100644
index 0000000..3915878
--- /dev/null
+++ b/core/ktx/src/androidTest/res/drawable/box.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <size android:height="10px" android:width="10px"/>
+    <solid android:color="#fff"/>
+</shape>
diff --git a/core/ktx/src/androidTest/res/font/inconsolata_regular.ttf b/core/ktx/src/androidTest/res/font/inconsolata_regular.ttf
new file mode 100644
index 0000000..fc981ce
--- /dev/null
+++ b/core/ktx/src/androidTest/res/font/inconsolata_regular.ttf
Binary files differ
diff --git a/core/ktx/src/androidTest/res/layout/test_activity.xml b/core/ktx/src/androidTest/res/layout/test_activity.xml
new file mode 100644
index 0000000..a477350
--- /dev/null
+++ b/core/ktx/src/androidTest/res/layout/test_activity.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/root"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <ImageView android:id="@+id/image_view"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:src="@android:drawable/ic_media_play"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/core/ktx/src/androidTest/res/layout/test_attrs.xml b/core/ktx/src/androidTest/res/layout/test_attrs.xml
new file mode 100644
index 0000000..d5975c5
--- /dev/null
+++ b/core/ktx/src/androidTest/res/layout/test_attrs.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:app="http://schemas.android.com/apk/res-auto"
+        android:id="@+id/root"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        app:sample="42" />
diff --git a/core/ktx/src/androidTest/res/layout/typed_array.xml b/core/ktx/src/androidTest/res/layout/typed_array.xml
new file mode 100644
index 0000000..e485ffd
--- /dev/null
+++ b/core/ktx/src/androidTest/res/layout/typed_array.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+      xmlns:app="http://schemas.android.com/apk/res-auto"
+      android:layout_width="match_parent" android:layout_height="match_parent"
+      app:boolean_present="true"
+      app:color_present="#fff"
+      app:dimension_present="1px"
+      app:drawable_present="@drawable/box"
+      app:string_present="Hello"
+      app:float_present="0.1"
+      app:integer_present="1"
+      app:resource_present="@font/inconsolata_regular"
+      app:font_present="@font/inconsolata_regular"
+      app:text_array_present="@array/text_array"
+/>
diff --git a/core/ktx/src/androidTest/res/values/attrs.xml b/core/ktx/src/androidTest/res/values/attrs.xml
new file mode 100644
index 0000000..e3f9723
--- /dev/null
+++ b/core/ktx/src/androidTest/res/values/attrs.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<resources>
+    <declare-styleable name="SampleAttrs">
+        <attr name="sample" format="integer" />
+    </declare-styleable>
+</resources>
diff --git a/core/ktx/src/androidTest/res/values/strings.xml b/core/ktx/src/androidTest/res/values/strings.xml
new file mode 100644
index 0000000..20877e9
--- /dev/null
+++ b/core/ktx/src/androidTest/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<resources>
+    <string name="text">Hello World</string>
+    <string-array name="text_array">
+        <item>Hello</item>
+        <item>World</item>
+    </string-array>
+</resources>
diff --git a/core/ktx/src/androidTest/res/values/styles.xml b/core/ktx/src/androidTest/res/values/styles.xml
new file mode 100644
index 0000000..ea35e47
--- /dev/null
+++ b/core/ktx/src/androidTest/res/values/styles.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<resources>
+    <declare-styleable name="TypedArrayTypes">
+        <attr name="boolean_present" format="boolean"/>
+        <attr name="boolean_absent" format="boolean"/>
+
+        <attr name="color_present" format="color"/>
+        <attr name="color_absent" format="color"/>
+
+        <attr name="dimension_present" format="dimension"/>
+        <attr name="dimension_absent" format="dimension"/>
+
+        <attr name="drawable_present" format="reference"/>
+        <attr name="drawable_absent" format="reference"/>
+
+        <attr name="float_present" format="float"/>
+        <attr name="float_absent" format="float"/>
+
+        <attr name="font_present" format="reference"/>
+        <attr name="font_absent" format="reference"/>
+
+        <attr name="integer_present" format="integer"/>
+        <attr name="integer_absent" format="integer"/>
+
+        <attr name="resource_present" format="reference"/>
+        <attr name="resource_absent" format="reference"/>
+
+        <attr name="string_present" format="string"/>
+        <attr name="string_absent" format="string"/>
+
+        <attr name="text_array_present" format="reference"/>
+        <attr name="text_array_absent" format="reference"/>
+    </declare-styleable>
+</resources>
diff --git a/core/ktx/src/androidTest/res/xml/preferences.xml b/core/ktx/src/androidTest/res/xml/preferences.xml
new file mode 100644
index 0000000..33629e1
--- /dev/null
+++ b/core/ktx/src/androidTest/res/xml/preferences.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<PreferenceScreen/>
\ No newline at end of file
diff --git a/core/ktx/src/main/AndroidManifest.xml b/core/ktx/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..7f93e5e
--- /dev/null
+++ b/core/ktx/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+<manifest package="androidx.core.ktx"/>
diff --git a/core/ktx/src/main/java/androidx/core/animation/Animator.kt b/core/ktx/src/main/java/androidx/core/animation/Animator.kt
new file mode 100644
index 0000000..1438bcd
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/animation/Animator.kt
@@ -0,0 +1,119 @@
+/*
+ * 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 androidx.core.animation
+
+import android.animation.Animator
+import androidx.annotation.RequiresApi
+
+/**
+ * Add an action which will be invoked when the animation has ended.
+ *
+ * @return the [Animator.AnimatorListener] added to the Animator
+ * @see Animator.end
+ */
+fun Animator.doOnEnd(action: (animator: Animator) -> Unit) = addListener(onEnd = action)
+
+/**
+ * Add an action which will be invoked when the animation has started.
+ *
+ * @return the [Animator.AnimatorListener] added to the Animator
+ * @see Animator.start
+ */
+fun Animator.doOnStart(action: (animator: Animator) -> Unit) = addListener(onStart = action)
+
+/**
+ * Add an action which will be invoked when the animation has been cancelled.
+ *
+ * @return the [Animator.AnimatorListener] added to the Animator
+ * @see Animator.cancel
+ */
+fun Animator.doOnCancel(action: (animator: Animator) -> Unit) = addListener(onCancel = action)
+
+/**
+ * Add an action which will be invoked when the animation has repeated.
+ * @return the [Animator.AnimatorListener] added to the Animator
+ */
+fun Animator.doOnRepeat(action: (animator: Animator) -> Unit) = addListener(onRepeat = action)
+
+/**
+ * Add an action which will be invoked when the animation has resumed after a pause.
+ *
+ * @return the [Animator.AnimatorPauseListener] added to the Animator
+ * @see Animator.resume
+ */
+@RequiresApi(19)
+fun Animator.doOnResume(action: (animator: Animator) -> Unit) = addPauseListener(onResume = action)
+
+/**
+ * Add an action which will be invoked when the animation has been paused.
+ *
+ * @return the [Animator.AnimatorPauseListener] added to the Animator
+ * @see Animator.pause
+ */
+@RequiresApi(19)
+fun Animator.doOnPause(action: (animator: Animator) -> Unit) = addPauseListener(onPause = action)
+
+/**
+ * Add a listener to this Animator using the provided actions.
+ */
+fun Animator.addListener(
+    onEnd: ((animator: Animator) -> Unit)? = null,
+    onStart: ((animator: Animator) -> Unit)? = null,
+    onCancel: ((animator: Animator) -> Unit)? = null,
+    onRepeat: ((animator: Animator) -> Unit)? = null
+): Animator.AnimatorListener {
+    val listener = object : Animator.AnimatorListener {
+        override fun onAnimationRepeat(animator: Animator) {
+            onRepeat?.invoke(animator)
+        }
+
+        override fun onAnimationEnd(animator: Animator) {
+            onEnd?.invoke(animator)
+        }
+
+        override fun onAnimationCancel(animator: Animator) {
+            onCancel?.invoke(animator)
+        }
+
+        override fun onAnimationStart(animator: Animator) {
+            onStart?.invoke(animator)
+        }
+    }
+    addListener(listener)
+    return listener
+}
+
+/**
+ * Add a pause and resume listener to this Animator using the provided actions.
+ */
+@RequiresApi(19)
+fun Animator.addPauseListener(
+    onResume: ((animator: Animator) -> Unit)? = null,
+    onPause: ((animator: Animator) -> Unit)? = null
+): Animator.AnimatorPauseListener {
+    val listener = object : Animator.AnimatorPauseListener {
+        override fun onAnimationPause(animator: Animator) {
+            onPause?.invoke(animator)
+        }
+
+        override fun onAnimationResume(animator: Animator) {
+            onResume?.invoke(animator)
+        }
+    }
+    addPauseListener(listener)
+    return listener
+}
diff --git a/core/ktx/src/main/java/androidx/core/content/ContentValues.kt b/core/ktx/src/main/java/androidx/core/content/ContentValues.kt
new file mode 100644
index 0000000..e1a0d01
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/content/ContentValues.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.content
+
+import android.content.ContentValues
+
+/**
+ * Returns a new [ContentValues] with the given key/value pairs as elements.
+ *
+ * @throws IllegalArgumentException When a value is not a supported type of [ContentValues].
+ */
+fun contentValuesOf(vararg pairs: Pair<String, Any?>) = ContentValues(pairs.size).apply {
+    for ((key, value) in pairs) {
+        when (value) {
+            null -> putNull(key)
+            is String -> put(key, value)
+            is Int -> put(key, value)
+            is Long -> put(key, value)
+            is Boolean -> put(key, value)
+            is Float -> put(key, value)
+            is Double -> put(key, value)
+            is ByteArray -> put(key, value)
+            is Byte -> put(key, value)
+            is Short -> put(key, value)
+            else -> {
+                val valueType = value.javaClass.canonicalName
+                throw IllegalArgumentException("Illegal value type $valueType for key \"$key\"")
+            }
+        }
+    }
+}
diff --git a/core/ktx/src/main/java/androidx/core/content/Context.kt b/core/ktx/src/main/java/androidx/core/content/Context.kt
new file mode 100644
index 0000000..2ffb17b
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/content/Context.kt
@@ -0,0 +1,93 @@
+/*
+ * 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 androidx.core.content
+
+import android.content.Context
+import android.content.res.TypedArray
+import android.util.AttributeSet
+import androidx.annotation.AttrRes
+import androidx.annotation.RequiresApi
+import androidx.annotation.StyleRes
+
+/**
+ * Return the handle to a system-level service by class.
+ *
+ * The return type of this function intentionally uses a
+ * [platform type](https://kotlinlang.org/docs/reference/java-interop.html#null-safety-and-platform-types)
+ * to allow callers to decide whether they require a service be present or can tolerate its absence.
+ *
+ * @see Context.getSystemService(Class)
+ */
+@RequiresApi(23)
+@Suppress("HasPlatformType") // Intentionally propagating platform type with unknown nullability.
+inline fun <reified T> Context.systemService() = getSystemService(T::class.java)
+
+/**
+ * Executes [block] on a [TypedArray] receiver. The [TypedArray] holds the attribute
+ * values in [set] that are listed in [attrs]. In addition, if the given [AttributeSet]
+ * specifies a style class (through the `style` attribute), that style will be applied
+ * on top of the base attributes it defines.
+ *
+ * @param set The base set of attribute values.
+ * @param attrs The desired attributes to be retrieved. These attribute IDs must be
+ *              sorted in ascending order.
+ * @param defStyleAttr An attribute in the current theme that contains a reference to
+ *                     a style resource that supplies defaults values for the [TypedArray].
+ *                     Can be 0 to not look for defaults.
+ * @param defStyleRes A resource identifier of a style resource that supplies default values
+ *                    for the [TypedArray], used only if [defStyleAttr] is 0 or can not be found
+ *                     in the theme. Can be 0 to not look for defaults.
+ *
+ * @see Context.obtainStyledAttributes
+ * @see android.content.res.Resources.Theme.obtainStyledAttributes
+ */
+inline fun Context.withStyledAttributes(
+    set: AttributeSet? = null,
+    attrs: IntArray,
+    @AttrRes defStyleAttr: Int = 0,
+    @StyleRes defStyleRes: Int = 0,
+    block: TypedArray.() -> Unit
+) {
+    val typedArray = obtainStyledAttributes(set, attrs, defStyleAttr, defStyleRes)
+    try {
+        typedArray.block()
+    } finally {
+        typedArray.recycle()
+    }
+}
+
+/**
+ * Executes [block] on a [TypedArray] receiver. The [TypedArray] holds the the values
+ * defined by the style resource [resourceId] which are listed in [attrs].
+ *
+ * @param attrs The desired attributes. These attribute IDs must be sorted in ascending order.
+ *
+ * @see Context.obtainStyledAttributes
+ * @see android.content.res.Resources.Theme.obtainStyledAttributes
+ */
+inline fun Context.withStyledAttributes(
+    @StyleRes resourceId: Int,
+    attrs: IntArray,
+    block: TypedArray.() -> Unit
+) {
+    val typedArray = obtainStyledAttributes(resourceId, attrs)
+    try {
+        typedArray.block()
+    } finally {
+        typedArray.recycle()
+    }
+}
diff --git a/core/ktx/src/main/java/androidx/core/content/SharedPreferences.kt b/core/ktx/src/main/java/androidx/core/content/SharedPreferences.kt
new file mode 100644
index 0000000..c4677ea
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/content/SharedPreferences.kt
@@ -0,0 +1,50 @@
+/*
+ * 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 androidx.core.content
+
+import android.annotation.SuppressLint
+import android.content.SharedPreferences
+
+/**
+ * Allows editing of this preference instance with a call to [apply][SharedPreferences.Editor.apply]
+ * or [commit][SharedPreferences.Editor.commit] to persist the changes.
+ * Default behaviour is [apply][SharedPreferences.Editor.apply].
+ * ```
+ * prefs.edit {
+ *     putString("key", value)
+ * }
+ * ```
+ * To [commit][SharedPreferences.Editor.commit] changes:
+ * ```
+ * prefs.edit(commit = true) {
+ *     putString("key", value)
+ * }
+ * ```
+ */
+@SuppressLint("ApplySharedPref")
+inline fun SharedPreferences.edit(
+    commit: Boolean = false,
+    action: SharedPreferences.Editor.() -> Unit
+) {
+    val editor = edit()
+    action(editor)
+    if (commit) {
+        editor.commit()
+    } else {
+        editor.apply()
+    }
+}
diff --git a/core/ktx/src/main/java/androidx/core/content/res/TypedArray.kt b/core/ktx/src/main/java/androidx/core/content/res/TypedArray.kt
new file mode 100644
index 0000000..a4f6fef
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/content/res/TypedArray.kt
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.content.res
+
+import android.content.res.ColorStateList
+import android.content.res.TypedArray
+import android.graphics.Typeface
+import android.graphics.drawable.Drawable
+import androidx.annotation.AnyRes
+import androidx.annotation.ColorInt
+import androidx.annotation.Dimension
+import androidx.annotation.RequiresApi
+import androidx.annotation.StyleableRes
+
+private fun TypedArray.checkAttribute(@StyleableRes index: Int) {
+    if (!hasValue(index)) {
+        throw IllegalArgumentException("Attribute not defined in set.")
+    }
+}
+
+/**
+ * Retrieve the boolean value for the attribute at [index] or throws [IllegalArgumentException]
+ * if not defined.
+ *
+ * @see TypedArray.hasValue
+ * @see TypedArray.getBoolean
+ */
+fun TypedArray.getBooleanOrThrow(@StyleableRes index: Int): Boolean {
+    checkAttribute(index)
+    return getBoolean(index, false)
+}
+
+/**
+ * Retrieve the color value for the attribute at [index] or throws [IllegalArgumentException]
+ * if not defined.
+ *
+ * @see TypedArray.hasValue
+ * @see TypedArray.getColor
+ */
+@ColorInt
+fun TypedArray.getColorOrThrow(@StyleableRes index: Int): Int {
+    checkAttribute(index)
+    return getColor(index, 0)
+}
+
+/**
+ * Retrieve the color state list value for the attribute at [index] or throws
+ * [IllegalArgumentException] if not defined.
+ *
+ * @see TypedArray.hasValue
+ * @see TypedArray.getColorStateList
+ */
+fun TypedArray.getColorStateListOrThrow(@StyleableRes index: Int): ColorStateList {
+    checkAttribute(index)
+    return checkNotNull(getColorStateList(index)) {
+        "Attribute value was not a color or color state list."
+    }
+}
+
+/**
+ * Retrieve the dimension value for the attribute at [index] or throws [IllegalArgumentException]
+ * if not defined.
+ *
+ * @see TypedArray.hasValue
+ * @see TypedArray.getDimension
+ */
+fun TypedArray.getDimensionOrThrow(@StyleableRes index: Int): Float {
+    checkAttribute(index)
+    return getDimension(index, 0f)
+}
+
+/**
+ * Retrieve the dimension pixel offset value for the attribute at [index] or throws
+ * [IllegalArgumentException] if not defined.
+ *
+ * @see TypedArray.hasValue
+ * @see TypedArray.getDimensionPixelOffset
+ */
+@Dimension
+fun TypedArray.getDimensionPixelOffsetOrThrow(@StyleableRes index: Int): Int {
+    checkAttribute(index)
+    return getDimensionPixelOffset(index, 0)
+}
+
+/**
+ * Retrieve the dimension pixel size value for the attribute at [index] or throws
+ * [IllegalArgumentException] if not defined.
+ *
+ * @see TypedArray.hasValue
+ * @see TypedArray.getDimensionPixelSize
+ */
+@Dimension
+fun TypedArray.getDimensionPixelSizeOrThrow(@StyleableRes index: Int): Int {
+    checkAttribute(index)
+    return getDimensionPixelSize(index, 0)
+}
+
+/**
+ * Retrieve the drawable value for the attribute at [index] or throws [IllegalArgumentException]
+ * if not defined.
+ *
+ * @see TypedArray.hasValue
+ * @see TypedArray.getDrawable
+ */
+fun TypedArray.getDrawableOrThrow(@StyleableRes index: Int): Drawable {
+    checkAttribute(index)
+    return getDrawable(index)
+}
+
+/**
+ * Retrieve the float value for the attribute at [index] or throws [IllegalArgumentException]
+ * if not defined.
+ *
+ * @see TypedArray.hasValue
+ * @see TypedArray.getFloat
+ */
+fun TypedArray.getFloatOrThrow(@StyleableRes index: Int): Float {
+    checkAttribute(index)
+    return getFloat(index, 0f)
+}
+
+/**
+ * Retrieve the font value for the attribute at [index] or throws [IllegalArgumentException]
+ * if not defined.
+ *
+ * @see TypedArray.hasValue
+ * @see TypedArray.getFont
+ */
+@RequiresApi(26)
+fun TypedArray.getFontOrThrow(@StyleableRes index: Int): Typeface {
+    checkAttribute(index)
+    return getFont(index)
+}
+
+/**
+ * Retrieve the integer value for the attribute at [index] or throws [IllegalArgumentException]
+ * if not defined.
+ *
+ * @see TypedArray.hasValue
+ * @see TypedArray.getInt
+ */
+fun TypedArray.getIntOrThrow(@StyleableRes index: Int): Int {
+    checkAttribute(index)
+    return getInt(index, 0)
+}
+
+/**
+ * Retrieve the integer value for the attribute at [index] or throws [IllegalArgumentException]
+ * if not defined.
+ *
+ * @see TypedArray.hasValue
+ * @see TypedArray.getInteger
+ */
+fun TypedArray.getIntegerOrThrow(@StyleableRes index: Int): Int {
+    checkAttribute(index)
+    return getInteger(index, 0)
+}
+
+/**
+ * Retrieves the resource identifier for the attribute at [index] or throws
+ * [IllegalArgumentException] if not defined.
+ *
+ * @see TypedArray.hasValue
+ * @see TypedArray.getResourceId
+ */
+@AnyRes
+fun TypedArray.getResourceIdOrThrow(@StyleableRes index: Int): Int {
+    checkAttribute(index)
+    return getResourceId(index, 0)
+}
+
+/**
+ * Retrieve the string value for the attribute at [index] or throws [IllegalArgumentException]
+ * if not defined.
+ *
+ * @see TypedArray.hasValue
+ * @see TypedArray.getString
+ */
+fun TypedArray.getStringOrThrow(@StyleableRes index: Int): String {
+    checkAttribute(index)
+    return checkNotNull(getString(index)) {
+        "Attribute value could not be coerced to String."
+    }
+}
+
+/**
+ * Retrieve the text value for the attribute at [index] or throws [IllegalArgumentException]
+ * if not defined.
+ *
+ * @see TypedArray.hasValue
+ * @see TypedArray.getText
+ */
+fun TypedArray.getTextOrThrow(@StyleableRes index: Int): CharSequence {
+    checkAttribute(index)
+    return checkNotNull(getText(index)) {
+        "Attribute value could not be coerced to CharSequence."
+    }
+}
+
+/**
+ * Retrieve the text array value for the attribute at [index] or throws
+ * [IllegalArgumentException] if not defined.
+ *
+ * @see TypedArray.hasValue
+ * @see TypedArray.getTextArray
+ */
+fun TypedArray.getTextArrayOrThrow(@StyleableRes index: Int): Array<CharSequence> {
+    checkAttribute(index)
+    return getTextArray(index)
+}
+
+/**
+ * Executes the given [block] function on this TypedArray and then recycles it.
+ *
+ * @see kotlin.io.use
+ */
+inline fun <R> TypedArray.use(block: (TypedArray) -> R): R {
+    return block(this).also {
+        recycle()
+    }
+}
diff --git a/core/ktx/src/main/java/androidx/core/database/Cursor.kt b/core/ktx/src/main/java/androidx/core/database/Cursor.kt
new file mode 100644
index 0000000..b63e719
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/database/Cursor.kt
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to other public API.
+
+package androidx.core.database
+
+import android.database.Cursor
+
+/**
+ * Returns the value of the requested column as a byte array.
+ *
+ * The result and whether this method throws an exception when the column value is null or the
+ * column type is not a blob type is implementation-defined.
+ *
+ * @see Cursor.getColumnIndexOrThrow
+ * @see Cursor.getBlob
+ */
+inline fun Cursor.getBlob(columnName: String): ByteArray =
+    getBlob(getColumnIndexOrThrow(columnName))
+
+/**
+ * Returns the value of the requested column as a double.
+ *
+ * The result and whether this method throws an exception when the column value is null or the
+ * column type is not a floating-point type is implementation-defined.
+ *
+ * @see Cursor.getColumnIndexOrThrow
+ * @see Cursor.getDouble
+ */
+inline fun Cursor.getDouble(columnName: String): Double =
+    getDouble(getColumnIndexOrThrow(columnName))
+
+/**
+ * Returns the value of the requested column as a float.
+ *
+ * The result and whether this method throws an exception when the column value is null or the
+ * column type is not a floating-point type is implementation-defined.
+ *
+ * @see Cursor.getColumnIndexOrThrow
+ * @see Cursor.getFloat
+ */
+inline fun Cursor.getFloat(columnName: String): Float = getFloat(getColumnIndexOrThrow(columnName))
+
+/**
+ * Returns the value of the requested column as an integer.
+ *
+ * The result and whether this method throws an exception when the column value is null or the
+ * column type is not an integral type is implementation-defined.
+ *
+ * @see Cursor.getColumnIndexOrThrow
+ * @see Cursor.getInt
+ */
+inline fun Cursor.getInt(columnName: String): Int = getInt(getColumnIndexOrThrow(columnName))
+
+/**
+ * Returns the value of the requested column as a long.
+ *
+ * The result and whether this method throws an exception when the column value is null or the
+ * column type is not an integral type is implementation-defined.
+ *
+ * @see Cursor.getColumnIndexOrThrow
+ * @see Cursor.getLong
+ */
+inline fun Cursor.getLong(columnName: String): Long = getLong(getColumnIndexOrThrow(columnName))
+
+/**
+ * Returns the value of the requested column as a short.
+ *
+ * The result and whether this method throws an exception when the column value is null or the
+ * column type is not an integral type is implementation-defined.
+ *
+ * @see Cursor.getColumnIndexOrThrow
+ * @see Cursor.getShort
+ */
+inline fun Cursor.getShort(columnName: String): Short = getShort(getColumnIndexOrThrow(columnName))
+
+/**
+ * Returns the value of the requested column as a string.
+ *
+ * The result and whether this method throws an exception when the column value is null or the
+ * column type is not a string type is implementation-defined.
+ *
+ * @see Cursor.getColumnIndexOrThrow
+ * @see Cursor.getString
+ */
+inline fun Cursor.getString(columnName: String): String =
+    getString(getColumnIndexOrThrow(columnName))
+
+/**
+ * Returns the value of the requested column as a nullable byte array.
+ *
+ * The result and whether this method throws an exception when the column type is not a blob type is
+ * implementation-defined.
+ *
+ * @see Cursor.isNull
+ * @see Cursor.getBlob
+ */
+inline fun Cursor.getBlobOrNull(index: Int) = if (isNull(index)) null else getBlob(index)
+
+/**
+ * Returns the value of the requested column as a nullable double.
+ *
+ * The result and whether this method throws an exception when the column type is not a
+ * floating-point type is implementation-defined.
+ *
+ * @see Cursor.isNull
+ * @see Cursor.getDouble
+ */
+inline fun Cursor.getDoubleOrNull(index: Int) = if (isNull(index)) null else getDouble(index)
+
+/**
+ * Returns the value of the requested column as a nullable float.
+ *
+ * The result and whether this method throws an exception when the column type is not a
+ * floating-point type is implementation-defined.
+ *
+ * @see Cursor.isNull
+ * @see Cursor.getFloat
+ */
+inline fun Cursor.getFloatOrNull(index: Int) = if (isNull(index)) null else getFloat(index)
+
+/**
+ * Returns the value of the requested column as a nullable integer.
+ *
+ * The result and whether this method throws an exception when the column type is not an integral
+ * type is implementation-defined.
+ *
+ * @see Cursor.isNull
+ * @see Cursor.getInt
+ */
+inline fun Cursor.getIntOrNull(index: Int) = if (isNull(index)) null else getInt(index)
+
+/**
+ * Returns the value of the requested column as a nullable long.
+ *
+ * The result and whether this method throws an exception when the column type is not an integral
+ * type is implementation-defined.
+ *
+ * @see Cursor.isNull
+ * @see Cursor.getLong
+ */
+inline fun Cursor.getLongOrNull(index: Int) = if (isNull(index)) null else getLong(index)
+
+/**
+ * Returns the value of the requested column as a nullable short.
+ *
+ * The result and whether this method throws an exception when the column type is not an integral
+ * type is implementation-defined.
+ *
+ * @see Cursor.isNull
+ * @see Cursor.getShort
+ */
+inline fun Cursor.getShortOrNull(index: Int) = if (isNull(index)) null else getShort(index)
+
+/**
+ * Returns the value of the requested column as a nullable string.
+ *
+ * The result and whether this method throws an exception when the column type is not a string type
+ * is implementation-defined.
+ *
+ * @see Cursor.isNull
+ * @see Cursor.getString
+ */
+inline fun Cursor.getStringOrNull(index: Int) = if (isNull(index)) null else getString(index)
+
+/**
+ * Returns the value of the requested column as a nullable byte array.
+ *
+ * The result and whether this method throws an exception when the column type is not a blob type is
+ * implementation-defined.
+ *
+ * @see Cursor.getColumnIndexOrThrow
+ * @see Cursor.isNull
+ * @see Cursor.getBlob
+ */
+inline fun Cursor.getBlobOrNull(columnName: String) =
+    getColumnIndexOrThrow(columnName).let { if (isNull(it)) null else getBlob(it) }
+
+/**
+ * Returns the value of the requested column as a nullable double.
+ *
+ * The result and whether this method throws an exception when the column type is not a
+ * floating-point type is implementation-defined.
+ *
+ * @see Cursor.getColumnIndexOrThrow
+ * @see Cursor.isNull
+ * @see Cursor.getDouble
+ */
+inline fun Cursor.getDoubleOrNull(columnName: String) =
+    getColumnIndexOrThrow(columnName).let { if (isNull(it)) null else getDouble(it) }
+
+/**
+ * Returns the value of the requested column as a nullable float.
+ *
+ * The result and whether this method throws an exception when the column type is not a
+ * floating-point type is implementation-defined.
+ *
+ * @see Cursor.getColumnIndexOrThrow
+ * @see Cursor.isNull
+ * @see Cursor.getFloat
+ */
+inline fun Cursor.getFloatOrNull(columnName: String) =
+    getColumnIndexOrThrow(columnName).let { if (isNull(it)) null else getFloat(it) }
+
+/**
+ * Returns the value of the requested column as a nullable integer.
+ *
+ * The result and whether this method throws an exception when the column type is not an integral
+ * type is implementation-defined.
+ *
+ * @see Cursor.getColumnIndexOrThrow
+ * @see Cursor.isNull
+ * @see Cursor.getInt
+ */
+inline fun Cursor.getIntOrNull(columnName: String) =
+    getColumnIndexOrThrow(columnName).let { if (isNull(it)) null else getInt(it) }
+
+/**
+ * Returns the value of the requested column as a nullable long.
+ *
+ * The result and whether this method throws an exception when the column type is not an integral
+ * type is implementation-defined.
+ *
+ * @see Cursor.getColumnIndexOrThrow
+ * @see Cursor.isNull
+ * @see Cursor.getLong
+ */
+inline fun Cursor.getLongOrNull(columnName: String) =
+    getColumnIndexOrThrow(columnName).let { if (isNull(it)) null else getLong(it) }
+
+/**
+ * Returns the value of the requested column as a nullable short.
+ *
+ * The result and whether this method throws an exception when the column type is not an integral
+ * type is implementation-defined.
+ *
+ * @see Cursor.getColumnIndexOrThrow
+ * @see Cursor.isNull
+ * @see Cursor.getShort
+ */
+inline fun Cursor.getShortOrNull(columnName: String) =
+    getColumnIndexOrThrow(columnName).let { if (isNull(it)) null else getShort(it) }
+
+/**
+ * Returns the value of the requested column as a nullable string.
+ *
+ * The result and whether this method throws an exception when the column type is not a string type
+ * is implementation-defined.
+ *
+ * @see Cursor.getColumnIndexOrThrow
+ * @see Cursor.isNull
+ * @see Cursor.getString
+ */
+inline fun Cursor.getStringOrNull(columnName: String) =
+    getColumnIndexOrThrow(columnName).let { if (isNull(it)) null else getString(it) }
diff --git a/core/ktx/src/main/java/androidx/core/database/sqlite/SQLiteDatabase.kt b/core/ktx/src/main/java/androidx/core/database/sqlite/SQLiteDatabase.kt
new file mode 100644
index 0000000..bdbd94e
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/database/sqlite/SQLiteDatabase.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.database.sqlite
+
+import android.database.sqlite.SQLiteDatabase
+
+/**
+ * Run [body] in a transaction marking it as successful if it completes without exception.
+ *
+ * @param exclusive Run in `EXCLUSIVE` mode when true, `IMMEDIATE` mode otherwise.
+ */
+inline fun <T> SQLiteDatabase.transaction(
+    exclusive: Boolean = true,
+    body: SQLiteDatabase.() -> T
+): T {
+    if (exclusive) {
+        beginTransaction()
+    } else {
+        beginTransactionNonExclusive()
+    }
+    try {
+        val result = body()
+        setTransactionSuccessful()
+        return result
+    } finally {
+        endTransaction()
+    }
+}
diff --git a/core/ktx/src/main/java/androidx/core/graphics/Bitmap.kt b/core/ktx/src/main/java/androidx/core/graphics/Bitmap.kt
new file mode 100644
index 0000000..45ab6ba
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/graphics/Bitmap.kt
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE")
+
+package androidx.core.graphics
+
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.ColorSpace
+import androidx.annotation.ColorInt
+import androidx.annotation.RequiresApi
+
+/**
+ * Creates a new [Canvas] to draw on this bitmap and executes the specified
+ * [block] on the newly created canvas. Example:
+ *
+ * ```
+ * return Bitmap.createBitmap(…).applyCanvas {
+ *    drawLine(…)
+ *    translate(…)
+ *    drawRect(…)
+ * }
+ * ```
+ */
+inline fun Bitmap.applyCanvas(block: Canvas.() -> Unit): Bitmap {
+    val c = Canvas(this)
+    c.block()
+    return this
+}
+
+/**
+ * Returns the value of the pixel at the specified location. The returned value
+ * is a [color int][android.graphics.Color] in the sRGB color space.
+ */
+inline operator fun Bitmap.get(x: Int, y: Int) = getPixel(x, y)
+
+/**
+ * Writes the specified [color int][android.graphics.Color] into the bitmap
+ * (assuming it is mutable) at the specified `(x, y)` coordinate. The specified
+ * color is converted from sRGB to the bitmap's color space if needed.
+ */
+inline operator fun Bitmap.set(x: Int, y: Int, @ColorInt color: Int) = setPixel(x, y, color)
+
+/**
+ * Creates a new bitmap, scaled from this bitmap, when possible. If the specified
+ * [width] and [height] are the same as the current width and height of this bitmap,
+ * this bitmap is returned and no new bitmap is created.
+ *
+ * @param width The new bitmap's desired width
+ * @param height The new bitmap's desired height
+ * @param filter `true` if the source should be filtered (`true` by default)
+ *
+ * @return The new scaled bitmap or the source bitmap if no scaling is required.
+ */
+inline fun Bitmap.scale(width: Int, height: Int, filter: Boolean = true): Bitmap {
+    return Bitmap.createScaledBitmap(this, width, height, filter)
+}
+
+/**
+ * Returns a mutable bitmap with the specified [width] and [height]. A config
+ * can be optionally specified. If not, the default config is [Bitmap.Config.ARGB_8888].
+ *
+ * @param width The new bitmap's desired width
+ * @param height The new bitmap's desired height
+ * @param config The new bitmap's desired [config][Bitmap.Config]
+ *
+ * @return A new bitmap with the specified dimensions and config
+ */
+inline fun createBitmap(
+    width: Int,
+    height: Int,
+    config: Bitmap.Config = Bitmap.Config.ARGB_8888
+): Bitmap {
+    return Bitmap.createBitmap(width, height, config)
+}
+
+/**
+ * Returns a mutable bitmap with the specified [width] and [height]. The config,
+ * transparency and color space can optionally be specified. They respectively
+ * default to [Bitmap.Config.ARGB_8888], `true` and [sRGB][ColorSpace.Named.SRGB].
+ *
+ * @param width The new bitmap's desired width
+ * @param height The new bitmap's desired height
+ * @param config The new bitmap's desired [config][Bitmap.Config]
+ * @param hasAlpha Whether the new bitmap is opaque or not
+ * @param colorSpace The new bitmap's color space
+ *
+ * @return A new bitmap with the specified dimensions and config
+ */
+@RequiresApi(26)
+inline fun createBitmap(
+    width: Int,
+    height: Int,
+    config: Bitmap.Config = Bitmap.Config.ARGB_8888,
+    hasAlpha: Boolean = true,
+    colorSpace: ColorSpace = ColorSpace.get(ColorSpace.Named.SRGB)
+): Bitmap {
+    return Bitmap.createBitmap(width, height, config, hasAlpha, colorSpace)
+}
diff --git a/core/ktx/src/main/java/androidx/core/graphics/Canvas.kt b/core/ktx/src/main/java/androidx/core/graphics/Canvas.kt
new file mode 100644
index 0000000..71efc08
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/graphics/Canvas.kt
@@ -0,0 +1,125 @@
+/*
+ * 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 androidx.core.graphics
+
+import android.graphics.Canvas
+import android.graphics.Matrix
+
+/**
+ * Wrap the specified [block] in calls to [Canvas.save]
+ * and [Canvas.restoreToCount].
+ */
+inline fun Canvas.withSave(block: Canvas.() -> Unit) {
+    val checkpoint = save()
+    try {
+        block()
+    } finally {
+        restoreToCount(checkpoint)
+    }
+}
+
+/**
+ * Wrap the specified [block] in calls to [Canvas.save]/[Canvas.translate]
+ * and [Canvas.restoreToCount].
+ */
+inline fun Canvas.withTranslation(
+    x: Float = 0.0f,
+    y: Float = 0.0f,
+    block: Canvas.() -> Unit
+) {
+    val checkpoint = save()
+    translate(x, y)
+    try {
+        block()
+    } finally {
+        restoreToCount(checkpoint)
+    }
+}
+
+/**
+ * Wrap the specified [block] in calls to [Canvas.save]/[Canvas.rotate]
+ * and [Canvas.restoreToCount].
+ */
+inline fun Canvas.withRotation(
+    degrees: Float = 0.0f,
+    pivotX: Float = 0.0f,
+    pivotY: Float = 0.0f,
+    block: Canvas.() -> Unit
+) {
+    val checkpoint = save()
+    rotate(degrees, pivotX, pivotY)
+    try {
+        block()
+    } finally {
+        restoreToCount(checkpoint)
+    }
+}
+
+/**
+ * Wrap the specified [block] in calls to [Canvas.save]/[Canvas.scale]
+ * and [Canvas.restoreToCount].
+ */
+inline fun Canvas.withScale(
+    x: Float = 1.0f,
+    y: Float = 1.0f,
+    pivotX: Float = 0.0f,
+    pivotY: Float = 0.0f,
+    block: Canvas.() -> Unit
+) {
+    val checkpoint = save()
+    scale(x, y, pivotX, pivotY)
+    try {
+        block()
+    } finally {
+        restoreToCount(checkpoint)
+    }
+}
+
+/**
+ * Wrap the specified [block] in calls to [Canvas.save]/[Canvas.skew]
+ * and [Canvas.restoreToCount].
+ */
+inline fun Canvas.withSkew(
+    x: Float = 0.0f,
+    y: Float = 0.0f,
+    block: Canvas.() -> Unit
+) {
+    val checkpoint = save()
+    skew(x, y)
+    try {
+        block()
+    } finally {
+        restoreToCount(checkpoint)
+    }
+}
+
+/**
+ * Wrap the specified [block] in calls to [Canvas.save]/[Canvas.concat]
+ * and [Canvas.restoreToCount].
+ */
+inline fun Canvas.withMatrix(
+    matrix: Matrix = Matrix(),
+    block: Canvas.() -> Unit
+) {
+    val checkpoint = save()
+    concat(matrix)
+    try {
+        block()
+    } finally {
+        restoreToCount(checkpoint)
+    }
+}
diff --git a/core/ktx/src/main/java/androidx/core/graphics/Color.kt b/core/ktx/src/main/java/androidx/core/graphics/Color.kt
new file mode 100644
index 0000000..f853422
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/graphics/Color.kt
@@ -0,0 +1,364 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE", "WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE")
+
+package androidx.core.graphics
+
+import android.graphics.Color
+import android.graphics.ColorSpace
+import androidx.annotation.ColorInt
+import androidx.annotation.ColorLong
+import androidx.annotation.RequiresApi
+
+/**
+ * Returns the first component of the color. For instance, when the color model
+ * of the color is [android.graphics.ColorSpace.Model.RGB], the first component
+ * is "red".
+ *
+ * This method allows to use destructuring declarations when working with colors,
+ * for example:
+ * ```
+ * val (red, green, blue) = myColor
+ * ```
+ */
+@RequiresApi(26)
+inline operator fun Color.component1() = getComponent(0)
+
+/**
+ * Returns the second component of the color. For instance, when the color model
+ * of the color is [android.graphics.ColorSpace.Model.RGB], the second component
+ * is "green".
+ *
+ * This method allows to use destructuring declarations when working with colors,
+ * for example:
+ * ```
+ * val (red, green, blue) = myColor
+ * ```
+ */
+@RequiresApi(26)
+inline operator fun Color.component2() = getComponent(1)
+
+/**
+ * Returns the third component of the color. For instance, when the color model
+ * of the color is [android.graphics.ColorSpace.Model.RGB], the third component
+ * is "blue".
+= *
+ * This method allows to use destructuring declarations when working with colors,
+ * for example:
+ * ```
+ * val (red, green, blue) = myColor
+ * ```
+ */
+@RequiresApi(26)
+inline operator fun Color.component3() = getComponent(2)
+
+/**
+ * Returns the fourth component of the color. For instance, when the color model
+ * of the color is [android.graphics.ColorSpace.Model.RGB], the fourth component
+ * is "alpha".
+ *
+ * This method allows to use destructuring declarations when working with colors,
+ * for example:
+ * ```
+ * val (red, green, blue, alpha) = myColor
+ * ```
+ */
+@RequiresApi(26)
+inline operator fun Color.component4() = getComponent(3)
+
+/**
+ * Composites two translucent colors together. More specifically, adds two colors using
+ * the [source over][android.graphics.PorterDuff.Mode.SRC_OVER] blending mode. The colors
+ * must not be pre-multiplied and the result is a non pre-multiplied color.
+ *
+ * If the two colors have different color spaces, the color in the right-hand part
+ * of the expression is converted to the color space of the color in left-hand part
+ * of the expression.
+ *
+ * The following example creates a purple color by blending opaque blue with
+ * semi-translucent red:
+ *
+ * ```
+ * val purple = Color.valueOf(0f, 0f, 1f) + Color.valueOf(1f, 0f, 0f, 0.5f)
+ * ```
+ *
+ * @throws IllegalArgumentException if the [color models][android.graphics.Color.getModel]
+ *                                  of the colors do not match
+ */
+@RequiresApi(26)
+operator fun Color.plus(c: Color): Color = ColorUtils.compositeColors(c, this)
+
+/**
+ * Return the alpha component of a color int. This is equivalent to calling:
+ * ```
+ * Color.alpha(myInt)
+ * ```
+ */
+inline val @receiver:ColorInt Int.alpha get() = (this shr 24) and 0xff
+
+/**
+ * Return the red component of a color int. This is equivalent to calling:
+ * ```
+ * Color.red(myInt)
+ * ```
+ */
+inline val @receiver:ColorInt Int.red get() = (this shr 16) and 0xff
+
+/**
+ * Return the green component of a color int. This is equivalent to calling:
+ * ```
+ * Color.green(myInt)
+ * ```
+ */
+inline val @receiver:ColorInt Int.green get() = (this shr 8) and 0xff
+
+/**
+ * Return the blue component of a color int. This is equivalent to calling:
+ * ```
+ * Color.blue(myInt)
+ * ```
+ */
+inline val @receiver:ColorInt Int.blue get() = this and 0xff
+
+/**
+ * Return the alpha component of a color int. This is equivalent to calling:
+ * ```
+ * Color.alpha(myInt)
+ * ```
+ *
+ * This method allows to use destructuring declarations when working with colors,
+ * for example:
+ * ```
+ * val (alpha, red, green, blue) = myColor
+ * ```
+ */
+inline operator fun @receiver:ColorInt Int.component1() = (this shr 24) and 0xff
+
+/**
+ * Return the red component of a color int. This is equivalent to calling:
+ * ```
+ * Color.red(myInt)
+ * ```
+ *
+ * This method allows to use destructuring declarations when working with colors,
+ * for example:
+ * ```
+ * val (alpha, red, green, blue) = myColor
+ * ```
+ */
+inline operator fun @receiver:ColorInt Int.component2() = (this shr 16) and 0xff
+
+/**
+ * Return the green component of a color int. This is equivalent to calling:
+ * ```
+ * Color.green(myInt)
+ * ```
+ *
+ * This method allows to use destructuring declarations when working with colors,
+ * for example:
+ * ```
+ * val (alpha, red, green, blue) = myColor
+ * ```
+ */
+inline operator fun @receiver:ColorInt Int.component3() = (this shr 8) and 0xff
+
+/**
+ * Return the blue component of a color int. This is equivalent to calling:
+ * ```
+ * Color.blue(myInt)
+ * ```
+ *
+ * This method allows to use destructuring declarations when working with colors,
+ * for example:
+ * ```
+ * val (alpha, red, green, blue) = myColor
+ * ```
+ */
+inline operator fun @receiver:ColorInt Int.component4() = this and 0xff
+
+/**
+ * Returns the relative luminance of a color int, assuming sRGB encoding.
+ * Based on the formula for relative luminance defined in WCAG 2.0,
+ * W3C Recommendation 11 December 2008.
+ */
+@get:RequiresApi(26)
+inline val @receiver:ColorInt Int.luminance get() = Color.luminance(this)
+
+/**
+ * Creates a new [Color] instance from a color int. The resulting color
+ * is in the [sRGB][android.graphics.ColorSpace.Named.SRGB] color space.
+ */
+@RequiresApi(26)
+inline fun @receiver:ColorInt Int.toColor(): Color = Color.valueOf(this)
+
+/**
+ * Converts the specified ARGB [color int][Color] to an RGBA [color long][Color]
+ * in the [sRGB][android.graphics.ColorSpace.Named.SRGB] color space.
+ */
+@RequiresApi(26)
+@ColorLong
+inline fun @receiver:ColorInt Int.toColorLong() = Color.pack(this)
+
+/**
+ * Returns the first component of the color. For instance, when the color model
+ * of the color is [android.graphics.ColorSpace.Model.RGB], the first component
+ * is "red".
+ *
+ * This method allows to use destructuring declarations when working with colors,
+ * for example:
+ * ```
+ * val (red, green, blue, alpha) = myColorLong
+ * ```
+ */
+@RequiresApi(26)
+inline operator fun @receiver:ColorLong Long.component1() = Color.red(this)
+
+/**
+ * Returns the second component of the color. For instance, when the color model
+ * of the color is [android.graphics.ColorSpace.Model.RGB], the second component
+ * is "green".
+ *
+ * This method allows to use destructuring declarations when working with colors,
+ * for example:
+ * ```
+ * val (red, green, blue, alpha) = myColorLong
+ * ```
+ */
+@RequiresApi(26)
+inline operator fun @receiver:ColorLong Long.component2() = Color.green(this)
+
+/**
+ * Returns the third component of the color. For instance, when the color model
+ * of the color is [android.graphics.ColorSpace.Model.RGB], the third component
+ * is "blue".
+ *
+ * This method allows to use destructuring declarations when working with colors,
+ * for example:
+ * ```
+ * val (red, green, blue, alpha) = myColorLong
+ * ```
+ */
+@RequiresApi(26)
+inline operator fun @receiver:ColorLong Long.component3() = Color.blue(this)
+
+/**
+ * Returns the fourth component of the color. For instance, when the color model
+ * of the color is [android.graphics.ColorSpace.Model.RGB], the fourth component
+ * is "alpha".
+ *
+ * This method allows to use destructuring declarations when working with colors,
+ * for example:
+ * ```
+ * val (red, green, blue, alpha) = myColorLong
+ * ```
+ */
+@RequiresApi(26)
+inline operator fun @receiver:ColorLong Long.component4() = Color.alpha(this)
+
+/**
+ * Return the alpha component of a color long. This is equivalent to calling:
+ * ```
+ * Color.alpha(myLong)
+ * ```
+ */
+@get:RequiresApi(26)
+inline val @receiver:ColorLong Long.alpha get() = Color.alpha(this)
+
+/**
+ * Return the red component of a color long. This is equivalent to calling:
+ * ```
+ * Color.red(myLong)
+ * ```
+ */
+@get:RequiresApi(26)
+inline val @receiver:ColorLong Long.red get() = Color.red(this)
+
+/**
+ * Return the green component of a color long. This is equivalent to calling:
+ * ```
+ * Color.green(myLong)
+ * ```
+ */
+@get:RequiresApi(26)
+inline val @receiver:ColorLong Long.green get() = Color.green(this)
+
+/**
+ * Return the blue component of a color long. This is equivalent to calling:
+ * ```
+ * Color.blue(myLong)
+ * ```
+ */
+@get:RequiresApi(26)
+inline val @receiver:ColorLong Long.blue get() = Color.blue(this)
+
+/**
+ * Returns the relative luminance of a color. Based on the formula for
+ * relative luminance defined in WCAG 2.0, W3C Recommendation 11 December 2008.
+ */
+@get:RequiresApi(26)
+inline val @receiver:ColorLong Long.luminance get() = Color.luminance(this)
+
+/**
+ * Creates a new [Color] instance from a [color long][Color].
+ */
+@RequiresApi(26)
+inline fun @receiver:ColorLong Long.toColor(): Color = Color.valueOf(this)
+
+/**
+ * Converts the specified [color long][Color] to an ARGB [color int][Color].
+ */
+@RequiresApi(26)
+@ColorInt
+inline fun @receiver:ColorLong Long.toColorInt() = Color.toArgb(this)
+
+/**
+ * Indicates whether the color is in the [sRGB][android.graphics.ColorSpace.Named.SRGB]
+ * color space.
+ */
+@get:RequiresApi(26)
+inline val @receiver:ColorLong Long.isSrgb get() = Color.isSrgb(this)
+
+/**
+ * Indicates whether the color is in a [wide-gamut][android.graphics.ColorSpace] color space.
+ */
+@get:RequiresApi(26)
+inline val @receiver:ColorLong Long.isWideGamut get() = Color.isWideGamut(this)
+
+/**
+ * Returns the color space encoded in the specified color long.
+ */
+@get:RequiresApi(26)
+inline val @receiver:ColorLong Long.colorSpace: ColorSpace get() = Color.colorSpace(this)
+
+/**
+ * Return a corresponding [Int] color of this [String].
+ *
+ * Supported formats are:
+ * ```
+ * #RRGGBB
+ * #AARRGGBB
+ * ```
+ *
+ * The following names are also accepted: "red", "blue", "green", "black", "white",
+ * "gray", "cyan", "magenta", "yellow", "lightgray", "darkgray",
+ * "grey", "lightgrey", "darkgrey", "aqua", "fuchsia", "lime",
+ * "maroon", "navy", "olive", "purple", "silver", "teal".
+ *
+ * @throws IllegalArgumentException if this [String] cannot be parsed.
+ */
+@ColorInt
+inline fun String.toColorInt(): Int = Color.parseColor(this)
diff --git a/core/ktx/src/main/java/androidx/core/graphics/Matrix.kt b/core/ktx/src/main/java/androidx/core/graphics/Matrix.kt
new file mode 100644
index 0000000..5cb0cdf
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/graphics/Matrix.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE")
+
+package androidx.core.graphics
+
+import android.graphics.Matrix
+
+/**
+ * Multiplies this [Matrix] by another matrix and returns the result as
+ * a new matrix.
+ */
+inline operator fun Matrix.times(m: Matrix) = Matrix(this).apply { preConcat(m) }
+
+/**
+ * Returns the 9 values of this [Matrix] as a new array of floats.
+ */
+inline fun Matrix.values() = FloatArray(9).apply { getValues(this) }
+
+/**
+ * Creates a translation matrix with the translation amounts [tx] and [ty]
+ * respectively on the `x` and `y` axis.
+ */
+fun translationMatrix(tx: Float = 0.0f, ty: Float = 0.0f) = Matrix().apply { setTranslate(tx, ty) }
+
+/**
+ * Creates a scale matrix with the scale factor [sx] and [sy] respectively on the
+ * `x` and `y` axis.
+ */
+fun scaleMatrix(sx: Float = 1.0f, sy: Float = 1.0f) = Matrix().apply { setScale(sx, sy) }
+
+/**
+ * Creates a rotation matrix, defined by a rotation angle in degrees around the pivot
+ * point located at the coordinates ([px], [py]).
+ */
+fun rotationMatrix(degrees: Float, px: Float = 0.0f, py: Float = 0.0f) =
+    Matrix().apply { setRotate(degrees, px, py) }
diff --git a/core/ktx/src/main/java/androidx/core/graphics/Path.kt b/core/ktx/src/main/java/androidx/core/graphics/Path.kt
new file mode 100644
index 0000000..ca70533
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/graphics/Path.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE")
+
+package androidx.core.graphics
+
+import android.graphics.Path
+import androidx.annotation.RequiresApi
+
+/**
+ * Flattens (or approximate) the [Path] with a series of line segments.
+ *
+ * @param error The acceptable error for a line on the Path. Typically this would be
+ *              0.5 so that the error is less than half a pixel. This value must be
+ *              positive and is set to 0.5 by default.
+ *
+ * @see Path.approximate
+ */
+@RequiresApi(26)
+fun Path.flatten(error: Float = 0.5f): Iterable<PathSegment> = PathUtils.flatten(this, error)
+
+/**
+ * Returns the union of two paths as a new [Path].
+ */
+@RequiresApi(19)
+inline operator fun Path.plus(p: Path): Path {
+    return Path(this).apply {
+        op(p, Path.Op.UNION)
+    }
+}
+
+/**
+ * Returns the difference of two paths as a new [Path].
+ */
+@RequiresApi(19)
+inline operator fun Path.minus(p: Path): Path {
+    return Path(this).apply {
+        op(p, Path.Op.DIFFERENCE)
+    }
+}
+
+/**
+ * Returns the union of two paths as a new [Path].
+ */
+@RequiresApi(19)
+inline infix fun Path.and(p: Path) = this + p
+
+/**
+ * Returns the intersection of two paths as a new [Path].
+ * If the paths do not intersect, returns an empty path.
+ */
+@RequiresApi(19)
+inline infix fun Path.or(p: Path): Path {
+    return Path().apply {
+        op(this@or, p, Path.Op.INTERSECT)
+    }
+}
+
+/**
+ * Returns the union minus the intersection of two paths as a new [Path].
+ */
+@RequiresApi(19)
+inline infix fun Path.xor(p: Path): Path {
+    return Path(this).apply {
+        op(p, Path.Op.XOR)
+    }
+}
diff --git a/core/ktx/src/main/java/androidx/core/graphics/Picture.kt b/core/ktx/src/main/java/androidx/core/graphics/Picture.kt
new file mode 100644
index 0000000..d1e8c99
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/graphics/Picture.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 20188 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.
+ */
+@file:Suppress("NOTHING_TO_INLINE")
+
+package androidx.core.graphics
+
+import android.graphics.Canvas
+import android.graphics.Picture
+
+/**
+ * Creates a new [Canvas] to record commands in this [Picture], executes the specified
+ * [block] on the newly created canvas and returns this [Picture]. Example:
+ *
+ * ```
+ * return myPicture.record(1280, 720) {
+ *    drawLine(…)
+ *    translate(…)
+ *    drawRect(…)
+ * }
+ * ```
+ */
+inline fun Picture.record(width: Int, height: Int, block: Canvas.() -> Unit): Picture {
+    val c = beginRecording(width, height)
+    try {
+        c.block()
+    } finally {
+        endRecording()
+    }
+    return this
+}
diff --git a/core/ktx/src/main/java/androidx/core/graphics/Point.kt b/core/ktx/src/main/java/androidx/core/graphics/Point.kt
new file mode 100644
index 0000000..b6e35e6
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/graphics/Point.kt
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE")
+
+package androidx.core.graphics
+
+import android.graphics.Point
+import android.graphics.PointF
+
+/**
+ * Returns the x coordinate of this point.
+ *
+ * This method allows to use destructuring declarations when working with points,
+ * for example:
+ * ```
+ * val (x, y) = myPoint
+ * ```
+ */
+inline operator fun Point.component1() = this.x
+
+/**
+ * Returns the y coordinate of this point.
+ *
+ * This method allows to use destructuring declarations when working with points,
+ * for example:
+ * ```
+ * val (x, y) = myPoint
+ * ```
+ */
+inline operator fun Point.component2() = this.y
+
+/**
+ * Returns the x coordinate of this point.
+ *
+ * This method allows to use destructuring declarations when working with points,
+ * for example:
+ * ```
+ * val (x, y) = myPoint
+ * ```
+ */
+inline operator fun PointF.component1() = this.x
+
+/**
+ * Returns the y coordinate of this point.
+ *
+ * This method allows to use destructuring declarations when working with points,
+ * for example:
+ * ```
+ * val (x, y) = myPoint
+ * ```
+ */
+inline operator fun PointF.component2() = this.y
+
+/**
+ * Offsets this point by the specified point and returns the result as a new point.
+ */
+inline operator fun Point.plus(p: Point): Point {
+    return Point(x, y).apply {
+        offset(p.x, p.y)
+    }
+}
+
+/**
+ * Offsets this point by the specified point and returns the result as a new point.
+ */
+inline operator fun PointF.plus(p: PointF): PointF {
+    return PointF(x, y).apply {
+        offset(p.x, p.y)
+    }
+}
+
+/**
+ * Offsets this point by the specified amount on both X and Y axis and returns the
+ * result as a new point.
+ */
+inline operator fun Point.plus(xy: Int): Point {
+    return Point(x, y).apply {
+        offset(xy, xy)
+    }
+}
+
+/**
+ * Offsets this point by the specified amount on both X and Y axis and returns the
+ * result as a new point.
+ */
+inline operator fun PointF.plus(xy: Float): PointF {
+    return PointF(x, y).apply {
+        offset(xy, xy)
+    }
+}
+
+/**
+ * Offsets this point by the negation of the specified point and returns the result
+ * as a new point.
+ */
+inline operator fun Point.minus(p: Point): Point {
+    return Point(x, y).apply {
+        offset(-p.x, -p.y)
+    }
+}
+
+/**
+ * Offsets this point by the negation of the specified point and returns the result
+ * as a new point.
+ */
+inline operator fun PointF.minus(p: PointF): PointF {
+    return PointF(x, y).apply {
+        offset(-p.x, -p.y)
+    }
+}
+
+/**
+ * Offsets this point by the negation of the specified amount on both X and Y axis and
+ * returns the result as a new point.
+ */
+inline operator fun Point.minus(xy: Int): Point {
+    return Point(x, y).apply {
+        offset(-xy, -xy)
+    }
+}
+
+/**
+ * Offsets this point by the negation of the specified amount on both X and Y axis and
+ * returns the result as a new point.
+ */
+inline operator fun PointF.minus(xy: Float): PointF {
+    return PointF(x, y).apply {
+        offset(-xy, -xy)
+    }
+}
+
+/**
+ * Returns a new point representing the negation of this point.
+ */
+inline operator fun Point.unaryMinus() = Point(-x, -y)
+
+/**
+ * Returns a new point representing the negation of this point.
+ */
+inline operator fun PointF.unaryMinus() = PointF(-x, -y)
+
+/**
+ * Returns a [PointF] representation of this point.
+ */
+inline fun Point.toPointF() = PointF(this)
+
+/**
+ * Returns a [Point] representation of this point.
+ */
+inline fun PointF.toPoint() = Point(x.toInt(), y.toInt())
diff --git a/core/ktx/src/main/java/androidx/core/graphics/PorterDuff.kt b/core/ktx/src/main/java/androidx/core/graphics/PorterDuff.kt
new file mode 100644
index 0000000..a34d6f9
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/graphics/PorterDuff.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE")
+
+package androidx.core.graphics
+
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffColorFilter
+import android.graphics.PorterDuffXfermode
+
+/**
+ * Creates a new [PorterDuffXfermode] that uses this [PorterDuff.Mode] as the
+ * alpha compositing or blending mode.
+ */
+inline fun PorterDuff.Mode.toXfermode() = PorterDuffXfermode(this)
+
+/**
+ * Creates a new [PorterDuffColorFilter] that uses this [PorterDuff.Mode] as the
+ * alpha compositing or blending mode, and the specified [color].
+ */
+inline fun PorterDuff.Mode.toColorFilter(color: Int) = PorterDuffColorFilter(color, this)
diff --git a/core/ktx/src/main/java/androidx/core/graphics/Rect.kt b/core/ktx/src/main/java/androidx/core/graphics/Rect.kt
new file mode 100644
index 0000000..960c0c5
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/graphics/Rect.kt
@@ -0,0 +1,335 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE")
+
+package androidx.core.graphics
+
+import android.annotation.SuppressLint
+import android.graphics.Matrix
+import android.graphics.Point
+import android.graphics.PointF
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.Region
+
+/**
+ * Returns "left", the first component of the rectangle.
+ *
+ * This method allows to use destructuring declarations when working with rectangles,
+ * for example:
+ * ```
+ * val (left, top, right, bottom) = myRectangle
+ * ```
+ */
+inline operator fun Rect.component1() = this.left
+
+/**
+ * Returns "top", the second component of the rectangle.
+ *
+ * This method allows to use destructuring declarations when working with rectangles,
+ * for example:
+ * ```
+ * val (left, top, right, bottom) = myRectangle
+ * ```
+ */
+inline operator fun Rect.component2() = this.top
+
+/**
+ * Returns "right", the third component of the rectangle.
+ *
+ * This method allows to use destructuring declarations when working with rectangles,
+ * for example:
+ * ```
+ * val (left, top, right, bottom) = myRectangle
+ * ```
+ */
+inline operator fun Rect.component3() = this.right
+
+/**
+ * Returns "bottom", the fourth component of the rectangle.
+ *
+ * This method allows to use destructuring declarations when working with rectangles,
+ * for example:
+ * ```
+ * val (left, top, right, bottom) = myRectangle
+ * ```
+ */
+inline operator fun Rect.component4() = this.bottom
+
+/**
+ * Returns "left", the first component of the rectangle.
+ *
+ * This method allows to use destructuring declarations when working with rectangles,
+ * for example:
+ * ```
+ * val (left, top, right, bottom) = myRectangle
+ * ```
+ */
+inline operator fun RectF.component1() = this.left
+
+/**
+ * Returns "top", the second component of the rectangle.
+ *
+ * This method allows to use destructuring declarations when working with rectangles,
+ * for example:
+ * ```
+ * val (left, top, right, bottom) = myRectangle
+ * ```
+ */
+inline operator fun RectF.component2() = this.top
+
+/**
+ * Returns "right", the third component of the rectangle.
+ *
+ * This method allows to use destructuring declarations when working with rectangles,
+ * for example:
+ * ```
+ * val (left, top, right, bottom) = myRectangle
+ * ```
+ */
+inline operator fun RectF.component3() = this.right
+
+/**
+ * Returns "bottom", the fourth component of the rectangle.
+ *
+ * This method allows to use destructuring declarations when working with rectangles,
+ * for example:
+ * ```
+ * val (left, top, right, bottom) = myRectangle
+ * ```
+ */
+inline operator fun RectF.component4() = this.bottom
+
+/**
+ * Performs the union of this rectangle and the specified rectangle and returns
+ * the result as a new rectangle.
+ */
+inline operator fun Rect.plus(r: Rect): Rect {
+    return Rect(this).apply {
+        union(r)
+    }
+}
+
+/**
+ * Performs the union of this rectangle and the specified rectangle and returns
+ * the result as a new rectangle.
+ */
+inline operator fun RectF.plus(r: RectF): RectF {
+    return RectF(this).apply {
+        union(r)
+    }
+}
+
+/**
+ * Returns a new rectangle representing this rectangle offset by the specified
+ * amount on both X and Y axis.
+ */
+inline operator fun Rect.plus(xy: Int): Rect {
+    return Rect(this).apply {
+        offset(xy, xy)
+    }
+}
+
+/**
+ * Returns a new rectangle representing this rectangle offset by the specified
+ * amount on both X and Y axis.
+ */
+inline operator fun RectF.plus(xy: Float): RectF {
+    return RectF(this).apply {
+        offset(xy, xy)
+    }
+}
+
+/**
+ * Returns a new rectangle representing this rectangle offset by the specified
+ * point.
+ */
+inline operator fun Rect.plus(xy: Point): Rect {
+    return Rect(this).apply {
+        offset(xy.x, xy.y)
+    }
+}
+
+/**
+ * Returns a new rectangle representing this rectangle offset by the specified
+ * point.
+ */
+inline operator fun RectF.plus(xy: PointF): RectF {
+    return RectF(this).apply {
+        offset(xy.x, xy.y)
+    }
+}
+
+/**
+ * Returns the difference of this rectangle and the specified rectangle as a new region.
+ */
+inline operator fun Rect.minus(r: Rect): Region {
+    return Region(this).apply {
+        op(r, Region.Op.DIFFERENCE)
+    }
+}
+
+/**
+ * Returns the difference of this rectangle and the specified rectangle as a new region.
+ * This rectangle is first converted to a [Rect] using [RectF.toRect].
+ */
+inline operator fun RectF.minus(r: RectF): Region {
+    return Region(this.toRect()).apply {
+        op(r.toRect(), Region.Op.DIFFERENCE)
+    }
+}
+
+/**
+ * Returns a new rectangle representing this rectangle offset by the negation
+ * of the specified amount on both X and Y axis.
+ */
+inline operator fun Rect.minus(xy: Int): Rect {
+    return Rect(this).apply {
+        offset(-xy, -xy)
+    }
+}
+
+/**
+ * Returns a new rectangle representing this rectangle offset by the negation
+ * of the specified amount on both X and Y axis.
+ */
+inline operator fun RectF.minus(xy: Float): RectF {
+    return RectF(this).apply {
+        offset(-xy, -xy)
+    }
+}
+
+/**
+ * Returns a new rectangle representing this rectangle offset by the negation of
+ * the specified point.
+ */
+inline operator fun Rect.minus(xy: Point): Rect {
+    return Rect(this).apply {
+        offset(-xy.x, -xy.y)
+    }
+}
+
+/**
+ * Returns a new rectangle representing this rectangle offset by the negation of
+ * the specified point.
+ */
+inline operator fun RectF.minus(xy: PointF): RectF {
+    return RectF(this).apply {
+        offset(-xy.x, -xy.y)
+    }
+}
+
+/**
+ * Returns the union of two rectangles as a new rectangle.
+ */
+inline infix fun Rect.and(r: Rect) = this + r
+
+/**
+ * Returns the union of two rectangles as a new rectangle.
+ */
+inline infix fun RectF.and(r: RectF) = this + r
+
+/**
+ * Returns the intersection of two rectangles as a new rectangle.
+ * If the rectangles do not intersect, returns a copy of the left hand side
+ * rectangle.
+ */
+@SuppressLint("CheckResult")
+inline infix fun Rect.or(r: Rect): Rect {
+    return Rect(this).apply {
+        intersect(r)
+    }
+}
+
+/**
+ * Returns the intersection of two rectangles as a new rectangle.
+ * If the rectangles do not intersect, returns a copy of the left hand side
+ * rectangle.
+ */
+@SuppressLint("CheckResult")
+inline infix fun RectF.or(r: RectF): RectF {
+    return RectF(this).apply {
+        intersect(r)
+    }
+}
+
+/**
+ * Returns the union minus the intersection of two rectangles as a new region.
+ */
+inline infix fun Rect.xor(r: Rect): Region {
+    return Region(this).apply {
+        op(r, Region.Op.XOR)
+    }
+}
+
+/**
+ * Returns the union minus the intersection of two rectangles as a new region.
+ * The two rectangles are first converted to [Rect] using [RectF.toRect].
+ */
+inline infix fun RectF.xor(r: RectF): Region {
+    return Region(this.toRect()).apply {
+        op(r.toRect(), Region.Op.XOR)
+    }
+}
+
+/**
+ * Returns true if the specified point is inside the rectangle.
+ * The left and top are considered to be inside, while the right and bottom are not.
+ * This means that for a point to be contained: left <= x < right and top <= y < bottom.
+ * An empty rectangle never contains any point.
+ */
+inline operator fun Rect.contains(p: Point) = contains(p.x, p.y)
+
+/**
+ * Returns true if the specified point is inside the rectangle.
+ * The left and top are considered to be inside, while the right and bottom are not.
+ * This means that for a point to be contained: left <= x < right and top <= y < bottom.
+ * An empty rectangle never contains any point.
+ */
+inline operator fun RectF.contains(p: PointF) = contains(p.x, p.y)
+
+/**
+ * Returns a [RectF] representation of this rectangle.
+ */
+inline fun Rect.toRectF(): RectF = RectF(this)
+
+/**
+ * Returns a [Rect] representation of this rectangle. The resulting rect will be sized such
+ * that this rect can fit within it.
+ */
+inline fun RectF.toRect(): Rect {
+    val r = Rect()
+    roundOut(r)
+    return r
+}
+
+/**
+ * Returns a [Region] representation of this rectangle.
+ */
+inline fun Rect.toRegion() = Region(this)
+
+/**
+ * Returns a [Region] representation of this rectangle. The resulting rect will be sized such
+ * that this rect can fit within it.
+ */
+inline fun RectF.toRegion() = Region(this.toRect())
+
+/**
+ * Transform this rectangle in place using the supplied [Matrix] and returns
+ * this rectangle.
+ */
+inline fun RectF.transform(m: Matrix) = apply { m.mapRect(this@transform) }
diff --git a/core/ktx/src/main/java/androidx/core/graphics/Region.kt b/core/ktx/src/main/java/androidx/core/graphics/Region.kt
new file mode 100644
index 0000000..4fc5179
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/graphics/Region.kt
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE")
+
+package androidx.core.graphics
+
+import android.graphics.Point
+import android.graphics.Rect
+import android.graphics.Region
+import android.graphics.RegionIterator
+
+/**
+ * Return true if the region contains the specified [Point].
+ */
+inline operator fun Region.contains(p: Point) = contains(p.x, p.y)
+
+/**
+ * Return the union of this region and the specified [Rect] as a new region.
+ */
+inline operator fun Region.plus(r: Rect): Region {
+    return Region(this).apply {
+        union(r)
+    }
+}
+
+/**
+ * Return the union of this region and the specified region as a new region.
+ */
+inline operator fun Region.plus(r: Region): Region {
+    return Region(this).apply {
+        op(r, Region.Op.UNION)
+    }
+}
+
+/**
+ * Return the difference of this region and the specified [Rect] as a new region.
+ */
+inline operator fun Region.minus(r: Rect): Region {
+    return Region(this).apply {
+        op(r, Region.Op.DIFFERENCE)
+    }
+}
+
+/**
+ * Return the difference of this region and the specified region as a new region.
+ */
+inline operator fun Region.minus(r: Region): Region {
+    return Region(this).apply {
+        op(r, Region.Op.DIFFERENCE)
+    }
+}
+
+/**
+ * Returns the negation of this region as a new region.
+ */
+inline operator fun Region.unaryMinus(): Region {
+    return Region(bounds).apply {
+        op(this@unaryMinus, Region.Op.DIFFERENCE)
+    }
+}
+
+/**
+ * Returns the negation of this region as a new region.
+ */
+inline operator fun Region.not() = -this
+
+/**
+ * Return the union of this region and the specified [Rect] as a new region.
+ */
+inline infix fun Region.and(r: Rect) = this + r
+
+/**
+ * Return the union of this region and the specified region as a new region.
+ */
+inline infix fun Region.and(r: Region) = this + r
+
+/**
+ * Return the intersection of this region and the specified [Rect] as a new region.
+ */
+inline infix fun Region.or(r: Rect): Region {
+    return Region(this).apply {
+        op(r, Region.Op.INTERSECT)
+    }
+}
+
+/**
+ * Return the intersection of this region and the specified region as a new region.
+ */
+inline infix fun Region.or(r: Region): Region {
+    return Region(this).apply {
+        op(r, Region.Op.INTERSECT)
+    }
+}
+
+/**
+ * Return the union minus the intersection of this region and the specified [Rect]
+ * as a new region.
+ */
+inline infix fun Region.xor(r: Rect): Region {
+    return Region(this).apply {
+        op(r, Region.Op.XOR)
+    }
+}
+
+/**
+ * Return the union minus the intersection of this region and the specified region
+ * as a new region.
+ */
+inline infix fun Region.xor(r: Region): Region {
+    return Region(this).apply {
+        op(r, Region.Op.XOR)
+    }
+}
+
+/** Performs the given action on each rect in this region. */
+inline fun Region.forEach(action: (rect: Rect) -> Unit) {
+    val iterator = RegionIterator(this)
+    while (true) {
+        val r = Rect()
+        if (!iterator.next(r)) {
+            break
+        }
+        action(r)
+    }
+}
+
+/** Returns an [Iterator] over the rects in this region. */
+operator fun Region.iterator() = object : Iterator<Rect> {
+    private val iterator = RegionIterator(this@iterator)
+    private val rect = Rect()
+    private var hasMore = iterator.next(rect)
+
+    override fun hasNext() = hasMore
+
+    override fun next(): Rect {
+        if (hasMore) {
+            val r = Rect(rect)
+            hasMore = iterator.next(rect)
+            return r
+        }
+        throw IndexOutOfBoundsException()
+    }
+}
diff --git a/core/ktx/src/main/java/androidx/core/graphics/Shader.kt b/core/ktx/src/main/java/androidx/core/graphics/Shader.kt
new file mode 100644
index 0000000..0fb93cb
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/graphics/Shader.kt
@@ -0,0 +1,30 @@
+/*
+ * 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 androidx.core.graphics
+
+import android.graphics.Matrix
+import android.graphics.Shader
+
+/**
+ * Wrap the specified [block] in calls to [Shader.getLocalMatrix] and [Shader.setLocalMatrix].
+ */
+inline fun Shader.transform(block: Matrix.() -> Unit) {
+    val matrix = Matrix()
+    getLocalMatrix(matrix)
+    block(matrix)
+    setLocalMatrix(matrix)
+}
diff --git a/core/ktx/src/main/java/androidx/core/graphics/drawable/BitmapDrawable.kt b/core/ktx/src/main/java/androidx/core/graphics/drawable/BitmapDrawable.kt
new file mode 100644
index 0000000..4a96aab
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/graphics/drawable/BitmapDrawable.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE", "WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE")
+
+package androidx.core.graphics.drawable
+
+import android.content.res.Resources
+import android.graphics.Bitmap
+import android.graphics.drawable.BitmapDrawable
+
+/** Create a [BitmapDrawable] from this [Bitmap]. */
+inline fun Bitmap.toDrawable(resources: Resources) = BitmapDrawable(resources, this)
diff --git a/core/ktx/src/main/java/androidx/core/graphics/drawable/ColorDrawable.kt b/core/ktx/src/main/java/androidx/core/graphics/drawable/ColorDrawable.kt
new file mode 100644
index 0000000..bef04df
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/graphics/drawable/ColorDrawable.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE", "WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE")
+
+package androidx.core.graphics.drawable
+
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import androidx.annotation.ColorInt
+import androidx.annotation.RequiresApi
+
+/** Create a [ColorDrawable] from this color value. */
+inline fun @receiver:ColorInt Int.toDrawable() = ColorDrawable(this)
+
+/** Create a [ColorDrawable] from this [Color] (via [Color.toArgb]). */
+@RequiresApi(26)
+inline fun Color.toDrawable() = ColorDrawable(toArgb())
diff --git a/core/ktx/src/main/java/androidx/core/graphics/drawable/Drawable.kt b/core/ktx/src/main/java/androidx/core/graphics/drawable/Drawable.kt
new file mode 100644
index 0000000..9e63bbd
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/graphics/drawable/Drawable.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.graphics.drawable
+
+import android.graphics.Bitmap
+import android.graphics.Bitmap.Config
+import android.graphics.Canvas
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import androidx.annotation.Px
+import androidx.core.graphics.component1
+import androidx.core.graphics.component2
+import androidx.core.graphics.component3
+import androidx.core.graphics.component4
+
+/**
+ * Return a [Bitmap] representation of this [Drawable].
+ *
+ * If this instance is a [BitmapDrawable] and the [width], [height], and [config] match, the
+ * underlying [Bitmap] instance will be returned directly. If any of those three properties differ
+ * then a new [Bitmap] is created. For all other [Drawable] types, a new [Bitmap] is created.
+ *
+ * @param width Width of the desired bitmap. Defaults to [Drawable.getIntrinsicWidth].
+ * @param height Height of the desired bitmap. Defaults to [Drawable.getIntrinsicHeight].
+ * @param config Bitmap config of the desired bitmap. Null attempts to use the native config, if
+ * any. Defaults to [Config.ARGB_8888] otherwise.
+ */
+fun Drawable.toBitmap(
+    @Px width: Int = intrinsicWidth,
+    @Px height: Int = intrinsicHeight,
+    config: Config? = null
+): Bitmap {
+    if (this is BitmapDrawable) {
+        if (config == null || bitmap.config == config) {
+            // Fast-path to return original. Bitmap.createScaledBitmap will do this check, but it
+            // involves allocation and two jumps into native code so we perform the check ourselves.
+            if (width == intrinsicWidth && height == intrinsicHeight) {
+                return bitmap
+            }
+            return Bitmap.createScaledBitmap(bitmap, width, height, true)
+        }
+    }
+
+    val (oldLeft, oldTop, oldRight, oldBottom) = bounds
+
+    val bitmap = Bitmap.createBitmap(width, height, config ?: Config.ARGB_8888)
+    setBounds(0, 0, width, height)
+    draw(Canvas(bitmap))
+
+    setBounds(oldLeft, oldTop, oldRight, oldBottom)
+    return bitmap
+}
+
+/**
+ * Updates this drawable's bounds. This version of the method allows using named parameters
+ * to just set one or more axes.
+ *
+ * @see Drawable.setBounds
+ */
+fun Drawable.updateBounds(
+    @Px left: Int = bounds.left,
+    @Px top: Int = bounds.top,
+    @Px right: Int = bounds.right,
+    @Px bottom: Int = bounds.bottom
+) {
+    setBounds(left, top, right, bottom)
+}
diff --git a/core/ktx/src/main/java/androidx/core/graphics/drawable/Icon.kt b/core/ktx/src/main/java/androidx/core/graphics/drawable/Icon.kt
new file mode 100644
index 0000000..a9077e2
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/graphics/drawable/Icon.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.core.graphics.drawable
+
+import android.graphics.Bitmap
+import android.graphics.drawable.Icon
+import android.net.Uri
+import androidx.annotation.RequiresApi
+
+/**
+ * Create an [Icon] from this adaptive [Bitmap].
+ *
+ * @see Icon.createWithAdaptiveBitmap
+ */
+@RequiresApi(26)
+inline fun Bitmap.toAdaptiveIcon(): Icon = Icon.createWithAdaptiveBitmap(this)
+
+/**
+ * Create an [Icon] from this [Bitmap].
+ *
+ * @see Icon.createWithBitmap
+ */
+@RequiresApi(26)
+inline fun Bitmap.toIcon(): Icon = Icon.createWithBitmap(this)
+
+/**
+ * Create an [Icon] from this [Uri].
+ *
+ * @see Icon.createWithContentUri
+ */
+@RequiresApi(26)
+inline fun Uri.toIcon(): Icon = Icon.createWithContentUri(this)
+
+/**
+ * Create an [Icon] from this [ByteArray].
+ *
+ * @see Icon.createWithData
+ */
+@RequiresApi(26)
+inline fun ByteArray.toIcon(): Icon = Icon.createWithData(this, 0, size)
diff --git a/core/ktx/src/main/java/androidx/core/net/Uri.kt b/core/ktx/src/main/java/androidx/core/net/Uri.kt
new file mode 100644
index 0000000..a5d9f1d
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/net/Uri.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.core.net
+
+import android.net.Uri
+import java.io.File
+
+/**
+ * Creates a Uri from the given encoded URI string.
+ *
+ * @see Uri.parse
+ */
+inline fun String.toUri(): Uri = Uri.parse(this)
+
+/**
+ * Creates a Uri from the given file.
+ *
+ * @see Uri.fromFile
+ */
+inline fun File.toUri(): Uri = Uri.fromFile(this)
+
+/** Creates a [File] from the given [Uri]. */
+inline fun Uri.toFile(): File = File(path)
diff --git a/core/ktx/src/main/java/androidx/core/os/Bundle.kt b/core/ktx/src/main/java/androidx/core/os/Bundle.kt
new file mode 100644
index 0000000..53da45d
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/os/Bundle.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.os
+
+import android.os.Binder
+import android.os.Build
+import android.os.Bundle
+import android.os.Parcelable
+import android.util.Size
+import android.util.SizeF
+import java.io.Serializable
+
+/**
+ * Returns a new [Bundle] with the given key/value pairs as elements.
+ *
+ * @throws IllegalArgumentException When a value is not a supported type of [Bundle].
+ */
+fun bundleOf(vararg pairs: Pair<String, Any?>) = Bundle(pairs.size).apply {
+    for ((key, value) in pairs) {
+        when (value) {
+            null -> putString(key, null) // Any nullable type will suffice.
+
+            // Scalars
+            is Boolean -> putBoolean(key, value)
+            is Byte -> putByte(key, value)
+            is Char -> putChar(key, value)
+            is Double -> putDouble(key, value)
+            is Float -> putFloat(key, value)
+            is Int -> putInt(key, value)
+            is Long -> putLong(key, value)
+            is Short -> putShort(key, value)
+
+            // References
+            is Bundle -> putBundle(key, value)
+            is CharSequence -> putCharSequence(key, value)
+            is Parcelable -> putParcelable(key, value)
+
+            // Scalar arrays
+            is BooleanArray -> putBooleanArray(key, value)
+            is ByteArray -> putByteArray(key, value)
+            is CharArray -> putCharArray(key, value)
+            is DoubleArray -> putDoubleArray(key, value)
+            is FloatArray -> putFloatArray(key, value)
+            is IntArray -> putIntArray(key, value)
+            is LongArray -> putLongArray(key, value)
+            is ShortArray -> putShortArray(key, value)
+
+            // Reference arrays
+            is Array<*> -> {
+                val componentType = value::class.java.componentType
+                @Suppress("UNCHECKED_CAST") // Checked by reflection.
+                when {
+                    Parcelable::class.java.isAssignableFrom(componentType) -> {
+                        putParcelableArray(key, value as Array<Parcelable>)
+                    }
+                    String::class.java.isAssignableFrom(componentType) -> {
+                        putStringArray(key, value as Array<String>)
+                    }
+                    CharSequence::class.java.isAssignableFrom(componentType) -> {
+                        putCharSequenceArray(key, value as Array<CharSequence>)
+                    }
+                    Serializable::class.java.isAssignableFrom(componentType) -> {
+                        putSerializable(key, value)
+                    }
+                    else -> {
+                        val valueType = componentType.canonicalName
+                        throw IllegalArgumentException(
+                            "Illegal value array type $valueType for key \"$key\"")
+                    }
+                }
+            }
+
+            // Last resort. Also we must check this after Array<*> as all arrays are serializable.
+            is Serializable -> putSerializable(key, value)
+
+            else -> {
+                if (Build.VERSION.SDK_INT >= 18 && value is Binder) {
+                    putBinder(key, value)
+                } else if (Build.VERSION.SDK_INT >= 21 && value is Size) {
+                    putSize(key, value)
+                } else if (Build.VERSION.SDK_INT >= 21 && value is SizeF) {
+                    putSizeF(key, value)
+                } else {
+                    val valueType = value.javaClass.canonicalName
+                    throw IllegalArgumentException("Illegal value type $valueType for key \"$key\"")
+                }
+            }
+        }
+    }
+}
diff --git a/core/ktx/src/main/java/androidx/core/os/Handler.kt b/core/ktx/src/main/java/androidx/core/os/Handler.kt
new file mode 100644
index 0000000..de09a9b
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/os/Handler.kt
@@ -0,0 +1,68 @@
+/*
+ * 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 androidx.core.os
+
+import android.os.Handler
+
+/**
+ * Version of [Handler.postDelayed] which re-orders the parameters, allowing the action to be
+ * placed outside of parentheses.
+ *
+ * ```
+ * handler.postDelayed(200) {
+ *     doSomething()
+ * }
+ * ```
+ *
+ * @return the created Runnable
+ */
+inline fun Handler.postDelayed(
+    delayInMillis: Long,
+    token: Any? = null,
+    crossinline action: () -> Unit
+): Runnable {
+    val runnable = Runnable { action() }
+    if (token == null) {
+        postDelayed(runnable, delayInMillis)
+    } else {
+        HandlerCompat.postDelayed(this, runnable, token, delayInMillis)
+    }
+    return runnable
+}
+
+/**
+ * Version of [Handler.postAtTime] which re-orders the parameters, allowing the action to be
+ * placed outside of parentheses.
+ *
+ * ```
+ * handler.postAtTime(200) {
+ *     doSomething()
+ * }
+ * ```
+ *
+ * @param token An optional object with which the posted message will be associated.
+ * @return the created Runnable
+ */
+inline fun Handler.postAtTime(
+    uptimeMillis: Long,
+    token: Any? = null,
+    crossinline action: () -> Unit
+): Runnable {
+    val runnable = Runnable { action() }
+    postAtTime(runnable, token, uptimeMillis)
+    return runnable
+}
diff --git a/core/ktx/src/main/java/androidx/core/os/PersistableBundle.kt b/core/ktx/src/main/java/androidx/core/os/PersistableBundle.kt
new file mode 100644
index 0000000..261e72b
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/os/PersistableBundle.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.os
+
+import android.os.Build
+import android.os.PersistableBundle
+import androidx.annotation.RequiresApi
+
+/**
+ * Returns a new [PersistableBundle] with the given key/value pairs as elements.
+ *
+ * @throws IllegalArgumentException When a value is not a supported type of [PersistableBundle].
+ */
+@RequiresApi(21)
+fun persistableBundleOf(vararg pairs: Pair<String, Any?>) = PersistableBundle(pairs.size).apply {
+    for ((key, value) in pairs) {
+        when (value) {
+            null -> putString(key, null) // Any nullable type will suffice.
+
+            // Scalars
+            is Boolean -> {
+                if (Build.VERSION.SDK_INT >= 22) {
+                    putBoolean(key, value)
+                } else {
+                    throw IllegalArgumentException("Illegal value type boolean for key \"$key\"")
+                }
+            }
+            is Double -> putDouble(key, value)
+            is Int -> putInt(key, value)
+            is Long -> putLong(key, value)
+
+            // References
+            is String -> putString(key, value)
+
+            // Scalar arrays
+            is BooleanArray -> {
+                if (Build.VERSION.SDK_INT >= 22) {
+                    putBooleanArray(key, value)
+                } else {
+                    throw IllegalArgumentException("Illegal value type boolean[] for key \"$key\"")
+                }
+            }
+            is DoubleArray -> putDoubleArray(key, value)
+            is IntArray -> putIntArray(key, value)
+            is LongArray -> putLongArray(key, value)
+
+            // Reference arrays
+            is Array<*> -> {
+                val componentType = value::class.java.componentType
+                @Suppress("UNCHECKED_CAST") // Checked by reflection.
+                when {
+                    String::class.java.isAssignableFrom(componentType) -> {
+                        putStringArray(key, value as Array<String>)
+                    }
+                    else -> {
+                        val valueType = componentType.canonicalName
+                        throw IllegalArgumentException(
+                            "Illegal value array type $valueType for key \"$key\"")
+                    }
+                }
+            }
+
+            else -> {
+                val valueType = value.javaClass.canonicalName
+                throw IllegalArgumentException("Illegal value type $valueType for key \"$key\"")
+            }
+        }
+    }
+}
diff --git a/core/ktx/src/main/java/androidx/core/os/Trace.kt b/core/ktx/src/main/java/androidx/core/os/Trace.kt
new file mode 100644
index 0000000..43bf85e
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/os/Trace.kt
@@ -0,0 +1,32 @@
+/*
+ * 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 androidx.core.os
+
+import android.os.Trace
+
+/**
+ * Wrap the specified [block] in calls to [Trace.beginSection] (with the supplied [sectionName])
+ * and [Trace.endSection].
+ */
+inline fun <T> trace(sectionName: String, block: () -> T): T {
+    TraceCompat.beginSection(sectionName)
+    try {
+        return block()
+    } finally {
+        TraceCompat.endSection()
+    }
+}
diff --git a/core/ktx/src/main/java/androidx/core/preference/PreferenceGroup.kt b/core/ktx/src/main/java/androidx/core/preference/PreferenceGroup.kt
new file mode 100644
index 0000000..b4f267e
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/preference/PreferenceGroup.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE")
+
+package androidx.core.preference
+
+import android.preference.Preference
+import android.preference.PreferenceGroup
+
+/**
+ * Returns the preference with `key`.
+ *
+ * @throws NullPointerException if no preference is found with that key.
+ */
+inline operator fun PreferenceGroup.get(key: CharSequence): Preference = findPreference(key)
+
+/**
+ * Returns the preference at `index`.
+ *
+ * @throws IndexOutOfBoundsException if index is less than 0 or greater than or equal to the count.
+ */
+operator fun PreferenceGroup.get(index: Int): Preference = getPreference(index)
+        ?: throw IndexOutOfBoundsException("Index: $index, Size: $preferenceCount")
+
+/** Returns `true` if `preference` is found in this preference group. */
+operator fun PreferenceGroup.contains(preference: Preference): Boolean {
+    for (index in 0 until size) {
+        if (get(index) == preference) {
+            return true
+        }
+    }
+    return false
+}
+
+/** Adds `preference` to this preference group. */
+inline operator fun PreferenceGroup.plusAssign(preference: Preference) {
+    addPreference(preference)
+}
+
+/** Removes `preference` from this preference group. */
+inline operator fun PreferenceGroup.minusAssign(preference: Preference) {
+    removePreference(preference)
+}
+
+/** Returns the number of preferences in this preference group. */
+inline val PreferenceGroup.size: Int get() = preferenceCount
+
+/** Returns true if this preference group contains no preferences. */
+inline fun PreferenceGroup.isEmpty(): Boolean = size == 0
+
+/** Returns true if this preference group contains one or more preferences. */
+inline fun PreferenceGroup.isNotEmpty(): Boolean = size != 0
+
+/** Performs the given action on each preference in this preference group. */
+inline fun PreferenceGroup.forEach(action: (preference: Preference) -> Unit) {
+    for (index in 0 until size) {
+        action(get(index))
+    }
+}
+
+/** Performs the given action on each preference in this preference group, providing its sequential index. */
+inline fun PreferenceGroup.forEachIndexed(action: (index: Int, preference: Preference) -> Unit) {
+    for (index in 0 until size) {
+        action(index, get(index))
+    }
+}
+
+/** Returns a [MutableIterator] over the preferences in this preference group. */
+operator fun PreferenceGroup.iterator() = object : MutableIterator<Preference> {
+    private var index = 0
+    override fun hasNext() = index < size
+    override fun next() = getPreference(index++) ?: throw IndexOutOfBoundsException()
+    override fun remove() {
+        removePreference(getPreference(--index))
+    }
+}
diff --git a/core/ktx/src/main/java/androidx/core/text/CharSequence.kt b/core/ktx/src/main/java/androidx/core/text/CharSequence.kt
new file mode 100644
index 0000000..d41aed2
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/text/CharSequence.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.core.text
+
+import android.text.TextUtils
+
+/**
+ * Returns whether the given [CharSequence] contains only digits.
+ *
+ * @see TextUtils.isDigitsOnly
+ */
+inline fun CharSequence.isDigitsOnly() = TextUtils.isDigitsOnly(this)
+
+/**
+ * Returns the length that the specified [CharSequence] would have if spaces and ASCII control
+ * characters were trimmed from the start and end, as by [String.trim].
+ *
+ * @see TextUtils.getTrimmedLength
+ */
+inline fun CharSequence.trimmedLength() = TextUtils.getTrimmedLength(this)
diff --git a/core/ktx/src/main/java/androidx/core/text/Html.kt b/core/ktx/src/main/java/androidx/core/text/Html.kt
new file mode 100644
index 0000000..d2636ee
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/text/Html.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.text
+
+import android.annotation.SuppressLint
+import android.text.Html
+import android.text.Html.FROM_HTML_MODE_LEGACY
+import android.text.Html.ImageGetter
+import android.text.Html.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE
+import android.text.Html.TagHandler
+import android.text.Spanned
+
+/**
+ * Returns a [Spanned] from parsing this string as HTML.
+ *
+ * @param flags Additional option to set the behavior of the HTML parsing. Default is set to
+ * [Html.FROM_HTML_MODE_LEGACY] which was introduced in API 24.
+ * @param imageGetter Returns displayable styled text from the provided HTML string.
+ * @param tagHandler Notified when HTML tags are encountered a tag the parser does
+ * not know how to interpret.
+ *
+ * @see Html.fromHtml
+ */
+fun String.parseAsHtml(
+    @SuppressLint("InlinedApi") flags: Int = FROM_HTML_MODE_LEGACY,
+    imageGetter: ImageGetter? = null,
+    tagHandler: TagHandler? = null
+): Spanned = HtmlCompat.fromHtml(this, flags, imageGetter, tagHandler)
+
+/**
+ * Returns a string of HTML from the spans in this [Spanned].
+ *
+ * @see Html.toHtml
+ */
+fun Spanned.toHtml(
+    @SuppressLint("InlinedApi") option: Int = TO_HTML_PARAGRAPH_LINES_CONSECUTIVE
+): String = HtmlCompat.toHtml(this, option)
diff --git a/core/ktx/src/main/java/androidx/core/text/SpannableString.kt b/core/ktx/src/main/java/androidx/core/text/SpannableString.kt
new file mode 100644
index 0000000..29aa9c2
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/text/SpannableString.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE")
+
+package androidx.core.text
+
+import android.text.Spannable
+import android.text.SpannableString
+import android.text.Spanned.SPAN_INCLUSIVE_EXCLUSIVE
+
+/**
+ * Returns a new [Spannable] from [CharSequence],
+ * or the source itself if it is already an instance of [SpannableString].
+ */
+inline fun CharSequence.toSpannable(): Spannable = SpannableString.valueOf(this)
+
+/** Adds [span] to the entire text. */
+inline operator fun Spannable.plusAssign(span: Any) =
+    setSpan(span, 0, length, SPAN_INCLUSIVE_EXCLUSIVE)
+
+/** Removes [span] from this text. */
+inline operator fun Spannable.minusAssign(span: Any) = removeSpan(span)
+
+/** Clear all spans from this text. */
+inline fun Spannable.clearSpans() = getSpans<Any>().forEach { removeSpan(it) }
+
+/**
+ * Add [span] to the range [start]&hellip;[end] of the text.
+ *
+ * ```
+ * val s = "Hello, World!".toSpannable()
+ * s[0, 5] = UnderlineSpan()
+ * ```
+ *
+ * Note: The [end] value is exclusive.
+ *
+ * @see Spannable.setSpan
+ */
+inline operator fun Spannable.set(start: Int, end: Int, span: Any) {
+    setSpan(span, start, end, SPAN_INCLUSIVE_EXCLUSIVE)
+}
+
+/**
+ * Add [span] to the [range] of the text.
+ *
+ * ```
+ * val s = "Hello, World!".toSpannable()
+ * s[0..5] = UnderlineSpan()
+ * ```
+ *
+ * Note: The range end value is exclusive.
+ *
+ * @see Spannable.setSpan
+ */
+inline operator fun Spannable.set(range: IntRange, span: Any) {
+    // This looks weird, but endInclusive is just the exact upper value.
+    setSpan(span, range.start, range.endInclusive, SPAN_INCLUSIVE_EXCLUSIVE)
+}
diff --git a/core/ktx/src/main/java/androidx/core/text/SpannableStringBuilder.kt b/core/ktx/src/main/java/androidx/core/text/SpannableStringBuilder.kt
new file mode 100644
index 0000000..5834a34
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/text/SpannableStringBuilder.kt
@@ -0,0 +1,136 @@
+/*
+ * 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 androidx.core.text
+
+import android.graphics.Typeface.BOLD
+import android.graphics.Typeface.ITALIC
+import android.text.Spannable.SPAN_INCLUSIVE_EXCLUSIVE
+import android.text.SpannableStringBuilder
+import android.text.SpannedString
+import android.text.style.BackgroundColorSpan
+import android.text.style.ForegroundColorSpan
+import android.text.style.RelativeSizeSpan
+import android.text.style.StrikethroughSpan
+import android.text.style.StyleSpan
+import android.text.style.UnderlineSpan
+import androidx.annotation.ColorInt
+
+/**
+ * Builds new string by populating a newly created [SpannableStringBuilder] using the provided
+ * [builderAction] and then converting it to [SpannedString].
+ */
+inline fun buildSpannedString(builderAction: SpannableStringBuilder.() -> Unit): SpannedString {
+    val builder = SpannableStringBuilder()
+    builder.builderAction()
+    return SpannedString(builder)
+}
+
+/**
+ * Wrap appended text in [builderAction] in [spans].
+ *
+ * Note: the spans will only have the correct position if the [builderAction] only appends or
+ * replaces text. Inserting, deleting, or clearing the text will cause the span to be placed at
+ * an incorrect position.
+ */
+inline fun SpannableStringBuilder.inSpans(
+    vararg spans: Any,
+    builderAction: SpannableStringBuilder.() -> Unit
+): SpannableStringBuilder {
+    val start = length
+    builderAction()
+    for (span in spans) setSpan(span, start, length, SPAN_INCLUSIVE_EXCLUSIVE)
+    return this
+}
+
+/**
+ * Wrap appended text in [builderAction] in [span].
+ *
+ * Note: the span will only have the correct position if the `builderAction` only appends or
+ * replaces text. Inserting, deleting, or clearing the text will cause the span to be placed at
+ * an incorrect position.
+ */
+inline fun SpannableStringBuilder.inSpans(
+    span: Any,
+    builderAction: SpannableStringBuilder.() -> Unit
+): SpannableStringBuilder {
+    val start = length
+    builderAction()
+    setSpan(span, start, length, SPAN_INCLUSIVE_EXCLUSIVE)
+    return this
+}
+
+/**
+ * Wrap appended text in [builderAction] in a bold [StyleSpan].
+ *
+ * @see SpannableStringBuilder.inSpans
+ */
+inline fun SpannableStringBuilder.bold(builderAction: SpannableStringBuilder.() -> Unit) =
+    inSpans(StyleSpan(BOLD), builderAction = builderAction)
+
+/**
+ * Wrap appended text in [builderAction] in an italic [StyleSpan].
+ *
+ * @see SpannableStringBuilder.inSpans
+ */
+inline fun SpannableStringBuilder.italic(builderAction: SpannableStringBuilder.() -> Unit) =
+    inSpans(StyleSpan(ITALIC), builderAction = builderAction)
+
+/**
+ * Wrap appended text in [builderAction] in an [UnderlineSpan].
+ *
+ * @see SpannableStringBuilder.inSpans
+ */
+inline fun SpannableStringBuilder.underline(builderAction: SpannableStringBuilder.() -> Unit) =
+    inSpans(UnderlineSpan(), builderAction = builderAction)
+
+/**
+ * Wrap appended text in [builderAction] in a [ForegroundColorSpan].
+ *
+ * @see SpannableStringBuilder.inSpans
+ */
+inline fun SpannableStringBuilder.color(
+    @ColorInt color: Int,
+    builderAction: SpannableStringBuilder.() -> Unit
+) = inSpans(ForegroundColorSpan(color), builderAction = builderAction)
+
+/**
+ * Wrap appended text in [builderAction] in a [BackgroundColorSpan].
+ *
+ * @see SpannableStringBuilder.inSpans
+ */
+inline fun SpannableStringBuilder.backgroundColor(
+    @ColorInt color: Int,
+    builderAction: SpannableStringBuilder.() -> Unit
+) = inSpans(BackgroundColorSpan(color), builderAction = builderAction)
+
+/**
+ * Wrap appended text in [builderAction] in a [StrikethroughSpan].
+ *
+ * @see SpannableStringBuilder.inSpans
+ */
+inline fun SpannableStringBuilder.strikeThrough(builderAction: SpannableStringBuilder.() -> Unit) =
+    inSpans(StrikethroughSpan(), builderAction = builderAction)
+
+/**
+ * Wrap appended text in [builderAction] in a [RelativeSizeSpan].
+ *
+ * @see SpannableStringBuilder.inSpans
+ */
+inline fun SpannableStringBuilder.scale(
+    proportion: Float,
+    builderAction: SpannableStringBuilder.() -> Unit
+) = inSpans(RelativeSizeSpan(proportion), builderAction = builderAction)
diff --git a/core/ktx/src/main/java/androidx/core/text/SpannedString.kt b/core/ktx/src/main/java/androidx/core/text/SpannedString.kt
new file mode 100644
index 0000000..db27511
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/text/SpannedString.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE")
+
+package androidx.core.text
+
+import android.text.Spanned
+import android.text.SpannedString
+
+/**
+ * Returns a new [Spanned] from [CharSequence],
+ * or the source itself if it is already an instance of [SpannedString].
+ */
+inline fun CharSequence.toSpanned(): Spanned = SpannedString.valueOf(this)
+
+/** Get all spans that are instance of [T]. */
+inline fun <reified T : Any> Spanned.getSpans(start: Int = 0, end: Int = length): Array<out T> =
+    getSpans(start, end, T::class.java)
diff --git a/core/ktx/src/main/java/androidx/core/text/String.kt b/core/ktx/src/main/java/androidx/core/text/String.kt
new file mode 100644
index 0000000..8bffdd0
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/text/String.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.core.text
+
+import android.text.TextUtils
+
+/**
+ * Html-encode the string.
+ *
+ * @see TextUtils.htmlEncode
+ */
+inline fun String.htmlEncode(): String = TextUtils.htmlEncode(this)
diff --git a/core/ktx/src/main/java/androidx/core/transition/Transition.kt b/core/ktx/src/main/java/androidx/core/transition/Transition.kt
new file mode 100644
index 0000000..b79f2cb
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/transition/Transition.kt
@@ -0,0 +1,94 @@
+/*
+ * 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 androidx.core.transition
+
+import android.transition.Transition
+import androidx.annotation.RequiresApi
+
+/**
+ * Add an action which will be invoked when this transition has ended.
+ */
+@RequiresApi(19)
+fun Transition.doOnEnd(action: (transition: Transition) -> Unit) {
+    addListener(onEnd = action)
+}
+
+/**
+ * Add an action which will be invoked when this transition has started.
+ */
+@RequiresApi(19)
+fun Transition.doOnStart(action: (transition: Transition) -> Unit) {
+    addListener(onStart = action)
+}
+
+/**
+ * Add an action which will be invoked when this transition has been cancelled.
+ */
+@RequiresApi(19)
+fun Transition.doOnCancel(action: (transition: Transition) -> Unit) {
+    addListener(onCancel = action)
+}
+
+/**
+ * Add an action which will be invoked when this transition has resumed after a pause.
+ */
+@RequiresApi(19)
+fun Transition.doOnResume(action: (transition: Transition) -> Unit) {
+    addListener(onResume = action)
+}
+
+/**
+ * Add an action which will be invoked when this transition has been paused.
+ */
+@RequiresApi(19)
+fun Transition.doOnPause(action: (transition: Transition) -> Unit) {
+    addListener(onPause = action)
+}
+
+/**
+ * Add a listener to this Transition using the provided actions.
+ */
+@RequiresApi(19)
+fun Transition.addListener(
+    onEnd: ((transition: Transition) -> Unit)? = null,
+    onStart: ((transition: Transition) -> Unit)? = null,
+    onCancel: ((transition: Transition) -> Unit)? = null,
+    onResume: ((transition: Transition) -> Unit)? = null,
+    onPause: ((transition: Transition) -> Unit)? = null
+) {
+    addListener(object : Transition.TransitionListener {
+        override fun onTransitionEnd(transition: Transition) {
+            onEnd?.invoke(transition)
+        }
+
+        override fun onTransitionResume(transition: Transition) {
+            onResume?.invoke(transition)
+        }
+
+        override fun onTransitionPause(transition: Transition) {
+            onPause?.invoke(transition)
+        }
+
+        override fun onTransitionCancel(transition: Transition) {
+            onCancel?.invoke(transition)
+        }
+
+        override fun onTransitionStart(transition: Transition) {
+            onStart?.invoke(transition)
+        }
+    })
+}
diff --git a/core/ktx/src/main/java/androidx/core/util/ArrayMap.kt b/core/ktx/src/main/java/androidx/core/util/ArrayMap.kt
new file mode 100644
index 0000000..b676403
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/util/ArrayMap.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.core.util
+
+import android.util.ArrayMap
+import androidx.annotation.RequiresApi
+import kotlin.Pair
+
+/** Returns an empty new [ArrayMap]. */
+@RequiresApi(19)
+inline fun <K, V> arrayMapOf(): ArrayMap<K, V> = ArrayMap()
+
+/**
+ * Returns a new [ArrayMap] with the specified contents, given as a list of pairs where the first
+ * component is the key and the second component is the value.
+ *
+ * If multiple pairs have the same key, the resulting map will contain the value from the last of
+ * those pairs.
+ */
+@RequiresApi(19)
+fun <K, V> arrayMapOf(vararg pairs: Pair<K, V>): ArrayMap<K, V> {
+    val map = ArrayMap<K, V>(pairs.size)
+    for (pair in pairs) {
+        map[pair.first] = pair.second
+    }
+    return map
+}
diff --git a/core/ktx/src/main/java/androidx/core/util/ArraySet.kt b/core/ktx/src/main/java/androidx/core/util/ArraySet.kt
new file mode 100644
index 0000000..6773d23
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/util/ArraySet.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.core.util
+
+import android.util.ArraySet
+import androidx.annotation.RequiresApi
+
+/** Returns an empty new [ArraySet]. */
+@RequiresApi(23)
+inline fun <T> arraySetOf(): ArraySet<T> = ArraySet()
+
+/** Returns a new [ArraySet] with the specified contents. */
+@RequiresApi(23)
+fun <T> arraySetOf(vararg values: T): ArraySet<T> {
+    val set = ArraySet<T>(values.size)
+    @Suppress("LoopToCallChain") // Causes needless copy to a list.
+    for (value in values) {
+        set.add(value)
+    }
+    return set
+}
diff --git a/core/ktx/src/main/java/androidx/core/util/AtomicFile.kt b/core/ktx/src/main/java/androidx/core/util/AtomicFile.kt
new file mode 100644
index 0000000..b8fbba7
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/util/AtomicFile.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to other public API.
+
+package androidx.core.util
+
+import android.util.AtomicFile
+import androidx.annotation.RequiresApi
+import java.io.FileOutputStream
+import java.nio.charset.Charset
+
+/**
+ * Perform the write operations inside [block] on this file. If [block] throws an exception the
+ * write will be failed. Otherwise the write will be applied atomically to the file.
+ */
+@RequiresApi(17)
+inline fun AtomicFile.tryWrite(block: (out: FileOutputStream) -> Unit) {
+    val stream = startWrite()
+    var success = false
+    try {
+        block(stream)
+        success = true
+    } finally {
+        if (success) {
+            finishWrite(stream)
+        } else {
+            failWrite(stream)
+        }
+    }
+}
+
+/**
+ * Sets the content of this file as an [array] of bytes.
+ */
+@RequiresApi(17)
+fun AtomicFile.writeBytes(array: ByteArray) {
+    tryWrite {
+        it.write(array)
+    }
+}
+
+/**
+ * Sets the content of this file as [text] encoded using UTF-8 or specified [charset].
+ * If this file exists, it becomes overwritten.
+ */
+@RequiresApi(17)
+fun AtomicFile.writeText(text: String, charset: Charset = Charsets.UTF_8) {
+    writeBytes(text.toByteArray(charset))
+}
+
+/**
+ * Gets the entire content of this file as a byte array.
+ *
+ * This method is not recommended on huge files. It has an internal limitation of 2 GB file size.
+ */
+@RequiresApi(17)
+inline fun AtomicFile.readBytes(): ByteArray = readFully()
+
+/**
+ * Gets the entire content of this file as a String using UTF-8 or specified [charset].
+ *
+ * This method is not recommended on huge files. It has an internal limitation of 2 GB file size.
+ */
+@RequiresApi(17)
+fun AtomicFile.readText(charset: Charset = Charsets.UTF_8): String {
+    return readFully().toString(charset)
+}
diff --git a/core/ktx/src/main/java/androidx/core/util/Half.kt b/core/ktx/src/main/java/androidx/core/util/Half.kt
new file mode 100644
index 0000000..409c01e
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/util/Half.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to other public API.
+
+package androidx.core.util
+
+import android.util.Half
+import androidx.annotation.HalfFloat
+import androidx.annotation.RequiresApi
+
+/**
+ * Returns a [Half] instance representing given [Short].
+ *
+ * @see Half.valueOf
+ */
+// TODO https://youtrack.jetbrains.com/issue/KT-21696
+@Suppress("WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE")
+@RequiresApi(26)
+inline fun @receiver:HalfFloat Short.toHalf(): Half = Half.valueOf(this)
+
+/**
+ * Returns a [Half] instance representing given [Float].
+ *
+ * @see Half.valueOf
+ */
+@RequiresApi(26)
+inline fun Float.toHalf(): Half = Half.valueOf(this)
+
+/**
+ * Returns a [Half] instance representing given [Double].
+ *
+ * @see Half.valueOf
+ */
+@RequiresApi(26)
+inline fun Double.toHalf(): Half = toFloat().toHalf()
+
+/**
+ * Returns a [Half] instance representing given [String].
+ *
+ * @see Half.valueOf
+ */
+@RequiresApi(26)
+inline fun String.toHalf(): Half = Half.valueOf(this)
diff --git a/core/ktx/src/main/java/androidx/core/util/Locale.kt b/core/ktx/src/main/java/androidx/core/util/Locale.kt
new file mode 100644
index 0000000..2b4312e
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/util/Locale.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.util
+
+import android.text.TextUtils
+import androidx.annotation.RequiresApi
+import java.util.Locale
+
+/**
+ * Returns layout direction for a given locale.
+ * @see TextUtils.getLayoutDirectionFromLocale
+ */
+val Locale.layoutDirection: Int
+        @RequiresApi(17)
+        get() = TextUtils.getLayoutDirectionFromLocale(this)
diff --git a/core/ktx/src/main/java/androidx/core/util/LongSparseArray.kt b/core/ktx/src/main/java/androidx/core/util/LongSparseArray.kt
new file mode 100644
index 0000000..cd9eb4c
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/util/LongSparseArray.kt
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.core.util
+
+import android.util.LongSparseArray
+import androidx.annotation.RequiresApi
+
+/** Returns the number of key/value pairs in the collection. */
+@get:RequiresApi(16)
+inline val <T> LongSparseArray<T>.size get() = size()
+
+/** Returns true if the collection contains [key]. */
+@RequiresApi(16)
+inline operator fun <T> LongSparseArray<T>.contains(key: Long) = indexOfKey(key) >= 0
+
+/** Allows the use of the index operator for storing values in the collection. */
+@RequiresApi(16)
+inline operator fun <T> LongSparseArray<T>.set(key: Long, value: T) = put(key, value)
+
+/** Creates a new collection by adding or replacing entries from [other]. */
+@RequiresApi(16)
+operator fun <T> LongSparseArray<T>.plus(other: LongSparseArray<T>): LongSparseArray<T> {
+    val new = LongSparseArray<T>(size() + other.size())
+    new.putAll(this)
+    new.putAll(other)
+    return new
+}
+
+/** Returns true if the collection contains [key]. */
+@RequiresApi(16)
+inline fun <T> LongSparseArray<T>.containsKey(key: Long) = indexOfKey(key) >= 0
+
+/** Returns true if the collection contains [value]. */
+@RequiresApi(16)
+inline fun <T> LongSparseArray<T>.containsValue(value: T) = indexOfValue(value) != -1
+
+/** Return the value corresponding to [key], or [defaultValue] when not present. */
+@RequiresApi(16)
+inline fun <T> LongSparseArray<T>.getOrDefault(key: Long, defaultValue: T) =
+    get(key) ?: defaultValue
+
+/** Return the value corresponding to [key], or from [defaultValue] when not present. */
+@RequiresApi(16)
+inline fun <T> LongSparseArray<T>.getOrElse(key: Long, defaultValue: () -> T) =
+    get(key) ?: defaultValue()
+
+/** Return true when the collection contains no elements. */
+@RequiresApi(16)
+inline fun <T> LongSparseArray<T>.isEmpty() = size() == 0
+
+/** Return true when the collection contains elements. */
+@RequiresApi(16)
+inline fun <T> LongSparseArray<T>.isNotEmpty() = size() != 0
+
+/** Removes the entry for [key] only if it is mapped to [value]. */
+@RequiresApi(16)
+fun <T> LongSparseArray<T>.remove(key: Long, value: T): Boolean {
+    val index = indexOfKey(key)
+    if (index != -1 && value == valueAt(index)) {
+        removeAt(index)
+        return true
+    }
+    return false
+}
+
+/** Update this collection by adding or replacing entries from [other]. */
+@RequiresApi(16)
+fun <T> LongSparseArray<T>.putAll(other: LongSparseArray<T>) = other.forEach(::put)
+
+/** Performs the given [action] for each key/value entry. */
+@RequiresApi(16)
+inline fun <T> LongSparseArray<T>.forEach(action: (key: Long, value: T) -> Unit) {
+    for (index in 0 until size()) {
+        action(keyAt(index), valueAt(index))
+    }
+}
+
+/** Return an iterator over the collection's keys. */
+@RequiresApi(16)
+fun <T> LongSparseArray<T>.keyIterator(): LongIterator = object : LongIterator() {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun nextLong() = keyAt(index++)
+}
+
+/** Return an iterator over the collection's values. */
+@RequiresApi(16)
+fun <T> LongSparseArray<T>.valueIterator(): Iterator<T> = object : Iterator<T> {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun next() = valueAt(index++)
+}
diff --git a/core/ktx/src/main/java/androidx/core/util/LruCache.kt b/core/ktx/src/main/java/androidx/core/util/LruCache.kt
new file mode 100644
index 0000000..44c2f8d
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/util/LruCache.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 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 androidx.core.util
+
+import android.util.LruCache
+
+/**
+ * Creates an [LruCache] with the given parameters.
+ *
+ * @param maxSize for caches that do not specify [sizeOf], this is
+ * the maximum number of entries in the cache. For all other caches,
+ * this is the maximum sum of the sizes of the entries in this cache.
+ * @param sizeOf function that returns the size of the entry for key and value in
+ * user-defined units. The default implementation returns 1.
+ * @param create a create called after a cache miss to compute a value for the corresponding key.
+ * Returns the computed value or null if no value can be computed. The default implementation
+ * returns null.
+ * @param onEntryRemoved a function called for entries that have been evicted or removed.
+ *
+ * @see LruCache.sizeOf
+ * @see LruCache.create
+ * @see LruCache.entryRemoved
+ */
+inline fun <K : Any, V : Any> lruCache(
+    maxSize: Int,
+    crossinline sizeOf: (key: K, value: V) -> Int = { _, _ -> 1 },
+    @Suppress("USELESS_CAST") // https://youtrack.jetbrains.com/issue/KT-21946
+    crossinline create: (key: K) -> V? = { null as V? },
+    crossinline onEntryRemoved: (evicted: Boolean, key: K, oldValue: V, newValue: V?) -> Unit =
+        { _, _, _, _ -> }
+): LruCache<K, V> {
+    return object : LruCache<K, V>(maxSize) {
+        override fun sizeOf(key: K, value: V) = sizeOf(key, value)
+        override fun create(key: K) = create(key)
+        override fun entryRemoved(evicted: Boolean, key: K, oldValue: V, newValue: V?) {
+            onEntryRemoved(evicted, key, oldValue, newValue)
+        }
+    }
+}
diff --git a/core/ktx/src/main/java/androidx/core/util/Pair.kt b/core/ktx/src/main/java/androidx/core/util/Pair.kt
new file mode 100644
index 0000000..cf12156
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/util/Pair.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.core.util
+
+import android.util.Pair
+
+/**
+ * Returns the first component of the pair.
+ *
+ * This method allows to use destructuring declarations when working with pairs, for example:
+ * ```
+ * val (first, second) = myPair
+ * ```
+ */
+@Suppress("HasPlatformType") // Intentionally propagating platform type with unknown nullability.
+inline operator fun <F, S> Pair<F, S>.component1() = first
+
+/**
+ * Returns the second component of the pair.
+ *
+ * This method allows to use destructuring declarations when working with pairs, for example:
+ * ```
+ * val (first, second) = myPair
+ * ```
+ */
+@Suppress("HasPlatformType") // Intentionally propagating platform type with unknown nullability.
+inline operator fun <F, S> Pair<F, S>.component2() = second
+
+/** Returns this [Pair] as a [kotlin.Pair]. */
+inline fun <F, S> Pair<F, S>.toKotlinPair() = kotlin.Pair(first, second)
+
+/** Returns this [kotlin.Pair] as an Android [Pair]. */
+// Note: the return type is explicitly specified here to prevent always seeing platform types.
+inline fun <F, S> kotlin.Pair<F, S>.toAndroidPair(): Pair<F, S> = Pair(first, second)
diff --git a/core/ktx/src/main/java/androidx/core/util/Range.kt b/core/ktx/src/main/java/androidx/core/util/Range.kt
new file mode 100644
index 0000000..b5f7eb6
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/util/Range.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.core.util
+
+import android.util.Range
+import androidx.annotation.RequiresApi
+
+/**
+ * Creates a range from this [Comparable] value to [that].
+ *
+ * @throws IllegalArgumentException if this value is comparatively smaller than [that].
+ */
+@RequiresApi(21)
+inline infix fun <T : Comparable<T>> T.rangeTo(that: T): Range<T> = Range(this, that)
+
+/** Return the smallest range that includes this and [value]. */
+@RequiresApi(21)
+inline operator fun <T : Comparable<T>> Range<T>.plus(value: T): Range<T> = extend(value)
+
+/** Return the smallest range that includes this and [other]. */
+@RequiresApi(21)
+inline operator fun <T : Comparable<T>> Range<T>.plus(other: Range<T>): Range<T> = extend(other)
+
+/**
+ * Return the intersection of this range and [other].
+ *
+ * @throws IllegalArgumentException if this is disjoint from [other].
+ */
+@RequiresApi(21)
+inline infix fun <T : Comparable<T>> Range<T>.and(other: Range<T>): Range<T> = intersect(other)
+
+/** Returns this [Range] as a [ClosedRange]. */
+@RequiresApi(21)
+fun <T : Comparable<T>> Range<T>.toClosedRange(): ClosedRange<T> = object : ClosedRange<T> {
+    override val endInclusive get() = upper
+    override val start get() = lower
+}
+
+/** Returns this [ClosedRange] as a [Range]. */
+@RequiresApi(21)
+fun <T : Comparable<T>> ClosedRange<T>.toRange(): Range<T> = Range(start, endInclusive)
diff --git a/core/ktx/src/main/java/androidx/core/util/Size.kt b/core/ktx/src/main/java/androidx/core/util/Size.kt
new file mode 100644
index 0000000..1cb7858
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/util/Size.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 20188 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE")
+
+package androidx.core.util
+
+import android.util.Size
+import android.util.SizeF
+import androidx.annotation.RequiresApi
+
+/**
+ * Returns "width", the first component of this [Size].
+ *
+ * This method allows to use destructuring declarations when working with
+ * sizes, for example:
+ * ```
+ * val (w, h) = mySize
+ * ```
+ */
+@RequiresApi(21)
+inline operator fun Size.component1() = width
+
+/**
+ * Returns "height", the second component of this [Size].
+ *
+ * This method allows to use destructuring declarations when working with
+ * sizes, for example:
+ * ```
+ * val (w, h) = mySize
+ * ```
+ */
+@RequiresApi(21)
+inline operator fun Size.component2() = height
+
+/**
+ * Returns "width", the first component of this [SizeF].
+ *
+ * This method allows to use destructuring declarations when working with
+ * sizes, for example:
+ * ```
+ * val (w, h) = mySize
+ * ```
+ */
+@RequiresApi(21)
+inline operator fun SizeF.component1() = width
+
+/**
+ * Returns "height", the second component of this [SizeF].
+ *
+ * This method allows to use destructuring declarations when working with
+ * sizes, for example:
+ * ```
+ * val (w, h) = mySize
+ * ```
+ */
+@RequiresApi(21)
+inline operator fun SizeF.component2() = height
diff --git a/core/ktx/src/main/java/androidx/core/util/SparseArray.kt b/core/ktx/src/main/java/androidx/core/util/SparseArray.kt
new file mode 100644
index 0000000..2b34a46
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/util/SparseArray.kt
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.core.util
+
+import android.util.SparseArray
+
+/** Returns the number of key/value pairs in the collection. */
+inline val <T> SparseArray<T>.size get() = size()
+
+/** Returns true if the collection contains [key]. */
+inline operator fun <T> SparseArray<T>.contains(key: Int) = indexOfKey(key) >= 0
+
+/** Allows the use of the index operator for storing values in the collection. */
+inline operator fun <T> SparseArray<T>.set(key: Int, value: T) = put(key, value)
+
+/** Creates a new collection by adding or replacing entries from [other]. */
+operator fun <T> SparseArray<T>.plus(other: SparseArray<T>): SparseArray<T> {
+    val new = SparseArray<T>(size() + other.size())
+    new.putAll(this)
+    new.putAll(other)
+    return new
+}
+
+/** Returns true if the collection contains [key]. */
+inline fun <T> SparseArray<T>.containsKey(key: Int) = indexOfKey(key) >= 0
+
+/** Returns true if the collection contains [value]. */
+inline fun <T> SparseArray<T>.containsValue(value: T) = indexOfValue(value) != -1
+
+/** Return the value corresponding to [key], or [defaultValue] when not present. */
+inline fun <T> SparseArray<T>.getOrDefault(key: Int, defaultValue: T) = get(key) ?: defaultValue
+
+/** Return the value corresponding to [key], or from [defaultValue] when not present. */
+inline fun <T> SparseArray<T>.getOrElse(key: Int, defaultValue: () -> T) =
+    get(key) ?: defaultValue()
+
+/** Return true when the collection contains no elements. */
+inline fun <T> SparseArray<T>.isEmpty() = size() == 0
+
+/** Return true when the collection contains elements. */
+inline fun <T> SparseArray<T>.isNotEmpty() = size() != 0
+
+/** Removes the entry for [key] only if it is mapped to [value]. */
+fun <T> SparseArray<T>.remove(key: Int, value: T): Boolean {
+    val index = indexOfKey(key)
+    if (index != -1 && value == valueAt(index)) {
+        removeAt(index)
+        return true
+    }
+    return false
+}
+
+/** Update this collection by adding or replacing entries from [other]. */
+fun <T> SparseArray<T>.putAll(other: SparseArray<T>) = other.forEach(::put)
+
+/** Performs the given [action] for each key/value entry. */
+inline fun <T> SparseArray<T>.forEach(action: (key: Int, value: T) -> Unit) {
+    for (index in 0 until size()) {
+        action(keyAt(index), valueAt(index))
+    }
+}
+
+/** Return an iterator over the collection's keys. */
+fun <T> SparseArray<T>.keyIterator(): IntIterator = object : IntIterator() {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun nextInt() = keyAt(index++)
+}
+
+/** Return an iterator over the collection's values. */
+fun <T> SparseArray<T>.valueIterator(): Iterator<T> = object : Iterator<T> {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun next() = valueAt(index++)
+}
diff --git a/core/ktx/src/main/java/androidx/core/util/SparseBooleanArray.kt b/core/ktx/src/main/java/androidx/core/util/SparseBooleanArray.kt
new file mode 100644
index 0000000..b349326
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/util/SparseBooleanArray.kt
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.core.util
+
+import android.util.SparseBooleanArray
+
+/** Returns the number of key/value pairs in the collection. */
+inline val SparseBooleanArray.size get() = size()
+
+/** Returns true if the collection contains [key]. */
+inline operator fun SparseBooleanArray.contains(key: Int) = indexOfKey(key) >= 0
+
+/** Allows the use of the index operator for storing values in the collection. */
+inline operator fun SparseBooleanArray.set(key: Int, value: Boolean) = put(key, value)
+
+/** Creates a new collection by adding or replacing entries from [other]. */
+operator fun SparseBooleanArray.plus(other: SparseBooleanArray): SparseBooleanArray {
+    val new = SparseBooleanArray(size() + other.size())
+    new.putAll(this)
+    new.putAll(other)
+    return new
+}
+
+/** Returns true if the collection contains [key]. */
+inline fun SparseBooleanArray.containsKey(key: Int) = indexOfKey(key) >= 0
+
+/** Returns true if the collection contains [value]. */
+inline fun SparseBooleanArray.containsValue(value: Boolean) = indexOfValue(value) != -1
+
+/** Return the value corresponding to [key], or [defaultValue] when not present. */
+inline fun SparseBooleanArray.getOrDefault(key: Int, defaultValue: Boolean) = get(key, defaultValue)
+
+/** Return the value corresponding to [key], or from [defaultValue] when not present. */
+inline fun SparseBooleanArray.getOrElse(key: Int, defaultValue: () -> Boolean) =
+    indexOfKey(key).let { if (it != -1) valueAt(it) else defaultValue() }
+
+/** Return true when the collection contains no elements. */
+inline fun SparseBooleanArray.isEmpty() = size() == 0
+
+/** Return true when the collection contains elements. */
+inline fun SparseBooleanArray.isNotEmpty() = size() != 0
+
+/** Removes the entry for [key] only if it is mapped to [value]. */
+fun SparseBooleanArray.remove(key: Int, value: Boolean): Boolean {
+    val index = indexOfKey(key)
+    if (index != -1 && value == valueAt(index)) {
+        // Delete by key because of https://issuetracker.google.com/issues/70934959.
+        delete(key)
+        return true
+    }
+    return false
+}
+
+/** Update this collection by adding or replacing entries from [other]. */
+fun SparseBooleanArray.putAll(other: SparseBooleanArray) = other.forEach(::put)
+
+/** Performs the given [action] for each key/value entry. */
+inline fun SparseBooleanArray.forEach(action: (key: Int, value: Boolean) -> Unit) {
+    for (index in 0 until size()) {
+        action(keyAt(index), valueAt(index))
+    }
+}
+
+/** Return an iterator over the collection's keys. */
+fun SparseBooleanArray.keyIterator(): IntIterator = object : IntIterator() {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun nextInt() = keyAt(index++)
+}
+
+/** Return an iterator over the collection's values. */
+fun SparseBooleanArray.valueIterator(): BooleanIterator = object : BooleanIterator() {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun nextBoolean() = valueAt(index++)
+}
diff --git a/core/ktx/src/main/java/androidx/core/util/SparseIntArray.kt b/core/ktx/src/main/java/androidx/core/util/SparseIntArray.kt
new file mode 100644
index 0000000..bba57c6
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/util/SparseIntArray.kt
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.core.util
+
+import android.util.SparseIntArray
+
+/** Returns the number of key/value pairs in the collection. */
+inline val SparseIntArray.size get() = size()
+
+/** Returns true if the collection contains [key]. */
+inline operator fun SparseIntArray.contains(key: Int) = indexOfKey(key) >= 0
+
+/** Allows the use of the index operator for storing values in the collection. */
+inline operator fun SparseIntArray.set(key: Int, value: Int) = put(key, value)
+
+/** Creates a new collection by adding or replacing entries from [other]. */
+operator fun SparseIntArray.plus(other: SparseIntArray): SparseIntArray {
+    val new = SparseIntArray(size() + other.size())
+    new.putAll(this)
+    new.putAll(other)
+    return new
+}
+
+/** Returns true if the collection contains [key]. */
+inline fun SparseIntArray.containsKey(key: Int) = indexOfKey(key) >= 0
+
+/** Returns true if the collection contains [value]. */
+inline fun SparseIntArray.containsValue(value: Int) = indexOfValue(value) != -1
+
+/** Return the value corresponding to [key], or [defaultValue] when not present. */
+inline fun SparseIntArray.getOrDefault(key: Int, defaultValue: Int) = get(key, defaultValue)
+
+/** Return the value corresponding to [key], or from [defaultValue] when not present. */
+inline fun SparseIntArray.getOrElse(key: Int, defaultValue: () -> Int) =
+    indexOfKey(key).let { if (it != -1) valueAt(it) else defaultValue() }
+
+/** Return true when the collection contains no elements. */
+inline fun SparseIntArray.isEmpty() = size() == 0
+
+/** Return true when the collection contains elements. */
+inline fun SparseIntArray.isNotEmpty() = size() != 0
+
+/** Removes the entry for [key] only if it is mapped to [value]. */
+fun SparseIntArray.remove(key: Int, value: Int): Boolean {
+    val index = indexOfKey(key)
+    if (index != -1 && value == valueAt(index)) {
+        removeAt(index)
+        return true
+    }
+    return false
+}
+
+/** Update this collection by adding or replacing entries from [other]. */
+fun SparseIntArray.putAll(other: SparseIntArray) = other.forEach(::put)
+
+/** Performs the given [action] for each key/value entry. */
+inline fun SparseIntArray.forEach(action: (key: Int, value: Int) -> Unit) {
+    for (index in 0 until size()) {
+        action(keyAt(index), valueAt(index))
+    }
+}
+
+/** Return an iterator over the collection's keys. */
+fun SparseIntArray.keyIterator(): IntIterator = object : IntIterator() {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun nextInt() = keyAt(index++)
+}
+
+/** Return an iterator over the collection's values. */
+fun SparseIntArray.valueIterator(): IntIterator = object : IntIterator() {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun nextInt() = valueAt(index++)
+}
diff --git a/core/ktx/src/main/java/androidx/core/util/SparseLongArray.kt b/core/ktx/src/main/java/androidx/core/util/SparseLongArray.kt
new file mode 100644
index 0000000..68b4763
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/util/SparseLongArray.kt
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.core.util
+
+import android.util.SparseLongArray
+import androidx.annotation.RequiresApi
+
+/** Returns the number of key/value entries in the collection. */
+@get:RequiresApi(18)
+inline val SparseLongArray.size get() = size()
+
+/** Returns true if the collection contains [key]. */
+@RequiresApi(18)
+inline operator fun SparseLongArray.contains(key: Int) = indexOfKey(key) >= 0
+
+/** Allows the use of the index operator for storing values in the collection. */
+@RequiresApi(18)
+inline operator fun SparseLongArray.set(key: Int, value: Long) = put(key, value)
+
+/** Creates a new collection by adding or replacing entries from [other]. */
+@RequiresApi(18)
+operator fun SparseLongArray.plus(other: SparseLongArray): SparseLongArray {
+    val new = SparseLongArray(size() + other.size())
+    new.putAll(this)
+    new.putAll(other)
+    return new
+}
+
+/** Returns true if the collection contains [key]. */
+@RequiresApi(18)
+inline fun SparseLongArray.containsKey(key: Int) = indexOfKey(key) >= 0
+
+/** Returns true if the collection contains [value]. */
+@RequiresApi(18)
+inline fun SparseLongArray.containsValue(value: Long) = indexOfValue(value) != -1
+
+/** Return the value corresponding to [key], or [defaultValue] when not present. */
+@RequiresApi(18)
+inline fun SparseLongArray.getOrDefault(key: Int, defaultValue: Long) = get(key, defaultValue)
+
+/** Return the value corresponding to [key], or from [defaultValue] when not present. */
+@RequiresApi(18)
+inline fun SparseLongArray.getOrElse(key: Int, defaultValue: () -> Long) =
+    indexOfKey(key).let { if (it != -1) valueAt(it) else defaultValue() }
+
+/** Return true when the collection contains no elements. */
+@RequiresApi(18)
+inline fun SparseLongArray.isEmpty() = size() == 0
+
+/** Return true when the collection contains elements. */
+@RequiresApi(18)
+inline fun SparseLongArray.isNotEmpty() = size() != 0
+
+/** Removes the entry for [key] only if it is set to [value]. */
+@RequiresApi(18)
+fun SparseLongArray.remove(key: Int, value: Long): Boolean {
+    val index = indexOfKey(key)
+    if (index != -1 && value == valueAt(index)) {
+        removeAt(index)
+        return true
+    }
+    return false
+}
+
+/** Update this collection by adding or replacing entries from [other]. */
+@RequiresApi(18)
+fun SparseLongArray.putAll(other: SparseLongArray) = other.forEach(::put)
+
+/** Performs the given [action] for each key/value entry. */
+@RequiresApi(18)
+inline fun SparseLongArray.forEach(action: (key: Int, value: Long) -> Unit) {
+    for (index in 0 until size()) {
+        action(keyAt(index), valueAt(index))
+    }
+}
+
+/** Return an iterator over the collection's keys. */
+@RequiresApi(18)
+fun SparseLongArray.keyIterator(): IntIterator = object : IntIterator() {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun nextInt() = keyAt(index++)
+}
+
+/** Return an iterator over the collection's values. */
+@RequiresApi(18)
+fun SparseLongArray.valueIterator(): LongIterator = object : LongIterator() {
+    var index = 0
+    override fun hasNext() = index < size()
+    override fun nextLong() = valueAt(index++)
+}
diff --git a/core/ktx/src/main/java/androidx/core/view/Menu.kt b/core/ktx/src/main/java/androidx/core/view/Menu.kt
new file mode 100644
index 0000000..7ab479f
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/view/Menu.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE")
+
+package androidx.core.view
+
+import android.view.Menu
+import android.view.MenuItem
+
+/**
+ * Returns the menu at [index].
+ *
+ * @throws IndexOutOfBoundsException if index is less than 0 or greater than or equal to the count.
+ */
+inline operator fun Menu.get(index: Int): MenuItem = getItem(index)
+
+/** Returns `true` if [item] is found in this menu. */
+operator fun Menu.contains(item: MenuItem): Boolean {
+    @Suppress("LoopToCallChain")
+    for (index in 0 until size) {
+        if (getItem(index) == item) {
+            return true
+        }
+    }
+    return false
+}
+
+/** Returns the number of items in this menu. */
+inline val Menu.size get() = size()
+
+/** Returns true if this menu contains no items. */
+inline fun Menu.isEmpty() = size() == 0
+
+/** Returns true if this menu contains one or more items. */
+inline fun Menu.isNotEmpty() = size() != 0
+
+/** Performs the given action on each item in this menu. */
+inline fun Menu.forEach(action: (item: MenuItem) -> Unit) {
+    for (index in 0 until size()) {
+        action(getItem(index))
+    }
+}
+
+/** Performs the given action on each item in this menu, providing its sequential index. */
+inline fun Menu.forEachIndexed(action: (index: Int, item: MenuItem) -> Unit) {
+    for (index in 0 until size()) {
+        action(index, getItem(index))
+    }
+}
+
+/** Returns a [MutableIterator] over the items in this menu. */
+operator fun Menu.iterator() = object : MutableIterator<MenuItem> {
+    private var index = 0
+    override fun hasNext() = index < size()
+    override fun next() = getItem(index++) ?: throw IndexOutOfBoundsException()
+    override fun remove() = removeItem(--index)
+}
diff --git a/core/ktx/src/main/java/androidx/core/view/View.kt b/core/ktx/src/main/java/androidx/core/view/View.kt
new file mode 100644
index 0000000..fcb0256
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/view/View.kt
@@ -0,0 +1,287 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to other public API.
+
+package androidx.core.view
+
+import android.graphics.Bitmap
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewTreeObserver
+import android.view.accessibility.AccessibilityEvent
+import androidx.annotation.Px
+import androidx.annotation.RequiresApi
+import androidx.annotation.StringRes
+import androidx.core.graphics.applyCanvas
+
+/**
+ * Performs the given action when this view is next laid out.
+ *
+ * @see doOnLayout
+ */
+inline fun View.doOnNextLayout(crossinline action: (view: View) -> Unit) {
+    addOnLayoutChangeListener(object : View.OnLayoutChangeListener {
+        override fun onLayoutChange(
+            view: View,
+            left: Int,
+            top: Int,
+            right: Int,
+            bottom: Int,
+            oldLeft: Int,
+            oldTop: Int,
+            oldRight: Int,
+            oldBottom: Int
+        ) {
+            view.removeOnLayoutChangeListener(this)
+            action(view)
+        }
+    })
+}
+
+/**
+ * Performs the given action when this view is laid out. If the view has been laid out and it
+ * has not requested a layout, the action will be performed straight away, otherwise the
+ * action will be performed after the view is next laid out.
+ *
+ * @see doOnNextLayout
+ */
+inline fun View.doOnLayout(crossinline action: (view: View) -> Unit) {
+    if (ViewCompat.isLaidOut(this) && !isLayoutRequested) {
+        action(this)
+    } else {
+        doOnNextLayout {
+            action(it)
+        }
+    }
+}
+
+/**
+ * Performs the given action when the view tree is about to be drawn.
+ */
+inline fun View.doOnPreDraw(crossinline action: (view: View) -> Unit) {
+    val vto = viewTreeObserver
+    vto.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
+        override fun onPreDraw(): Boolean {
+            action(this@doOnPreDraw)
+            when {
+                vto.isAlive -> vto.removeOnPreDrawListener(this)
+                else -> viewTreeObserver.removeOnPreDrawListener(this)
+            }
+            return true
+        }
+    })
+}
+
+/**
+ * Sends [AccessibilityEvent] of type [AccessibilityEvent.TYPE_ANNOUNCEMENT].
+ *
+ * @see View.announceForAccessibility
+ */
+@RequiresApi(16)
+inline fun View.announceForAccessibility(@StringRes resource: Int) {
+    val announcement = resources.getString(resource)
+    announceForAccessibility(announcement)
+}
+
+/**
+ * Updates this view's relative padding. This version of the method allows using named parameters
+ * to just set one or more axes.
+ *
+ * @see View.setPaddingRelative
+ */
+@RequiresApi(17)
+inline fun View.updatePaddingRelative(
+    @Px start: Int = paddingStart,
+    @Px top: Int = paddingTop,
+    @Px end: Int = paddingEnd,
+    @Px bottom: Int = paddingBottom
+) {
+    setPaddingRelative(start, top, end, bottom)
+}
+
+/**
+ * Updates this view's padding. This version of the method allows using named parameters
+ * to just set one or more axes.
+ *
+ * @see View.setPadding
+ */
+inline fun View.updatePadding(
+    @Px left: Int = paddingLeft,
+    @Px top: Int = paddingTop,
+    @Px right: Int = paddingRight,
+    @Px bottom: Int = paddingBottom
+) {
+    setPadding(left, top, right, bottom)
+}
+
+/**
+ * Sets the view's padding. This version of the method sets all axes to the provided size.
+ *
+ * @see View.setPadding
+ */
+inline fun View.setPadding(@Px size: Int) {
+    setPadding(size, size, size, size)
+}
+
+/**
+ * Version of [View.postDelayed] which re-orders the parameters, allowing the action to be placed
+ * outside of parentheses.
+ *
+ * ```
+ * view.postDelayed(200) {
+ *     doSomething()
+ * }
+ * ```
+ *
+ * @return the created Runnable
+ */
+inline fun View.postDelayed(delayInMillis: Long, crossinline action: () -> Unit): Runnable {
+    val runnable = Runnable { action() }
+    postDelayed(runnable, delayInMillis)
+    return runnable
+}
+
+/**
+ * Version of [View.postOnAnimationDelayed] which re-orders the parameters, allowing the action
+ * to be placed outside of parentheses.
+ *
+ * ```
+ * view.postOnAnimationDelayed(16) {
+ *     doSomething()
+ * }
+ * ```
+ *
+ * @return the created Runnable
+ */
+@RequiresApi(16)
+inline fun View.postOnAnimationDelayed(
+    delayInMillis: Long,
+    crossinline action: () -> Unit
+): Runnable {
+    val runnable = Runnable { action() }
+    postOnAnimationDelayed(runnable, delayInMillis)
+    return runnable
+}
+
+/**
+ * Return a [Bitmap] representation of this [View].
+ *
+ * The resulting bitmap will be the same width and height as this view's current layout
+ * dimensions. This does not take into account any transformations such as scale or translation.
+ *
+ * Note, this will use the software rendering pipeline to draw the view to the bitmap. This may
+ * result with different drawing to what is rendered on a hardware accelerated canvas (such as
+ * the device screen).
+ *
+ * If this view has not been laid out this method will throw a [IllegalStateException].
+ *
+ * @param config Bitmap config of the desired bitmap. Defaults to [Bitmap.Config.ARGB_8888].
+ */
+fun View.toBitmap(config: Bitmap.Config = Bitmap.Config.ARGB_8888): Bitmap {
+    if (!ViewCompat.isLaidOut(this)) {
+        throw IllegalStateException("View needs to be laid out before calling toBitmap()")
+    }
+    return Bitmap.createBitmap(width, height, config).applyCanvas(::draw)
+}
+
+/**
+ * Returns true when this view's visibility is [View.VISIBLE], false otherwise.
+ *
+ * ```
+ * if (view.isVisible) {
+ *     // Behavior...
+ * }
+ * ```
+ *
+ * Setting this property to true sets the visibility to [View.VISIBLE], false to [View.GONE].
+ *
+ * ```
+ * view.isVisible = true
+ * ```
+ */
+inline var View.isVisible: Boolean
+    get() = visibility == View.VISIBLE
+    set(value) {
+        visibility = if (value) View.VISIBLE else View.GONE
+    }
+
+/**
+ * Returns true when this view's visibility is [View.INVISIBLE], false otherwise.
+ *
+ * ```
+ * if (view.isInvisible) {
+ *     // Behavior...
+ * }
+ * ```
+ *
+ * Setting this property to true sets the visibility to [View.INVISIBLE], false to [View.VISIBLE].
+ *
+ * ```
+ * view.isInvisible = true
+ * ```
+ */
+inline var View.isInvisible: Boolean
+    get() = visibility == View.INVISIBLE
+    set(value) {
+        visibility = if (value) View.INVISIBLE else View.VISIBLE
+    }
+
+/**
+ * Returns true when this view's visibility is [View.GONE], false otherwise.
+ *
+ * ```
+ * if (view.isGone) {
+ *     // Behavior...
+ * }
+ * ```
+ *
+ * Setting this property to true sets the visibility to [View.GONE], false to [View.VISIBLE].
+ *
+ * ```
+ * view.isGone = true
+ * ```
+ */
+inline var View.isGone: Boolean
+    get() = visibility == View.GONE
+    set(value) {
+        visibility = if (value) View.GONE else View.VISIBLE
+    }
+
+/**
+ * Executes [block] with the View's layoutParams and reassigns the layoutParams with the
+ * updated version.
+ *
+ * @see View.getLayoutParams
+ * @see View.setLayoutParams
+ **/
+inline fun View.updateLayoutParams(block: ViewGroup.LayoutParams.() -> Unit) {
+    updateLayoutParams<ViewGroup.LayoutParams>(block)
+}
+
+/**
+ * Executes [block] with a typed version of the View's layoutParams and reassigns the
+ * layoutParams with the updated version.
+ *
+ * @see View.getLayoutParams
+ * @see View.setLayoutParams
+ **/
+@JvmName("updateLayoutParamsTyped")
+inline fun <reified T : ViewGroup.LayoutParams> View.updateLayoutParams(block: T.() -> Unit) {
+    val params = layoutParams as T
+    block(params)
+    layoutParams = params
+}
diff --git a/core/ktx/src/main/java/androidx/core/view/ViewGroup.kt b/core/ktx/src/main/java/androidx/core/view/ViewGroup.kt
new file mode 100644
index 0000000..8a7152a
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/view/ViewGroup.kt
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to other public API.
+
+package androidx.core.view
+
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.Px
+import androidx.annotation.RequiresApi
+
+/**
+ * Returns the view at [index].
+ *
+ * @throws IndexOutOfBoundsException if index is less than 0 or greater than or equal to the count.
+ */
+operator fun ViewGroup.get(index: Int) =
+    getChildAt(index) ?: throw IndexOutOfBoundsException("Index: $index, Size: $childCount")
+
+/** Returns `true` if [view] is found in this view group. */
+inline operator fun ViewGroup.contains(view: View) = indexOfChild(view) != -1
+
+/** Adds [view] to this view group. */
+inline operator fun ViewGroup.plusAssign(view: View) = addView(view)
+
+/** Removes [view] from this view group. */
+inline operator fun ViewGroup.minusAssign(view: View) = removeView(view)
+
+/** Returns the number of views in this view group. */
+inline val ViewGroup.size get() = childCount
+
+/** Returns true if this view group contains no views. */
+inline fun ViewGroup.isEmpty() = childCount == 0
+
+/** Returns true if this view group contains one or more views. */
+inline fun ViewGroup.isNotEmpty() = childCount != 0
+
+/** Performs the given action on each view in this view group. */
+inline fun ViewGroup.forEach(action: (view: View) -> Unit) {
+    for (index in 0 until childCount) {
+        action(getChildAt(index))
+    }
+}
+
+/** Performs the given action on each view in this view group, providing its sequential index. */
+inline fun ViewGroup.forEachIndexed(action: (index: Int, view: View) -> Unit) {
+    for (index in 0 until childCount) {
+        action(index, getChildAt(index))
+    }
+}
+
+/** Returns a [MutableIterator] over the views in this view group. */
+operator fun ViewGroup.iterator() = object : MutableIterator<View> {
+    private var index = 0
+    override fun hasNext() = index < childCount
+    override fun next() = getChildAt(index++) ?: throw IndexOutOfBoundsException()
+    override fun remove() = removeViewAt(--index)
+}
+
+/** Returns a [Sequence] over the child views in this view group. */
+val ViewGroup.children: Sequence<View>
+    get() = object : Sequence<View> {
+        override fun iterator() = this@children.iterator()
+    }
+
+/**
+ * Sets the margins in the ViewGroup's MarginLayoutParams. This version of the method sets all axes
+ * to the provided size.
+ *
+ * @see ViewGroup.MarginLayoutParams.setMargins
+ */
+inline fun ViewGroup.MarginLayoutParams.setMargins(@Px size: Int) {
+    setMargins(size, size, size, size)
+}
+
+/**
+ * Updates the margins in the [ViewGroup]'s [ViewGroup.MarginLayoutParams].
+ * This version of the method allows using named parameters to just set one or more axes.
+ *
+ * @see ViewGroup.MarginLayoutParams.setMargins
+ */
+inline fun ViewGroup.MarginLayoutParams.updateMargins(
+    @Px left: Int = leftMargin,
+    @Px top: Int = topMargin,
+    @Px right: Int = rightMargin,
+    @Px bottom: Int = bottomMargin
+) {
+    setMargins(left, top, right, bottom)
+}
+
+/**
+ * Updates the relative margins in the ViewGroup's MarginLayoutParams.
+ * This version of the method allows using named parameters to just set one or more axes.
+ *
+ * @see ViewGroup.MarginLayoutParams.setMargins
+ */
+@RequiresApi(17)
+inline fun ViewGroup.MarginLayoutParams.updateMarginsRelative(
+    @Px start: Int = marginStart,
+    @Px top: Int = topMargin,
+    @Px end: Int = marginEnd,
+    @Px bottom: Int = bottomMargin
+) {
+    marginStart = start
+    topMargin = top
+    marginEnd = end
+    bottomMargin = bottom
+}
diff --git a/core/ktx/src/main/java/androidx/core/widget/Toast.kt b/core/ktx/src/main/java/androidx/core/widget/Toast.kt
new file mode 100644
index 0000000..b0ddfd1
--- /dev/null
+++ b/core/ktx/src/main/java/androidx/core/widget/Toast.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE")
+
+package androidx.core.widget
+
+import android.content.Context
+import android.widget.Toast
+import androidx.annotation.StringRes
+
+/**
+ * Creates and shows a [Toast] with the given [text]
+ *
+ * @param duration Toast duration, defaults to [Toast.LENGTH_SHORT]
+ */
+inline fun Context.toast(text: CharSequence, duration: Int = Toast.LENGTH_SHORT): Toast {
+    return Toast.makeText(this, text, duration).apply { show() }
+}
+
+/**
+ * Creates and shows a [Toast] with text from a resource
+ *
+ * @param resId Resource id of the string resource to use
+ * @param duration Toast duration, defaults to [Toast.LENGTH_SHORT]
+ */
+inline fun Context.toast(@StringRes resId: Int, duration: Int = Toast.LENGTH_SHORT): Toast {
+    return Toast.makeText(this, resId, duration).apply { show() }
+}
diff --git a/emoji/core/api/current.txt b/emoji/core/api/current.txt
index 785f44a..7b343a1 100644
--- a/emoji/core/api/current.txt
+++ b/emoji/core/api/current.txt
@@ -9,6 +9,7 @@
     method public boolean hasEmojiGlyph(java.lang.CharSequence);
     method public boolean hasEmojiGlyph(java.lang.CharSequence, int);
     method public static androidx.emoji.text.EmojiCompat init(androidx.emoji.text.EmojiCompat.Config);
+    method public void load();
     method public java.lang.CharSequence process(java.lang.CharSequence);
     method public java.lang.CharSequence process(java.lang.CharSequence, int, int);
     method public java.lang.CharSequence process(java.lang.CharSequence, int, int, int);
@@ -17,9 +18,12 @@
     method public void unregisterInitCallback(androidx.emoji.text.EmojiCompat.InitCallback);
     field public static final java.lang.String EDITOR_INFO_METAVERSION_KEY = "android.support.text.emoji.emojiCompat_metadataVersion";
     field public static final java.lang.String EDITOR_INFO_REPLACE_ALL_KEY = "android.support.text.emoji.emojiCompat_replaceAll";
+    field public static final int LOAD_STATE_DEFAULT = 3; // 0x3
     field public static final int LOAD_STATE_FAILED = 2; // 0x2
     field public static final int LOAD_STATE_LOADING = 0; // 0x0
     field public static final int LOAD_STATE_SUCCEEDED = 1; // 0x1
+    field public static final int LOAD_STRATEGY_DEFAULT = 0; // 0x0
+    field public static final int LOAD_STRATEGY_MANUAL = 1; // 0x1
     field public static final int REPLACE_STRATEGY_ALL = 1; // 0x1
     field public static final int REPLACE_STRATEGY_DEFAULT = 0; // 0x0
     field public static final int REPLACE_STRATEGY_NON_EXISTENT = 2; // 0x2
@@ -31,6 +35,7 @@
     method public androidx.emoji.text.EmojiCompat.Config registerInitCallback(androidx.emoji.text.EmojiCompat.InitCallback);
     method public androidx.emoji.text.EmojiCompat.Config setEmojiSpanIndicatorColor(int);
     method public androidx.emoji.text.EmojiCompat.Config setEmojiSpanIndicatorEnabled(boolean);
+    method public androidx.emoji.text.EmojiCompat.Config setMetadataLoadStrategy(int);
     method public androidx.emoji.text.EmojiCompat.Config setReplaceAll(boolean);
     method public androidx.emoji.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean);
     method public androidx.emoji.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean, java.util.List<java.lang.Integer>);
diff --git a/emoji/core/src/androidTest/java/androidx/emoji/text/ConfigTest.java b/emoji/core/src/androidTest/java/androidx/emoji/text/ConfigTest.java
index 34f31fd..c8d3dad 100644
--- a/emoji/core/src/androidTest/java/androidx/emoji/text/ConfigTest.java
+++ b/emoji/core/src/androidTest/java/androidx/emoji/text/ConfigTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
@@ -148,9 +149,25 @@
         assertTrue(emojiCompat.isEmojiSpanIndicatorEnabled());
     }
 
+    @Test
+    public void testBuild_manualLoadStrategy_doesNotCallMetadataLoaderLoad() {
+        final EmojiCompat.MetadataRepoLoader loader = mock(EmojiCompat.MetadataRepoLoader.class);
+        final EmojiCompat.Config config = new ValidTestConfig(loader)
+                .setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL);
+
+        EmojiCompat.reset(config);
+
+        verify(loader, never()).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+        assertEquals(EmojiCompat.LOAD_STATE_DEFAULT, EmojiCompat.get().getLoadState());
+    }
+
     private static class ValidTestConfig extends EmojiCompat.Config {
         ValidTestConfig() {
             super(new TestConfigBuilder.TestEmojiDataLoader());
         }
+
+        ValidTestConfig(EmojiCompat.MetadataRepoLoader loader) {
+            super(loader);
+        }
     }
 }
diff --git a/emoji/core/src/androidTest/java/androidx/emoji/text/EmojiCompatTest.java b/emoji/core/src/androidTest/java/androidx/emoji/text/EmojiCompatTest.java
index dd8f3b9..fd9df56 100644
--- a/emoji/core/src/androidTest/java/androidx/emoji/text/EmojiCompatTest.java
+++ b/emoji/core/src/androidTest/java/androidx/emoji/text/EmojiCompatTest.java
@@ -53,6 +53,7 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -691,6 +692,97 @@
         metadataLoader.getLoaderLatch().countDown();
     }
 
+    @Test(expected = IllegalStateException.class)
+    public void testLoad_throwsException_whenLoadStrategyDefault() {
+        final EmojiCompat.MetadataRepoLoader loader = mock(EmojiCompat.MetadataRepoLoader.class);
+        final EmojiCompat.Config config = new TestConfigBuilder.TestConfig(loader);
+        EmojiCompat.reset(config);
+
+        EmojiCompat.get().load();
+    }
+
+    @Test
+    @SdkSuppress(maxSdkVersion = 18)
+    public void testLoad_pre19() {
+        final EmojiCompat.MetadataRepoLoader loader = spy(new TestConfigBuilder
+                .TestEmojiDataLoader());
+        final EmojiCompat.Config config = new TestConfigBuilder.TestConfig(loader)
+                .setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL);
+
+        EmojiCompat.reset(config);
+
+        verify(loader, never()).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+        assertEquals(EmojiCompat.LOAD_STATE_DEFAULT, EmojiCompat.get().getLoadState());
+
+        EmojiCompat.get().load();
+        assertEquals(EmojiCompat.LOAD_STATE_SUCCEEDED, EmojiCompat.get().getLoadState());
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testLoad_startsLoading() {
+        final EmojiCompat.MetadataRepoLoader loader = spy(new TestConfigBuilder
+                .TestEmojiDataLoader());
+        final EmojiCompat.Config config = new TestConfigBuilder.TestConfig(loader)
+                .setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL);
+
+        EmojiCompat.reset(config);
+
+        verify(loader, never()).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+        assertEquals(EmojiCompat.LOAD_STATE_DEFAULT, EmojiCompat.get().getLoadState());
+
+        EmojiCompat.get().load();
+        verify(loader, times(1)).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+        assertEquals(EmojiCompat.LOAD_STATE_SUCCEEDED, EmojiCompat.get().getLoadState());
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testLoad_onceSuccessDoesNotStartLoading() {
+        final EmojiCompat.MetadataRepoLoader loader = spy(new TestConfigBuilder
+                .TestEmojiDataLoader());
+        final EmojiCompat.Config config = new TestConfigBuilder.TestConfig(loader)
+                .setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL);
+
+        EmojiCompat.reset(config);
+
+        EmojiCompat.get().load();
+        verify(loader, times(1)).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+        assertEquals(EmojiCompat.LOAD_STATE_SUCCEEDED, EmojiCompat.get().getLoadState());
+
+        reset(loader);
+        EmojiCompat.get().load();
+        verify(loader, never()).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+        assertEquals(EmojiCompat.LOAD_STATE_SUCCEEDED, EmojiCompat.get().getLoadState());
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testLoad_onceLoadingDoesNotStartLoading() throws InterruptedException {
+        final TestConfigBuilder.WaitingDataLoader loader = spy(
+                new TestConfigBuilder.WaitingDataLoader(true /*success*/));
+        final EmojiCompat.Config config = new TestConfigBuilder.TestConfig(loader)
+                .setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL);
+
+        EmojiCompat.reset(config);
+
+        verify(loader, never()).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+
+        EmojiCompat.get().load();
+        verify(loader, times(1)).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+        assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_LOADING);
+
+        reset(loader);
+
+        EmojiCompat.get().load();
+        verify(loader, never()).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+
+        loader.getLoaderLatch().countDown();
+        loader.getTestLatch().await();
+
+        assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_SUCCEEDED);
+    }
+
     @Test
     @SdkSuppress(maxSdkVersion = 18)
     public void testGetAssetSignature() {
diff --git a/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiInputFilterTest.java b/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiInputFilterTest.java
index 27ea7c6..2882858 100644
--- a/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiInputFilterTest.java
+++ b/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiInputFilterTest.java
@@ -114,4 +114,16 @@
         verify(mEmojiCompat, times(0)).process(any(Spannable.class), anyInt(), anyInt());
         verify(mEmojiCompat, times(0)).registerInitCallback(any(EmojiCompat.InitCallback.class));
     }
+
+    @Test
+    public void testFilter_withManualLoadStrategy() {
+        final Spannable testString = new SpannableString("abc");
+        when(mEmojiCompat.getLoadState()).thenReturn(EmojiCompat.LOAD_STATE_DEFAULT);
+
+        final CharSequence result = mInputFilter.filter(testString, 0, 1, null, 0, 1);
+
+        assertNotNull(result);
+        verify(mEmojiCompat, times(0)).process(any(Spannable.class), anyInt(), anyInt());
+        verify(mEmojiCompat, times(1)).registerInitCallback(any(EmojiCompat.InitCallback.class));
+    }
 }
diff --git a/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiTextWatcherTest.java b/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiTextWatcherTest.java
index fade6f7..b8f0154 100644
--- a/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiTextWatcherTest.java
+++ b/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiTextWatcherTest.java
@@ -109,4 +109,15 @@
         verify(mEmojiCompat, times(1)).process(any(Spannable.class), anyInt(), anyInt(), anyInt(),
                 eq(EmojiCompat.REPLACE_STRATEGY_ALL));
     }
+
+    @Test
+    public void testFilter_withManualLoadStrategy() {
+        final Spannable testString = new SpannableString("abc");
+        when(mEmojiCompat.getLoadState()).thenReturn(EmojiCompat.LOAD_STATE_DEFAULT);
+
+        mTextWatcher.onTextChanged(testString, 0, 0, 1);
+
+        verify(mEmojiCompat, times(0)).process(any(Spannable.class), anyInt(), anyInt());
+        verify(mEmojiCompat, times(1)).registerInitCallback(any(EmojiCompat.InitCallback.class));
+    }
 }
diff --git a/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiTransformationMethodTest.java b/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiTransformationMethodTest.java
new file mode 100644
index 0000000..cf74331
--- /dev/null
+++ b/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiTransformationMethodTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2018 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 androidx.emoji.widget;
+
+import static junit.framework.TestCase.assertSame;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import static androidx.emoji.util.EmojiMatcher.sameCharSequence;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.method.TransformationMethod;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import androidx.emoji.text.EmojiCompat;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiTransformationMethodTest {
+
+    private EmojiTransformationMethod mTransformationMethod;
+    private TransformationMethod mWrappedTransformationMethod;
+    private View mView;
+    private EmojiCompat mEmojiCompat;
+    private final String mTestString = "abc";
+
+    @Before
+    public void setup() {
+        mEmojiCompat = mock(EmojiCompat.class);
+        when(mEmojiCompat.getLoadState()).thenReturn(EmojiCompat.LOAD_STATE_SUCCEEDED);
+        when(mEmojiCompat.process(any(CharSequence.class))).thenAnswer(new Answer<CharSequence>() {
+            @Override
+            public CharSequence answer(InvocationOnMock invocation) {
+                Object[] args = invocation.getArguments();
+                return new SpannableString((String) args[0]);
+            }
+        });
+        EmojiCompat.reset(mEmojiCompat);
+
+        mView = mock(View.class);
+        when(mView.isInEditMode()).thenReturn(false);
+
+        mWrappedTransformationMethod = mock(TransformationMethod.class);
+        when(mWrappedTransformationMethod.getTransformation(any(CharSequence.class),
+                any(View.class))).thenAnswer(new Answer<CharSequence>() {
+            @Override
+            public CharSequence answer(InvocationOnMock invocation) {
+                Object[] args = invocation.getArguments();
+                return (String) args[0];
+            }
+        });
+
+        mTransformationMethod = new EmojiTransformationMethod(mWrappedTransformationMethod);
+    }
+
+    @Test
+    public void testFilter_withNullSource() {
+        assertNull(mTransformationMethod.getTransformation(null, mView));
+        verify(mEmojiCompat, never()).process(any(CharSequence.class));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testFilter_withNullView() {
+        mTransformationMethod.getTransformation("", null);
+    }
+
+    @Test
+    public void testFilter_withNullTransformationMethod() {
+        mTransformationMethod = new EmojiTransformationMethod(null);
+
+        final CharSequence result = mTransformationMethod.getTransformation(mTestString, mView);
+
+        assertTrue(TextUtils.equals(new SpannableString(mTestString), result));
+        verify(mEmojiCompat, times(1)).process(sameCharSequence(mTestString));
+    }
+
+    @Test
+    public void testFilter() {
+        final CharSequence result = mTransformationMethod.getTransformation(mTestString, mView);
+
+        assertTrue(TextUtils.equals(new SpannableString(mTestString), result));
+        assertTrue(result instanceof Spannable);
+        verify(mWrappedTransformationMethod, times(1)).getTransformation(
+                sameCharSequence(mTestString), same(mView));
+        verify(mEmojiCompat, times(1)).process(sameCharSequence(mTestString));
+        verify(mEmojiCompat, never()).registerInitCallback(any(EmojiCompat.InitCallback.class));
+    }
+
+    @Test
+    public void testFilter_whenEmojiCompatLoading() {
+        when(mEmojiCompat.getLoadState()).thenReturn(EmojiCompat.LOAD_STATE_LOADING);
+
+        final CharSequence result = mTransformationMethod.getTransformation(mTestString, mView);
+
+        assertSame(mTestString, result);
+        verify(mWrappedTransformationMethod, times(1)).getTransformation(
+                sameCharSequence(mTestString), same(mView));
+        verify(mEmojiCompat, never()).process(sameCharSequence(mTestString));
+        verify(mEmojiCompat, never()).registerInitCallback(any(EmojiCompat.InitCallback.class));
+    }
+
+    @Test
+    public void testFilter_whenEmojiCompatLoadFailed() {
+        when(mEmojiCompat.getLoadState()).thenReturn(EmojiCompat.LOAD_STATE_FAILED);
+
+        final CharSequence result = mTransformationMethod.getTransformation(mTestString, mView);
+
+        assertSame(mTestString, result);
+        verify(mWrappedTransformationMethod, times(1)).getTransformation(
+                sameCharSequence(mTestString), same(mView));
+        verify(mEmojiCompat, never()).process(sameCharSequence(mTestString));
+        verify(mEmojiCompat, never()).registerInitCallback(any(EmojiCompat.InitCallback.class));
+    }
+
+    @Test
+    public void testFilter_withManualLoadStrategy() {
+        when(mEmojiCompat.getLoadState()).thenReturn(EmojiCompat.LOAD_STATE_DEFAULT);
+
+        final CharSequence result = mTransformationMethod.getTransformation(mTestString, mView);
+
+        assertSame(mTestString, result);
+        verify(mWrappedTransformationMethod, times(1)).getTransformation(
+                sameCharSequence(mTestString), same(mView));
+        verify(mEmojiCompat, never()).process(sameCharSequence(mTestString));
+        verify(mEmojiCompat, never()).registerInitCallback(any(EmojiCompat.InitCallback.class));
+    }
+}
diff --git a/emoji/core/src/main/java/androidx/emoji/text/EmojiCompat.java b/emoji/core/src/main/java/androidx/emoji/text/EmojiCompat.java
index 31d359d..572606f 100644
--- a/emoji/core/src/main/java/androidx/emoji/text/EmojiCompat.java
+++ b/emoji/core/src/main/java/androidx/emoji/text/EmojiCompat.java
@@ -61,7 +61,9 @@
  * <pre><code>EmojiCompat.init(&#47;* a config instance *&#47;);</code></pre>
  * <p/>
  * It is suggested to make the initialization as early as possible in your app. Please check {@link
- * EmojiCompat.Config} for more configuration parameters.
+ * EmojiCompat.Config} for more configuration parameters. Once {@link #init(EmojiCompat.Config)} is
+ * called a singleton instance will be created. Any call after that will not create a new instance
+ * and will return immediately.
  * <p/>
  * During initialization information about emojis is loaded on a background thread. Before the
  * EmojiCompat instance is initialized, calls to functions such as {@link
@@ -96,6 +98,11 @@
             "android.support.text.emoji.emojiCompat_replaceAll";
 
     /**
+     * EmojiCompat instance is constructed, however the initialization did not start yet.
+     */
+    public static final int LOAD_STATE_DEFAULT = 3;
+
+    /**
      * EmojiCompat is initializing.
      */
     public static final int LOAD_STATE_LOADING = 0;
@@ -115,7 +122,7 @@
      * @hide
      */
     @RestrictTo(LIBRARY_GROUP)
-    @IntDef({LOAD_STATE_LOADING, LOAD_STATE_SUCCEEDED, LOAD_STATE_FAILED})
+    @IntDef({LOAD_STATE_DEFAULT, LOAD_STATE_LOADING, LOAD_STATE_SUCCEEDED, LOAD_STATE_FAILED})
     @Retention(RetentionPolicy.SOURCE)
     public @interface LoadState {
     }
@@ -145,6 +152,26 @@
     }
 
     /**
+     * {@link EmojiCompat} will start loading metadata when {@link #init(Config)} is called.
+     */
+    public static final int LOAD_STRATEGY_DEFAULT = 0;
+
+    /**
+     * {@link EmojiCompat} will wait for {@link #load()} to be called by developer in order to
+     * start loading metadata.
+     */
+    public static final int LOAD_STRATEGY_MANUAL = 1;
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    @IntDef({LOAD_STRATEGY_DEFAULT, LOAD_STRATEGY_MANUAL})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LoadStrategy {
+    }
+
+    /**
      * @hide
      */
     @RestrictTo(LIBRARY_GROUP)
@@ -205,18 +232,25 @@
     private final int mEmojiSpanIndicatorColor;
 
     /**
+     * @see Config#setMetadataLoadStrategy(int)
+     */
+    @LoadStrategy private final int mMetadataLoadStrategy;
+
+    /**
      * Private constructor for singleton instance.
      *
      * @see #init(Config)
      */
     private EmojiCompat(@NonNull final Config config) {
         mInitLock = new ReentrantReadWriteLock();
+        mLoadState = LOAD_STATE_DEFAULT;
         mReplaceAll = config.mReplaceAll;
         mUseEmojiAsDefaultStyle = config.mUseEmojiAsDefaultStyle;
         mEmojiAsDefaultStyleExceptions = config.mEmojiAsDefaultStyleExceptions;
         mEmojiSpanIndicatorEnabled = config.mEmojiSpanIndicatorEnabled;
         mEmojiSpanIndicatorColor = config.mEmojiSpanIndicatorColor;
         mMetadataLoader = config.mMetadataLoader;
+        mMetadataLoadStrategy = config.mMetadataLoadStrategy;
         mMainHandler = new Handler(Looper.getMainLooper());
         mInitCallbacks = new ArraySet<>();
         if (config.mInitCallbacks != null && !config.mInitCallbacks.isEmpty()) {
@@ -230,7 +264,9 @@
     /**
      * Initialize the singleton instance with a configuration. When used on devices running API 18
      * or below, the singleton instance is immediately moved into {@link #LOAD_STATE_SUCCEEDED}
-     * state without loading any metadata.
+     * state without loading any metadata. When called for the first time, the library will create
+     * the singleton instance and any call after that will not create a new instance and return
+     * immediately.
      *
      * @see EmojiCompat.Config
      */
@@ -304,9 +340,30 @@
         }
     }
 
-    private void loadMetadata() {
+    /**
+     * When {@link Config#setMetadataLoadStrategy(int)} is set to {@link #LOAD_STRATEGY_MANUAL},
+     * this function starts loading the metadata. Calling the function when
+     * {@link Config#setMetadataLoadStrategy(int)} is {@code not} set to
+     * {@link #LOAD_STRATEGY_MANUAL} will throw an exception. The load will {@code not} start if:
+     * <ul>
+     *     <li>the metadata is already loaded successfully and {@link #getLoadState()} is
+     *     {@link #LOAD_STATE_SUCCEEDED}.
+     *     </li>
+     *      <li>a previous load attempt is not finished yet and {@link #getLoadState()} is
+     *     {@link #LOAD_STATE_LOADING}.</li>
+     * </ul>
+     *
+     * @throws IllegalStateException when {@link Config#setMetadataLoadStrategy(int)} is not set
+     * to {@link #LOAD_STRATEGY_MANUAL}
+     */
+    public void load() {
+        Preconditions.checkState(mMetadataLoadStrategy == LOAD_STRATEGY_MANUAL,
+                "Set metadataLoadStrategy to LOAD_STRATEGY_MANUAL to execute manual loading");
+        if (isInitialized()) return;
+
         mInitLock.writeLock().lock();
         try {
+            if (mLoadState == LOAD_STATE_LOADING) return;
             mLoadState = LOAD_STATE_LOADING;
         } finally {
             mInitLock.writeLock().unlock();
@@ -315,6 +372,21 @@
         mHelper.loadMetadata();
     }
 
+    private void loadMetadata() {
+        mInitLock.writeLock().lock();
+        try {
+            if (mMetadataLoadStrategy == LOAD_STRATEGY_DEFAULT) {
+                mLoadState = LOAD_STATE_LOADING;
+            }
+        } finally {
+            mInitLock.writeLock().unlock();
+        }
+
+        if (getLoadState() == LOAD_STATE_LOADING) {
+            mHelper.loadMetadata();
+        }
+    }
+
     private void onMetadataLoadSuccess() {
         final Collection<InitCallback> initCallbacks = new ArrayList<>();
         mInitLock.writeLock().lock();
@@ -389,8 +461,8 @@
      * Returns loading state of the EmojiCompat instance. When used on devices running API 18 or
      * below always returns {@link #LOAD_STATE_SUCCEEDED}.
      *
-     * @return one of {@link #LOAD_STATE_LOADING}, {@link #LOAD_STATE_SUCCEEDED},
-     * {@link #LOAD_STATE_FAILED}
+     * @return one of {@link #LOAD_STATE_DEFAULT}, {@link #LOAD_STATE_LOADING},
+     * {@link #LOAD_STATE_SUCCEEDED}, {@link #LOAD_STATE_FAILED}
      */
     public @LoadState int getLoadState() {
         mInitLock.readLock().lock();
@@ -805,6 +877,7 @@
         private Set<InitCallback> mInitCallbacks;
         private boolean mEmojiSpanIndicatorEnabled;
         private int mEmojiSpanIndicatorColor = Color.GREEN;
+        @LoadStrategy private int mMetadataLoadStrategy = LOAD_STRATEGY_DEFAULT;
 
         /**
          * Default constructor.
@@ -938,6 +1011,21 @@
         }
 
         /**
+         * Determines the strategy to start loading the metadata. By default {@link EmojiCompat}
+         * will start loading the metadata during {@link EmojiCompat#init(Config)}. When set to
+         * {@link EmojiCompat#LOAD_STRATEGY_MANUAL}, you should call {@link EmojiCompat#load()} to
+         * initiate metadata loading.
+         *
+         * @param strategy one of {@link EmojiCompat#LOAD_STRATEGY_DEFAULT},
+         *                  {@link EmojiCompat#LOAD_STRATEGY_MANUAL}
+         *
+         */
+        public Config setMetadataLoadStrategy(@LoadStrategy int strategy) {
+            mMetadataLoadStrategy = strategy;
+            return this;
+        }
+
+        /**
          * Returns the {@link MetadataRepoLoader}.
          */
         protected final MetadataRepoLoader getMetadataRepoLoader() {
diff --git a/emoji/core/src/main/java/androidx/emoji/widget/EmojiInputFilter.java b/emoji/core/src/main/java/androidx/emoji/widget/EmojiInputFilter.java
index 22837a6..b44e859 100644
--- a/emoji/core/src/main/java/androidx/emoji/widget/EmojiInputFilter.java
+++ b/emoji/core/src/main/java/androidx/emoji/widget/EmojiInputFilter.java
@@ -79,6 +79,7 @@
 
                 return source;
             case EmojiCompat.LOAD_STATE_LOADING:
+            case EmojiCompat.LOAD_STATE_DEFAULT:
                 EmojiCompat.get().registerInitCallback(getInitCallback());
                 return source;
 
diff --git a/emoji/core/src/main/java/androidx/emoji/widget/EmojiTextWatcher.java b/emoji/core/src/main/java/androidx/emoji/widget/EmojiTextWatcher.java
index 5d0e552..2197aff 100644
--- a/emoji/core/src/main/java/androidx/emoji/widget/EmojiTextWatcher.java
+++ b/emoji/core/src/main/java/androidx/emoji/widget/EmojiTextWatcher.java
@@ -80,6 +80,7 @@
                             mEmojiReplaceStrategy);
                     break;
                 case EmojiCompat.LOAD_STATE_LOADING:
+                case EmojiCompat.LOAD_STATE_DEFAULT:
                     EmojiCompat.get().registerInitCallback(getInitCallback());
                     break;
                 case EmojiCompat.LOAD_STATE_FAILED:
diff --git a/emoji/core/src/main/java/androidx/emoji/widget/EmojiTransformationMethod.java b/emoji/core/src/main/java/androidx/emoji/widget/EmojiTransformationMethod.java
index c082c83..81fe615 100644
--- a/emoji/core/src/main/java/androidx/emoji/widget/EmojiTransformationMethod.java
+++ b/emoji/core/src/main/java/androidx/emoji/widget/EmojiTransformationMethod.java
@@ -57,6 +57,7 @@
                     return EmojiCompat.get().process(source);
                 case EmojiCompat.LOAD_STATE_LOADING:
                 case EmojiCompat.LOAD_STATE_FAILED:
+                case EmojiCompat.LOAD_STATE_DEFAULT:
                 default:
                     break;
             }
diff --git a/fragment/ktx/OWNERS b/fragment/ktx/OWNERS
new file mode 100644
index 0000000..e450f4c
--- /dev/null
+++ b/fragment/ktx/OWNERS
@@ -0,0 +1 @@
+jakew@google.com
diff --git a/fragment/ktx/build.gradle b/fragment/ktx/build.gradle
new file mode 100644
index 0000000..52cb265
--- /dev/null
+++ b/fragment/ktx/build.gradle
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 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.
+ */
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+    id("org.jetbrains.kotlin.android")
+}
+
+android {
+    buildTypes {
+        debug {
+            testCoverageEnabled = false // Breaks Kotlin compiler.
+        }
+    }
+}
+
+dependencies {
+    api(project(":fragment"))
+    api(KOTLIN_STDLIB)
+    androidTestImplementation(JUNIT)
+    androidTestImplementation(TRUTH)
+    androidTestImplementation(TEST_RUNNER_TMP, libs.exclude_for_espresso)
+    androidTestImplementation(TEST_RULES_TMP, libs.exclude_for_espresso)
+}
+
+supportLibrary {
+    name = "Fragment Kotlin Extensions"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.FRAGMENT
+    inceptionYear = "2018"
+    description = "Kotlin extensions for 'fragment' artifact"
+}
diff --git a/fragment/ktx/src/androidTest/AndroidManifest.xml b/fragment/ktx/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..0a62e3e
--- /dev/null
+++ b/fragment/ktx/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="androidx.fragment.ktx">
+    <application>
+        <activity android:name="androidx.fragment.app.TestActivity"/>
+    </application>
+</manifest>
diff --git a/fragment/ktx/src/androidTest/java/androidx/fragment/app/FragmentManagerTest.kt b/fragment/ktx/src/androidTest/java/androidx/fragment/app/FragmentManagerTest.kt
new file mode 100644
index 0000000..7097955
--- /dev/null
+++ b/fragment/ktx/src/androidTest/java/androidx/fragment/app/FragmentManagerTest.kt
@@ -0,0 +1,59 @@
+package androidx.fragment.app
+
+import android.support.test.annotation.UiThreadTest
+import android.support.test.filters.MediumTest
+import android.support.test.rule.ActivityTestRule
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+
+@MediumTest
+class FragmentManagerTest {
+    @get:Rule val activityRule = ActivityTestRule<TestActivity>(TestActivity::class.java)
+    private val fragmentManager get() = activityRule.activity.supportFragmentManager
+
+    @UiThreadTest
+    @Test fun transaction() {
+        val fragment = TestFragment()
+        fragmentManager.transaction {
+            add(fragment, null)
+        }
+        assertThat(fragmentManager.fragments).doesNotContain(fragment)
+        fragmentManager.executePendingTransactions()
+        assertThat(fragmentManager.fragments).contains(fragment)
+    }
+
+    @UiThreadTest
+    @Test fun transactionNow() {
+        val fragment = TestFragment()
+        fragmentManager.transaction(now = true) {
+            add(fragment, null)
+        }
+        assertThat(fragmentManager.fragments).contains(fragment)
+    }
+
+    @UiThreadTest
+    @Test fun transactionAllowingStateLoss() {
+        // Use a detached FragmentManager to ensure state loss.
+        val fragmentManager = FragmentManagerImpl()
+
+        fragmentManager.transaction(allowStateLoss = true) {
+            add(TestFragment(), null)
+        }
+        assertThat(fragmentManager.fragments).isEmpty()
+    }
+
+    @UiThreadTest
+    @Test fun transactionNowAllowingStateLoss() {
+        // Use a detached FragmentManager to ensure state loss.
+        val fragmentManager = FragmentManagerImpl()
+
+        fragmentManager.transaction(now = true, allowStateLoss = true) {
+            add(TestFragment(), null)
+        }
+        assertThat(fragmentManager.fragments).isEmpty()
+    }
+}
+
+class TestActivity : FragmentActivity()
+class TestFragment : Fragment()
diff --git a/fragment/ktx/src/main/AndroidManifest.xml b/fragment/ktx/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..cd21eb1
--- /dev/null
+++ b/fragment/ktx/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+<manifest package="androidx.fragment.ktx"/>
diff --git a/fragment/ktx/src/main/java/androidx/fragment/app/FragmentManager.kt b/fragment/ktx/src/main/java/androidx/fragment/app/FragmentManager.kt
new file mode 100644
index 0000000..d9e8e96
--- /dev/null
+++ b/fragment/ktx/src/main/java/androidx/fragment/app/FragmentManager.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018 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 androidx.fragment.app
+
+/**
+ * Run [body] in a [FragmentTransaction] which is automatically committed if it completes without
+ * exception.
+ *
+ * One of four commit functions will be used based on the values of `now` and `allowStateLoss`:
+ *
+ * | `now` | `allowStateLoss` | Method                         |
+ * | ----- | ---------------- | ------------------------------ |
+ * | false | false            | `commit()`                     |
+ * | false | true             | `commitAllowingStateLoss()`    |
+ * | true  | false            | `commitNow()`                  |
+ * | true  | true             | `commitNowAllowingStateLoss()` |
+ */
+inline fun FragmentManager.transaction(
+    now: Boolean = false,
+    allowStateLoss: Boolean = false,
+    body: FragmentTransaction.() -> Unit
+) {
+    val transaction = beginTransaction()
+    transaction.body()
+    if (now) {
+        if (allowStateLoss) {
+            transaction.commitNowAllowingStateLoss()
+        } else {
+            transaction.commitNow()
+        }
+    } else {
+        if (allowStateLoss) {
+            transaction.commitAllowingStateLoss()
+        } else {
+            transaction.commit()
+        }
+    }
+}
diff --git a/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java b/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java
index 99f47d2..efee065 100644
--- a/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java
+++ b/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java
@@ -18,12 +18,6 @@
 
 import static android.support.test.InstrumentationRegistry.getContext;
 
-import static androidx.heifwriter.HeifWriter.INPUT_MODE_BITMAP;
-import static androidx.heifwriter.HeifWriter.INPUT_MODE_BUFFER;
-import static androidx.heifwriter.HeifWriter.INPUT_MODE_SURFACE;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
 import android.graphics.Bitmap;
 import android.graphics.ImageFormat;
 import android.media.MediaExtractor;
@@ -34,13 +28,21 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Process;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
+
+import static androidx.heifwriter.HeifWriter.INPUT_MODE_BITMAP;
+import static androidx.heifwriter.HeifWriter.INPUT_MODE_BUFFER;
+import static androidx.heifwriter.HeifWriter.INPUT_MODE_SURFACE;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.heifwriter.test.R;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -553,10 +555,14 @@
             MediaExtractor extractor = new MediaExtractor();
             extractor.setDataSource(filename);
             MediaFormat format = extractor.getTrackFormat(0);
-            int gridWidth = format.getInteger(MediaFormat.KEY_GRID_WIDTH);
-            int gridHeight = format.getInteger(MediaFormat.KEY_GRID_HEIGHT);
-            assertEquals("Wrong grid width", 512, gridWidth);
-            assertEquals("Wrong grid height", 512, gridHeight);
+            int gridWidth = format.getInteger(MediaFormat.KEY_TILE_WIDTH);
+            int gridHeight = format.getInteger(MediaFormat.KEY_TILE_HEIGHT);
+            int gridRows = format.getInteger(MediaFormat.KEY_GRID_ROWS);
+            int gridCols = format.getInteger(MediaFormat.KEY_GRID_COLUMNS);
+            assertTrue("Wrong grid width or cols",
+                    ((width + gridWidth - 1) / gridWidth) == gridCols);
+            assertTrue("Wrong grid height or rows",
+                    ((height + gridHeight - 1) / gridHeight) == gridRows);
             extractor.release();
         }
     }
diff --git a/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java b/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java
index 85aa925..babfc18 100644
--- a/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java
+++ b/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java
@@ -17,14 +17,9 @@
 package androidx.heifwriter;
 
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
-import android.opengl.GLES20;
-import android.opengl.GLUtils;
-import android.os.Looper;
-import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import android.media.Image;
 import android.media.MediaCodec;
 import android.media.MediaCodec.BufferInfo;
@@ -32,13 +27,19 @@
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaFormat;
+import android.opengl.GLES20;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.Looper;
 import android.os.Process;
 import android.util.Log;
 import android.util.Range;
 import android.view.Surface;
 
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -179,25 +180,14 @@
             throw new IllegalArgumentException("invalid encoder inputs");
         }
 
-        mEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_HEVC);
-
-        mWidth = width;
-        mHeight = height;
-
-        if (useGrid) {
-            mGridWidth = GRID_WIDTH;
-            mGridHeight = GRID_HEIGHT;
-            mGridRows = (height + GRID_HEIGHT - 1) / GRID_HEIGHT;
-            mGridCols = (width + GRID_WIDTH - 1) / GRID_WIDTH;
-        } else {
-            mGridWidth = mWidth;
-            mGridHeight = mHeight;
-            mGridRows = 1;
-            mGridCols = 1;
+        boolean useHeicEncoder = false;
+        try {
+            mEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC);
+            useHeicEncoder = true;
+        } catch (Exception e) {
+            mEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_HEVC);
         }
 
-        mNumTiles = mGridRows * mGridCols;
-
         mInputMode = inputMode;
 
         mCallback = cb;
@@ -218,13 +208,61 @@
                 CodecCapabilities.COLOR_FormatYUV420Flexible;
 
         // TODO: determine how to set bitrate and framerate, or use constant quality
-        MediaFormat codecFormat = MediaFormat.createVideoFormat(
-                MediaFormat.MIMETYPE_VIDEO_HEVC, mGridWidth, mGridHeight);
+        mWidth = width;
+        mHeight = height;
+
+        int gridWidth, gridHeight, gridRows, gridCols;
+
+        useGrid = useGrid && (width > GRID_WIDTH || height > GRID_HEIGHT);
+
+        if (useGrid) {
+            gridWidth = GRID_WIDTH;
+            gridHeight = GRID_HEIGHT;
+            gridRows = (height + GRID_HEIGHT - 1) / GRID_HEIGHT;
+            gridCols = (width + GRID_WIDTH - 1) / GRID_WIDTH;
+        } else {
+            gridWidth = mWidth;
+            gridHeight = mHeight;
+            gridRows = 1;
+            gridCols = 1;
+        }
+
+        MediaFormat codecFormat;
+        if (useHeicEncoder) {
+            codecFormat = MediaFormat.createVideoFormat(
+                    MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC, mWidth, mHeight);
+        } else {
+            codecFormat = MediaFormat.createVideoFormat(
+                    MediaFormat.MIMETYPE_VIDEO_HEVC, gridWidth, gridHeight);
+        }
+
+        if (useGrid) {
+            codecFormat.setInteger(MediaFormat.KEY_TILE_WIDTH, gridWidth);
+            codecFormat.setInteger(MediaFormat.KEY_TILE_HEIGHT, gridHeight);
+            codecFormat.setInteger(MediaFormat.KEY_GRID_COLUMNS, gridCols);
+            codecFormat.setInteger(MediaFormat.KEY_GRID_ROWS, gridRows);
+        }
+
+        if (useHeicEncoder) {
+            mGridWidth = width;
+            mGridHeight = height;
+            mGridRows = 1;
+            mGridCols = 1;
+        } else {
+            mGridWidth = gridWidth;
+            mGridHeight = gridHeight;
+            mGridRows = gridRows;
+            mGridCols = gridCols;
+        }
+        mNumTiles = mGridRows * mGridCols;
+
         codecFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 0);
         codecFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
 
         MediaCodecInfo.CodecCapabilities caps =
-                mEncoder.getCodecInfo().getCapabilitiesForType(MediaFormat.MIMETYPE_VIDEO_HEVC);
+                mEncoder.getCodecInfo().getCapabilitiesForType(useHeicEncoder
+                        ? MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC
+                        : MediaFormat.MIMETYPE_VIDEO_HEVC);
         MediaCodecInfo.EncoderCapabilities encoderCaps = caps.getEncoderCapabilities();
 
         codecFormat.setInteger(MediaFormat.KEY_FRAME_RATE, mNumTiles);
@@ -262,34 +300,36 @@
         if (useSurfaceInternally) {
             mEncoderSurface = mEncoder.createInputSurface();
 
-            boolean useGLCopy = (mNumTiles > 1) || (inputMode == INPUT_MODE_BITMAP);
-            mEOSTracker = new SurfaceEOSTracker(useGLCopy);
+            boolean copyTiles = (mNumTiles > 1);
+            mEOSTracker = new SurfaceEOSTracker(copyTiles);
 
-            if (useGLCopy) {
-                mEncoderEglSurface = new EglWindowSurface(mEncoderSurface);
-                mEncoderEglSurface.makeCurrent();
+            if (inputMode == INPUT_MODE_SURFACE) {
+                if (copyTiles) {
+                    mEncoderEglSurface = new EglWindowSurface(mEncoderSurface);
+                    mEncoderEglSurface.makeCurrent();
 
-                mRectBlt = new EglRectBlt(
-                        new Texture2dProgram((inputMode == INPUT_MODE_BITMAP) ?
-                                Texture2dProgram.TEXTURE_2D :
-                                Texture2dProgram.TEXTURE_EXT),
-                        mWidth, mHeight);
+                    mRectBlt = new EglRectBlt(
+                            new Texture2dProgram((inputMode == INPUT_MODE_BITMAP)
+                                    ? Texture2dProgram.TEXTURE_2D
+                                    : Texture2dProgram.TEXTURE_EXT),
+                            mWidth, mHeight);
 
-                mTextureId = mRectBlt.createTextureObject();
+                    mTextureId = mRectBlt.createTextureObject();
 
-                if (inputMode == INPUT_MODE_SURFACE) {
-                    // use single buffer mode to block on input
-                    mInputTexture = new SurfaceTexture(mTextureId, true);
-                    mInputTexture.setOnFrameAvailableListener(this);
-                    mInputTexture.setDefaultBufferSize(mWidth, mHeight);
-                    mInputSurface = new Surface(mInputTexture);
+                    if (inputMode == INPUT_MODE_SURFACE) {
+                        // use single buffer mode to block on input
+                        mInputTexture = new SurfaceTexture(mTextureId, true);
+                        mInputTexture.setOnFrameAvailableListener(this);
+                        mInputTexture.setDefaultBufferSize(mWidth, mHeight);
+                        mInputSurface = new Surface(mInputTexture);
+                    }
+
+                    // make uncurrent since onFrameAvailable could be called on arbituray thread.
+                    // making the context current on a different thread will cause error.
+                    mEncoderEglSurface.makeUnCurrent();
+                } else {
+                    mInputSurface = mEncoderSurface;
                 }
-
-                // make uncurrent since the onFrameAvailable could be called on arbituray thread.
-                // making the context current on a different thread will cause error.
-                mEncoderEglSurface.makeUnCurrent();
-            } else {
-                mInputSurface = mEncoderSurface;
             }
         } else {
             for (int i = 0; i < INPUT_BUFFER_POOL_SIZE; i++) {
@@ -321,7 +361,20 @@
                     computePresentationTime(mInputIndex + mNumTiles - 1));
 
             if (takeFrame) {
-                copyTilesGL(mTmpMatrix);
+                // Copies from surface texture to encoder inputs using GL.
+                GLES20.glViewport(0, 0, mGridWidth, mGridHeight);
+
+                for (int row = 0; row < mGridRows; row++) {
+                    for (int col = 0; col < mGridCols; col++) {
+                        int left = col * mGridWidth;
+                        int top = row * mGridHeight;
+                        mSrcRect.set(left, top, left + mGridWidth, top + mGridHeight);
+                        mRectBlt.copyRect(mTextureId, mTmpMatrix, mSrcRect);
+                        mEncoderEglSurface.setPresentationTime(
+                                1000 * computePresentationTime(mInputIndex++));
+                        mEncoderEglSurface.swapBuffers();
+                    }
+                }
             }
 
             surfaceTexture.releaseTexImage();
@@ -407,21 +460,16 @@
         if (!takeFrame) return;
 
         synchronized (this) {
-            if (mEncoderEglSurface == null) {
-                return;
+            for (int row = 0; row < mGridRows; row++) {
+                for (int col = 0; col < mGridCols; col++) {
+                    int left = col * mGridWidth;
+                    int top = row * mGridHeight;
+                    mSrcRect.set(left, top, left + mGridWidth, top + mGridHeight);
+                    Canvas canvas = mEncoderSurface.lockCanvas(null);
+                    canvas.drawBitmap(bitmap, mSrcRect, mDstRect, null);
+                    mEncoderSurface.unlockCanvasAndPost(canvas);
+                }
             }
-
-            mEncoderEglSurface.makeCurrent();
-
-            // load the bitmap to texture
-            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);
-            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
-
-            copyTilesGL(Texture2dProgram.V_FLIP_MATRIX);
-
-            // make uncurrent since the onFrameAvailable could be called on arbituray thread.
-            // making the context current on a different thread will cause error.
-            mEncoderEglSurface.makeUnCurrent();
         }
     }
 
@@ -594,28 +642,6 @@
     }
 
     /**
-     * Copies from source frame to encoder inputs using GL. The source could be either
-     * client's input surface, or the input bitmap loaded to texture.
-     *
-     * @param texMatrix The texture matrix to use. See the shader program in
-     * {@link Texture2dProgram} as well as {@link SurfaceTexture} for more details.
-     */
-    private void copyTilesGL(float[] texMatrix) {
-        GLES20.glViewport(0, 0, mGridWidth, mGridHeight);
-
-        for (int row = 0; row < mGridRows; row++) {
-            for (int col = 0; col < mGridCols; col++) {
-                int left = col * mGridWidth;
-                int top = row * mGridHeight;
-                mSrcRect.set(left, top, left + mGridWidth, top + mGridHeight);
-                mRectBlt.copyRect(mTextureId, texMatrix, mSrcRect);
-                mEncoderEglSurface.setPresentationTime(1000 * computePresentationTime(mInputIndex++));
-                mEncoderEglSurface.swapBuffers();
-            }
-        }
-    }
-
-    /**
      * Routine to release all resources. Must be run on the same looper that
      * handles the MediaCodec callbacks.
      */
@@ -677,7 +703,7 @@
     private class SurfaceEOSTracker {
         private static final boolean DEBUG_EOS = false;
 
-        final boolean mUseGLCopy;
+        final boolean mCopyTiles;
         long mInputEOSTimeNs = -1;
         long mLastInputTimeNs = -1;
         long mEncoderEOSTimeUs = -1;
@@ -685,14 +711,14 @@
         long mLastOutputTimeUs = -1;
         boolean mSignaled;
 
-        SurfaceEOSTracker(boolean useGLCopy) {
-            mUseGLCopy = useGLCopy;
+        SurfaceEOSTracker(boolean copyTiles) {
+            mCopyTiles = copyTiles;
         }
 
         synchronized void updateInputEOSTime(long timestampNs) {
             if (DEBUG_EOS) Log.d(TAG, "updateInputEOSTime: " + timestampNs);
 
-            if (mUseGLCopy) {
+            if (mCopyTiles) {
                 if (mInputEOSTimeNs < 0) {
                     mInputEOSTimeNs = timestampNs;
                 }
@@ -773,15 +799,18 @@
 
             if (DEBUG) Log.d(TAG, "onOutputFormatChanged: " + format);
 
-            format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC);
-            format.setInteger(MediaFormat.KEY_WIDTH, mWidth);
-            format.setInteger(MediaFormat.KEY_HEIGHT, mHeight);
+            if (!MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC.equals(
+                    format.getString(MediaFormat.KEY_MIME))) {
+                format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC);
+                format.setInteger(MediaFormat.KEY_WIDTH, mWidth);
+                format.setInteger(MediaFormat.KEY_HEIGHT, mHeight);
 
-            if (mNumTiles > 1) {
-                format.setInteger(MediaFormat.KEY_GRID_WIDTH, mGridWidth);
-                format.setInteger(MediaFormat.KEY_GRID_HEIGHT, mGridHeight);
-                format.setInteger(MediaFormat.KEY_GRID_ROWS, mGridRows);
-                format.setInteger(MediaFormat.KEY_GRID_COLS, mGridCols);
+                if (mNumTiles > 1) {
+                    format.setInteger(MediaFormat.KEY_TILE_WIDTH, mGridWidth);
+                    format.setInteger(MediaFormat.KEY_TILE_HEIGHT, mGridHeight);
+                    format.setInteger(MediaFormat.KEY_GRID_ROWS, mGridRows);
+                    format.setInteger(MediaFormat.KEY_GRID_COLUMNS, mGridCols);
+                }
             }
 
             mCallback.onOutputFormatChanged(HeifEncoder.this, format);
@@ -800,8 +829,12 @@
         public void onOutputBufferAvailable(MediaCodec codec, int index, BufferInfo info) {
             if (codec != mEncoder || mOutputEOS) return;
 
-            if (DEBUG) Log.d(TAG, "onInputBufferAvailable: " + index + ", time "
-                    + info.presentationTimeUs + ", size " + info.size + ", flags " + info.flags);
+            if (DEBUG) {
+                Log.d(TAG, "onOutputBufferAvailable: " + index
+                        + ", time " + info.presentationTimeUs
+                        + ", size " + info.size
+                        + ", flags " + info.flags);
+            }
 
             if ((info.size > 0) && ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0)) {
                 ByteBuffer outputBuffer = codec.getOutputBuffer(index);
diff --git a/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java b/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java
index be7dffb..9c96b6d 100644
--- a/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java
+++ b/heifwriter/src/main/java/androidx/heifwriter/HeifWriter.java
@@ -400,7 +400,7 @@
 
             try {
                 int gridRows = format.getInteger(MediaFormat.KEY_GRID_ROWS);
-                int gridCols = format.getInteger(MediaFormat.KEY_GRID_COLS);
+                int gridCols = format.getInteger(MediaFormat.KEY_GRID_COLUMNS);
                 mNumTiles = gridRows * gridCols;
             } catch (NullPointerException | ClassCastException  e) {
                 mNumTiles = 1;
diff --git a/leanback/src/main/res/values-be/strings.xml b/leanback/src/main/res/values-be/strings.xml
index 2828004..a4038d6 100644
--- a/leanback/src/main/res/values-be/strings.xml
+++ b/leanback/src/main/res/values-be/strings.xml
@@ -21,8 +21,8 @@
     <string name="orb_search_action" msgid="7534843523462177008">"Пошук"</string>
     <string name="lb_search_bar_hint" msgid="4819380969103509861">"Пошук"</string>
     <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Прамоўце пошукавы запыт"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Шукаць тут <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Прамоўце пошукавы запыт тут <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Шукаць тут: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Прамоўце запыт для пошуку тут: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
     <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
     <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
     <string name="lb_playback_controls_play" msgid="1590369760862605402">"Прайграць"</string>
@@ -53,7 +53,7 @@
     <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Элементы кіравання мультымедыя схаваны. Каб паказаць іх, націсніце d-pad"</string>
     <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Завяршыць"</string>
     <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Працягнуць"</string>
-    <string name="lb_media_player_error" msgid="8748646000835486516">"Код памылкі MediaPlayer %1$d дадаткова %2$d"</string>
+    <string name="lb_media_player_error" msgid="8748646000835486516">"Код памылкі MediaPlayer: %1$d (дадатковы: %2$d)"</string>
     <string name="lb_onboarding_get_started" msgid="7674487829030291492">"ПАЧАЦЬ"</string>
     <string name="lb_onboarding_accessibility_next" msgid="4213611627196077555">"Далей"</string>
 </resources>
diff --git a/leanback/src/main/res/values-es/strings.xml b/leanback/src/main/res/values-es/strings.xml
index dc33a6b..5d85c92 100644
--- a/leanback/src/main/res/values-es/strings.xml
+++ b/leanback/src/main/res/values-es/strings.xml
@@ -22,7 +22,7 @@
     <string name="lb_search_bar_hint" msgid="4819380969103509861">"Haz una búsqueda"</string>
     <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Habla para buscar"</string>
     <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Busca <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Busca <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> por voz"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Habla para buscar <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
     <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dx"</string>
     <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dx"</string>
     <string name="lb_playback_controls_play" msgid="1590369760862605402">"Reproducir"</string>
diff --git a/leanback/src/main/res/values-eu/strings.xml b/leanback/src/main/res/values-eu/strings.xml
index 6b7226f..72c433f 100644
--- a/leanback/src/main/res/values-eu/strings.xml
+++ b/leanback/src/main/res/values-eu/strings.xml
@@ -49,8 +49,8 @@
     <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Desgaitu azpitituluak"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Aktibatu \"Pantaila txiki gainjarri\" modua"</string>
     <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
-    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Multimedia kontrolatzeko aukerak ikusgai"</string>
-    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Ezkutatuta daude multimedia-edukia kontrolatzeko aukerak. Erakusteko, sakatu nabigazio-gurutzea."</string>
+    <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Multimedia-edukia kontrolatzeko aukerak ikusgai"</string>
+    <string name="lb_playback_controls_hidden" msgid="619396299825306757">"Ezkutatuta daude multimedia-edukia kontrolatzeko aukerak. Haiek erakusteko, sakatu nabigazio-gurutzea."</string>
     <string name="lb_guidedaction_finish_title" msgid="7747913934287176843">"Amaitu"</string>
     <string name="lb_guidedaction_continue_title" msgid="1122271825827282965">"Egin aurrera"</string>
     <string name="lb_media_player_error" msgid="8748646000835486516">"MediaPlayer errore-kodea: %1$d (%2$d gehigarria)"</string>
diff --git a/leanback/src/main/res/values-fr-rCA/strings.xml b/leanback/src/main/res/values-fr-rCA/strings.xml
index de3fde5..ad38e94 100644
--- a/leanback/src/main/res/values-fr-rCA/strings.xml
+++ b/leanback/src/main/res/values-fr-rCA/strings.xml
@@ -32,7 +32,7 @@
     <string name="lb_playback_controls_rewind" msgid="1412664391757869774">"Retour arrière"</string>
     <string name="lb_playback_controls_rewind_multiplier" msgid="8651612807713092781">"Retour rapide à %1$dX"</string>
     <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"Passer à l\'élément suivant"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Passer à l\'élément précédent"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"Retourner à l\'élément précédent"</string>
     <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"Autres actions"</string>
     <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"Désélectionner la mention « J\'aime »"</string>
     <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"Sélectionner la mention « J\'aime »"</string>
diff --git a/leanback/src/main/res/values-ja/strings.xml b/leanback/src/main/res/values-ja/strings.xml
index 22980f1..96f27e2 100644
--- a/leanback/src/main/res/values-ja/strings.xml
+++ b/leanback/src/main/res/values-ja/strings.xml
@@ -43,8 +43,8 @@
     <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"1 曲をリピート"</string>
     <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"シャッフルを有効にする"</string>
     <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"シャッフルを無効にする"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"高品質を有効にする"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"高品質を無効にする"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"高画質を有効にする"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"高画質を無効にする"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"クローズド キャプションを有効にする"</string>
     <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"クローズド キャプションを無効にする"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"ピクチャー イン ピクチャー モードに移動"</string>
diff --git a/leanback/src/main/res/values-ko/strings.xml b/leanback/src/main/res/values-ko/strings.xml
index 9eacb53..b1587b9 100644
--- a/leanback/src/main/res/values-ko/strings.xml
+++ b/leanback/src/main/res/values-ko/strings.xml
@@ -40,7 +40,7 @@
     <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"싫어요 선택"</string>
     <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"반복 안함"</string>
     <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"전체 반복"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"한 항목 반복"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"한 개 반복"</string>
     <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"셔플 사용 설정"</string>
     <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"셔플 사용 중지"</string>
     <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"고품질 사용 설정"</string>
diff --git a/leanback/src/main/res/values-mr/strings.xml b/leanback/src/main/res/values-mr/strings.xml
index b01e273..07b4e14 100644
--- a/leanback/src/main/res/values-mr/strings.xml
+++ b/leanback/src/main/res/values-mr/strings.xml
@@ -29,7 +29,7 @@
     <!-- String.format failed for translation -->
     <!-- no translation found for lb_control_display_rewind_multiplier (6173753802428649303) -->
     <skip />
-    <string name="lb_playback_controls_play" msgid="1590369760862605402">"खेळा"</string>
+    <string name="lb_playback_controls_play" msgid="1590369760862605402">"प्ले"</string>
     <string name="lb_playback_controls_pause" msgid="1769131316742618433">"विराम द्या"</string>
     <string name="lb_playback_controls_fast_forward" msgid="8966769845721269304">"पुढे ढकला"</string>
     <string name="lb_playback_controls_fast_forward_multiplier" msgid="801276177839339511">"फास्ट फॉरवर्ड %1$d"</string>
@@ -38,10 +38,10 @@
     <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"पुढील वगळा"</string>
     <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"मागील वगळा"</string>
     <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"आणखी क्रिया"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"वर अंगठा निवड रद्द करा"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"वर अंगठा निवडा"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"खाली अंगठा निवड रद्द करा"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"खाली अंगठा निवडा"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"थंब अप निवड रद्द करा"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"थंब अप निवडा"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"थंब डाउन निवड रद्द करा"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"थंब डाउन निवडा"</string>
     <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"काहीही रिपीट करू नका"</string>
     <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"सर्व रिपीट करा"</string>
     <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"एक रिपीट करा"</string>
diff --git a/leanback/src/main/res/values-uz/strings.xml b/leanback/src/main/res/values-uz/strings.xml
index 50a86af..95e0b67 100644
--- a/leanback/src/main/res/values-uz/strings.xml
+++ b/leanback/src/main/res/values-uz/strings.xml
@@ -21,8 +21,8 @@
     <string name="orb_search_action" msgid="7534843523462177008">"Qidiruv amali"</string>
     <string name="lb_search_bar_hint" msgid="4819380969103509861">"Qidiruv"</string>
     <string name="lb_search_bar_hint_speech" msgid="2795474673510974502">"Qidirish uchun gapiring"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"Qidirish: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"Qidirish uchun ayting: <xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g>"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="7453744869467668159">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ichidan qidirish"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="5851694095153624617">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> ichidan qidirish uchun gapiring"</string>
     <string name="lb_control_display_fast_forward_multiplier" msgid="2721825378927619928">"%1$dX"</string>
     <string name="lb_control_display_rewind_multiplier" msgid="6173753802428649303">"%1$dX"</string>
     <string name="lb_playback_controls_play" msgid="1590369760862605402">"Ijro"</string>
@@ -39,14 +39,14 @@
     <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"Salbiy baho tanlovini bekor qilish"</string>
     <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"Salbiy bahoni tanlash"</string>
     <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"Takrorlamaslik"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Barchasini takrorlash"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"Hammasini takrorlash"</string>
     <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"Bir marta takrorlash"</string>
     <string name="lb_playback_controls_shuffle_enable" msgid="7809089255981448519">"Aralashtirish funksiyasini yoqish"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Aralashtirish funksiyasini o‘chirish"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8182435535948303910">"Aralashtirmaslik"</string>
     <string name="lb_playback_controls_high_quality_enable" msgid="1862669142355962638">"Yuqori sifatni yoqish"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Yuqori sifatni o‘chirib qo‘yish"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="3000046054608531995">"Yuqori sifatda ijro qilmaslik"</string>
     <string name="lb_playback_controls_closed_captioning_enable" msgid="3934392140182327163">"Taglavhalarni yoqish"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Taglavhalarni o‘chirib qo‘yish"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="5508271941331836786">"Taglavhalarni chiqarmaslik"</string>
     <string name="lb_playback_controls_picture_in_picture" msgid="8800305194045609275">"Tasvir ustida tasvir rejimiga kirish"</string>
     <string name="lb_playback_time_separator" msgid="6549544638083578695">"/"</string>
     <string name="lb_playback_controls_shown" msgid="7794717158616536936">"Boshqaruv elementlari ochiq"</string>
diff --git a/leanback/src/main/res/values-zh-rTW/strings.xml b/leanback/src/main/res/values-zh-rTW/strings.xml
index bcaf11e..9aea4d2 100644
--- a/leanback/src/main/res/values-zh-rTW/strings.xml
+++ b/leanback/src/main/res/values-zh-rTW/strings.xml
@@ -34,10 +34,10 @@
     <string name="lb_playback_controls_skip_next" msgid="4877009494447817003">"跳至下一個項目"</string>
     <string name="lb_playback_controls_skip_previous" msgid="3147124289285911980">"跳至上一個項目"</string>
     <string name="lb_playback_controls_more_actions" msgid="2827883329510404797">"更多動作"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"取消選取喜歡"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"選取喜歡"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"取消選取不喜歡"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"選取不喜歡"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="8332816524260995892">"取消選取「喜歡」"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1038344559734334272">"選取「喜歡」"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="5075744418630733006">"取消選取「不喜歡」"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2847309435442474470">"選取「不喜歡」"</string>
     <string name="lb_playback_controls_repeat_none" msgid="5812341701962930499">"不重複播放"</string>
     <string name="lb_playback_controls_repeat_all" msgid="5164826436271322261">"重複播放所有項目"</string>
     <string name="lb_playback_controls_repeat_one" msgid="7675097479246139440">"重複播放單一項目"</string>
diff --git a/lifecycle/reactivestreams/build.gradle b/lifecycle/reactivestreams/build.gradle
index 34390b7..649c526 100644
--- a/lifecycle/reactivestreams/build.gradle
+++ b/lifecycle/reactivestreams/build.gradle
@@ -35,9 +35,7 @@
 
     testImplementation(JUNIT)
     testImplementation(RX_JAVA)
-    testImplementation(TEST_RUNNER)
-
-    androidTestImplementation(SUPPORT_APPCOMPAT, libs.support_exclude_config)
+    testImplementation(project(":arch:core-testing"))
 }
 
 supportLibrary {
@@ -48,4 +46,4 @@
     inceptionYear = "2017"
     description = "Android Lifecycle Reactivestreams"
     url = SupportLibraryExtension.ARCHITECTURE_URL
-}
\ No newline at end of file
+}
diff --git a/lifecycle/reactivestreams/ktx/OWNERS b/lifecycle/reactivestreams/ktx/OWNERS
new file mode 100644
index 0000000..e450f4c
--- /dev/null
+++ b/lifecycle/reactivestreams/ktx/OWNERS
@@ -0,0 +1 @@
+jakew@google.com
diff --git a/lifecycle/reactivestreams/ktx/build.gradle b/lifecycle/reactivestreams/ktx/build.gradle
new file mode 100644
index 0000000..2604a8e
--- /dev/null
+++ b/lifecycle/reactivestreams/ktx/build.gradle
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
+
+plugins {
+  id("SupportAndroidLibraryPlugin")
+  id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+  api(project(":lifecycle:lifecycle-reactivestreams"))
+  api(KOTLIN_STDLIB)
+
+  testImplementation(JUNIT)
+  testImplementation(RX_JAVA)
+  testImplementation(TRUTH)
+  testImplementation(project(":arch:core-testing"))
+}
+
+supportLibrary {
+  name = "Android Lifecycle ReactiveStreams KTX"
+  publish = true
+  mavenVersion = LibraryVersions.LIFECYCLES_EXT
+  mavenGroup = LibraryGroups.LIFECYCLE
+  inceptionYear = "2018"
+  description = "Kotlin extensions for Lifecycle ReactiveStreams"
+  url = SupportLibraryExtension.ARCHITECTURE_URL
+}
diff --git a/lifecycle/reactivestreams/ktx/src/main/AndroidManifest.xml b/lifecycle/reactivestreams/ktx/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d2c150c
--- /dev/null
+++ b/lifecycle/reactivestreams/ktx/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<manifest package="androidx.lifecycle.reactivestreams.ktx"/>
diff --git a/lifecycle/reactivestreams/ktx/src/main/java/androidx/lifecycle/LiveDataReactiveSteams.kt b/lifecycle/reactivestreams/ktx/src/main/java/androidx/lifecycle/LiveDataReactiveSteams.kt
new file mode 100644
index 0000000..e4a95e7
--- /dev/null
+++ b/lifecycle/reactivestreams/ktx/src/main/java/androidx/lifecycle/LiveDataReactiveSteams.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.lifecycle
+
+import org.reactivestreams.Publisher
+
+/**
+ * Adapts the given [LiveData] stream to a ReactiveStreams [Publisher].
+ *
+ * @see LiveDataReactiveStreams.toPublisher
+ */
+inline fun <T> LiveData<T>.toPublisher(lifecycle: LifecycleOwner): Publisher<T> =
+    LiveDataReactiveStreams.toPublisher(lifecycle, this)
+
+/**
+ * Creates an observable [LiveData] stream from a ReactiveStreams [Publisher].
+ *
+ * @see LiveDataReactiveStreams.fromPublisher
+ */
+inline fun <T> Publisher<T>.toLiveData(): LiveData<T> =
+    LiveDataReactiveStreams.fromPublisher(this)
diff --git a/lifecycle/reactivestreams/ktx/src/test/java/androidx/lifecycle/LiveDataReactiveStreamsTest.kt b/lifecycle/reactivestreams/ktx/src/test/java/androidx/lifecycle/LiveDataReactiveStreamsTest.kt
new file mode 100644
index 0000000..ad3bdb2
--- /dev/null
+++ b/lifecycle/reactivestreams/ktx/src/test/java/androidx/lifecycle/LiveDataReactiveStreamsTest.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 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 androidx.lifecycle
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.google.common.truth.Truth.assertThat
+import io.reactivex.processors.PublishProcessor
+import io.reactivex.processors.ReplayProcessor
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+class LiveDataReactiveStreamsTest {
+    @get:Rule val rule = InstantTaskExecutorRule()
+
+    private lateinit var lifecycleOwner: LifecycleOwner
+
+    @Before fun init() {
+        lifecycleOwner = object : LifecycleOwner {
+            internal var registry = LifecycleRegistry(this)
+
+            init {
+                registry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
+            }
+
+            override fun getLifecycle(): Lifecycle {
+                return registry
+            }
+        }
+    }
+
+    @Test fun convertsFromPublisher() {
+        val processor = PublishProcessor.create<String>()
+        val liveData = processor.toLiveData()
+
+        val output = mutableListOf<String?>()
+        liveData.observe(lifecycleOwner, Observer { output.add(it) })
+
+        processor.onNext("foo")
+        processor.onNext("bar")
+        processor.onNext("baz")
+
+        assertThat(output).containsExactly("foo", "bar", "baz")
+    }
+
+    @Test fun convertsToPublisherWithSyncData() {
+        val liveData = MutableLiveData<String>()
+        liveData.value = "foo"
+
+        val outputProcessor = ReplayProcessor.create<String>()
+        liveData.toPublisher(lifecycleOwner).subscribe(outputProcessor)
+
+        liveData.value = "bar"
+        liveData.value = "baz"
+
+        assertThat(outputProcessor.values).asList().containsExactly("foo", "bar", "baz")
+    }
+}
diff --git a/lifecycle/reactivestreams/src/androidTest/AndroidManifest.xml b/lifecycle/reactivestreams/src/androidTest/AndroidManifest.xml
deleted file mode 100644
index 304fd93..0000000
--- a/lifecycle/reactivestreams/src/androidTest/AndroidManifest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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.
-  -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="androidx.lifecycle.reactivestreams.test">
-    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
-
-    <application>
-        <activity android:name="androidx.lifecycle.viewmodeltest.ViewModelActivity"
-                  android:theme="@style/Base.Theme.AppCompat">
-        </activity>
-    </application>
-
-</manifest>
diff --git a/lifecycle/reactivestreams/src/main/java/androidx/lifecycle/LiveDataReactiveStreams.java b/lifecycle/reactivestreams/src/main/java/androidx/lifecycle/LiveDataReactiveStreams.java
index 4af5a09..711e71e 100644
--- a/lifecycle/reactivestreams/src/main/java/androidx/lifecycle/LiveDataReactiveStreams.java
+++ b/lifecycle/reactivestreams/src/main/java/androidx/lifecycle/LiveDataReactiveStreams.java
@@ -165,7 +165,7 @@
     }
 
     /**
-     * Creates an Observable {@link LiveData} stream from a ReactiveStreams publisher.
+     * Creates an observable {@link LiveData} stream from a ReactiveStreams {@link Publisher}}.
      *
      * <p>
      * When the LiveData becomes active, it subscribes to the emissions from the Publisher.
diff --git a/lifecycle/reactivestreams/src/test/java/androidx/lifecycle/LiveDataReactiveStreamsTest.java b/lifecycle/reactivestreams/src/test/java/androidx/lifecycle/LiveDataReactiveStreamsTest.java
index 6311d94..ed792d2 100644
--- a/lifecycle/reactivestreams/src/test/java/androidx/lifecycle/LiveDataReactiveStreamsTest.java
+++ b/lifecycle/reactivestreams/src/test/java/androidx/lifecycle/LiveDataReactiveStreamsTest.java
@@ -21,15 +21,13 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
-import android.support.test.filters.SmallTest;
-
 import androidx.annotation.Nullable;
-import androidx.arch.core.executor.ArchTaskExecutor;
-import androidx.arch.core.executor.TaskExecutor;
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule;
 
-import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.reactivestreams.Subscriber;
 import org.reactivestreams.Subscription;
 
@@ -47,8 +45,9 @@
 import io.reactivex.schedulers.TestScheduler;
 import io.reactivex.subjects.AsyncSubject;
 
-@SmallTest
 public class LiveDataReactiveStreamsTest {
+    @Rule public final TestRule instantTaskExecutorRule = new InstantTaskExecutorRule();
+
     private LifecycleOwner mLifecycleOwner;
 
     private final List<String> mLiveDataOutput = new ArrayList<>();
@@ -62,7 +61,6 @@
     private final ReplayProcessor<String> mOutputProcessor = ReplayProcessor.create();
 
     private static final TestScheduler sBackgroundScheduler = new TestScheduler();
-    private Thread mTestThread;
 
     @Before
     public void init() {
@@ -77,31 +75,6 @@
                 return mRegistry;
             }
         };
-        mTestThread = Thread.currentThread();
-        ArchTaskExecutor.getInstance().setDelegate(new TaskExecutor() {
-
-            @Override
-            public void executeOnDiskIO(Runnable runnable) {
-                throw new IllegalStateException();
-            }
-
-            @Override
-            public void postToMainThread(Runnable runnable) {
-                // Wrong implementation, but it is fine for test
-                runnable.run();
-            }
-
-            @Override
-            public boolean isMainThread() {
-                return Thread.currentThread() == mTestThread;
-            }
-
-        });
-    }
-
-    @After
-    public void removeExecutorDelegate() {
-        ArchTaskExecutor.getInstance().setDelegate(null);
     }
 
     @Test
diff --git a/media/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaBrowserCompatTest.java b/media/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaBrowserCompatTest.java
index 227afad..ba89f99 100644
--- a/media/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaBrowserCompatTest.java
+++ b/media/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaBrowserCompatTest.java
@@ -68,6 +68,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.support.mediacompat.testlib.util.PollingCheck;
+import android.support.test.filters.FlakyTest;
 import android.support.test.filters.MediumTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -537,6 +538,7 @@
 
     @Test
     @MediumTest
+    @FlakyTest(bugId = 74093976)
     public void testUnsubscribeWithSubscriptionCallbackForMultipleSubscriptions() throws Exception {
         connectMediaBrowserService();
         final List<StubSubscriptionCallback> subscriptionCallbacks = new ArrayList<>();
diff --git a/media/version-compat-tests/previous/client/build.gradle b/media/version-compat-tests/previous/client/build.gradle
index 8b0866e..06e446f 100644
--- a/media/version-compat-tests/previous/client/build.gradle
+++ b/media/version-compat-tests/previous/client/build.gradle
@@ -22,7 +22,7 @@
 
 dependencies {
     androidTestImplementation project(':support-media-compat-test-lib')
-    androidTestImplementation "com.android.support:support-media-compat:27.0.1"
+    androidTestImplementation "com.android.support:support-media-compat:27.1.0"
 
     androidTestImplementation(TEST_RUNNER_TMP, libs.exclude_for_espresso)
 }
diff --git a/media/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/MediaBrowserCompatTest.java b/media/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/MediaBrowserCompatTest.java
index d65b2bc..891769a 100644
--- a/media/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/MediaBrowserCompatTest.java
+++ b/media/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/MediaBrowserCompatTest.java
@@ -64,6 +64,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.support.mediacompat.testlib.util.PollingCheck;
+import android.support.test.filters.FlakyTest;
 import android.support.test.filters.MediumTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -489,6 +490,7 @@
 
     @Test
     @MediumTest
+    @FlakyTest(bugId = 74093976)
     public void testUnsubscribeWithSubscriptionCallbackForMultipleSubscriptions() throws Exception {
         connectMediaBrowserService();
         final List<StubSubscriptionCallback> subscriptionCallbacks = new ArrayList<>();
diff --git a/media/version-compat-tests/previous/service/build.gradle b/media/version-compat-tests/previous/service/build.gradle
index 3e1d9b9..5ac5270 100644
--- a/media/version-compat-tests/previous/service/build.gradle
+++ b/media/version-compat-tests/previous/service/build.gradle
@@ -22,7 +22,7 @@
 
 dependencies {
     androidTestImplementation(project(":support-media-compat-test-lib"))
-    androidTestImplementation "com.android.support:support-media-compat:27.0.1"
+    androidTestImplementation "com.android.support:support-media-compat:27.1.0"
 
     androidTestImplementation(TEST_RUNNER_TMP, libs.exclude_for_espresso)
 }
diff --git a/palette/ktx/OWNERS b/palette/ktx/OWNERS
new file mode 100644
index 0000000..e450f4c
--- /dev/null
+++ b/palette/ktx/OWNERS
@@ -0,0 +1 @@
+jakew@google.com
diff --git a/palette/ktx/build.gradle b/palette/ktx/build.gradle
new file mode 100644
index 0000000..e5d5d43
--- /dev/null
+++ b/palette/ktx/build.gradle
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 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.
+ */
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+    id("org.jetbrains.kotlin.android")
+}
+
+android {
+    buildTypes {
+        debug {
+            testCoverageEnabled = false // Breaks Kotlin compiler.
+        }
+    }
+}
+
+dependencies {
+    api(project(":palette"))
+    api(KOTLIN_STDLIB)
+    androidTestImplementation(JUNIT)
+    androidTestImplementation(TEST_RUNNER_TMP, libs.exclude_for_espresso)
+}
+
+supportLibrary {
+    name = "Palette Kotlin Extensions"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.PALETTE
+    inceptionYear = "2018"
+    description = "Kotlin extensions for 'palette' artifact"
+}
diff --git a/palette/ktx/src/androidTest/java/androidx/palette/graphics/PaletteTest.kt b/palette/ktx/src/androidTest/java/androidx/palette/graphics/PaletteTest.kt
new file mode 100644
index 0000000..c108493
--- /dev/null
+++ b/palette/ktx/src/androidTest/java/androidx/palette/graphics/PaletteTest.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018 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 androidx.palette.graphics
+
+import android.graphics.Bitmap
+import android.graphics.Bitmap.Config.ARGB_8888
+import android.graphics.Canvas
+import android.graphics.Color.RED
+import androidx.palette.graphics.Target.VIBRANT
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertSame
+import org.junit.Test
+
+class PaletteTest {
+    @Test fun bitmapBuild() {
+        val bitmap = Bitmap.createBitmap(10, 10, ARGB_8888)
+        // There's no easy way to test that the palette was created from our Bitmap.
+        assertNotNull(bitmap.buildPalette())
+    }
+
+    @Test fun operatorGet() {
+        val bitmap = Bitmap.createBitmap(10, 10, ARGB_8888).apply {
+            Canvas(this).drawColor(RED)
+        }
+        val palette = Palette.from(bitmap).generate()
+        assertSame(palette.getSwatchForTarget(VIBRANT), palette[VIBRANT])
+    }
+}
diff --git a/palette/ktx/src/main/AndroidManifest.xml b/palette/ktx/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..f25fda5
--- /dev/null
+++ b/palette/ktx/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 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.
+  -->
+<manifest package="androidx.palette.ktx"/>
diff --git a/palette/ktx/src/main/java/androidx/palette/graphics/Palette.kt b/palette/ktx/src/main/java/androidx/palette/graphics/Palette.kt
new file mode 100644
index 0000000..58da09a
--- /dev/null
+++ b/palette/ktx/src/main/java/androidx/palette/graphics/Palette.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2018 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.palette.graphics
+
+import android.graphics.Bitmap
+
+/**
+ * Create a [Palette.Builder] from this bitmap.
+ *
+ * @see Palette.from
+ */
+inline fun Bitmap.buildPalette() = Palette.Builder(this)
+
+/**
+ * Returns the selected swatch for the given target from the palette, or `null` if one
+ * could not be found.
+ *
+ * @see Palette.getSwatchForTarget
+ */
+inline operator fun Palette.get(target: Target): Palette.Swatch? = getSwatchForTarget(target)
diff --git a/persistence/db/ktx/OWNERS b/persistence/db/ktx/OWNERS
new file mode 100644
index 0000000..e450f4c
--- /dev/null
+++ b/persistence/db/ktx/OWNERS
@@ -0,0 +1 @@
+jakew@google.com
diff --git a/persistence/db/ktx/build.gradle b/persistence/db/ktx/build.gradle
new file mode 100644
index 0000000..676445b
--- /dev/null
+++ b/persistence/db/ktx/build.gradle
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+    id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+    api(project(":sqlite:sqlite"))
+    api(KOTLIN_STDLIB)
+
+    testImplementation(JUNIT)
+    testImplementation(MOCKITO_CORE)
+}
+
+supportLibrary {
+    name = "Android DB KTX"
+    publish = true
+    mavenVersion = LibraryVersions.ROOM
+    mavenGroup = LibraryGroups.PERSISTENCE
+    inceptionYear = "2018"
+    description = "Kotlin extensions for DB"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
+}
diff --git a/persistence/db/ktx/src/main/AndroidManifest.xml b/persistence/db/ktx/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..f4d66ba
--- /dev/null
+++ b/persistence/db/ktx/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<!--
+  ~ Copyright (C) 2018 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.
+  -->
+
+<manifest package="androidx.sqlite.db.ktx"/>
diff --git a/persistence/db/ktx/src/main/java/androidx/sqlite/db/SupportSQLiteDatabase.kt b/persistence/db/ktx/src/main/java/androidx/sqlite/db/SupportSQLiteDatabase.kt
new file mode 100644
index 0000000..ba7b338
--- /dev/null
+++ b/persistence/db/ktx/src/main/java/androidx/sqlite/db/SupportSQLiteDatabase.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 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 androidx.sqlite.db
+
+/**
+ * Run [body] in a transaction marking it as successful if it completes without exception.
+ *
+ * @param exclusive Run in `EXCLUSIVE` mode when true, `IMMEDIATE` mode otherwise.
+ */
+inline fun <T> SupportSQLiteDatabase.transaction(
+    exclusive: Boolean = true,
+    body: SupportSQLiteDatabase.() -> T
+): T {
+    if (exclusive) {
+        beginTransaction()
+    } else {
+        beginTransactionNonExclusive()
+    }
+    try {
+        val result = body()
+        setTransactionSuccessful()
+        return result
+    } finally {
+        endTransaction()
+    }
+}
diff --git a/persistence/db/ktx/src/test/java/androidx/sqlite/db/SupportSQLiteDatabaseTest.kt b/persistence/db/ktx/src/test/java/androidx/sqlite/db/SupportSQLiteDatabaseTest.kt
new file mode 100644
index 0000000..76698d3
--- /dev/null
+++ b/persistence/db/ktx/src/test/java/androidx/sqlite/db/SupportSQLiteDatabaseTest.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 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 androidx.sqlite.db
+
+import org.junit.Assert.fail
+import org.junit.Test
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+class SupportSQLiteDatabaseTest {
+    @Test fun exclusiveDefault() {
+        val db = mock(SupportSQLiteDatabase::class.java)
+        db.transaction {}
+        verify(db).beginTransaction()
+    }
+
+    @Test fun exclusiveFalse() {
+        val db = mock(SupportSQLiteDatabase::class.java)
+        db.transaction(exclusive = false) {}
+        verify(db).beginTransactionNonExclusive()
+    }
+
+    @Test fun exclusiveTrue() {
+        val db = mock(SupportSQLiteDatabase::class.java)
+        db.transaction(exclusive = true) {}
+        verify(db).beginTransaction()
+    }
+
+    @Test fun bodyNormalCallsSuccessAndEnd() {
+        val db = mock(SupportSQLiteDatabase::class.java)
+        db.transaction {}
+        verify(db).setTransactionSuccessful()
+        verify(db).endTransaction()
+    }
+
+    @Suppress("UNREACHABLE_CODE") // A programming error might not invoke the lambda.
+    @Test fun bodyThrowsDoesNotCallSuccess() {
+        val db = mock(SupportSQLiteDatabase::class.java)
+        try {
+            db.transaction {
+                throw IllegalStateException()
+            }
+            fail()
+        } catch (e: IllegalStateException) {
+        }
+        verify(db, times(0)).setTransactionSuccessful()
+        verify(db).endTransaction()
+    }
+}
diff --git a/settings.gradle b/settings.gradle
index 61676b0..65ef3f4 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -40,9 +40,11 @@
 includeProject(":car", "car")
 includeProject(":cardview", "cardview")
 includeProject(":collection", "collection")
+includeProject(":collection-ktx", "collection/ktx")
 includeProject(":contentpaging", "content")
 includeProject(":coordinatorlayout", "coordinatorlayout")
 includeProject(":core", "compat")
+includeProject(":core-ktx", "core/ktx")
 includeProject(":cursoradapter", "cursoradapter")
 includeProject(":customview", "customview")
 includeProject(":documentfile", "documentfile")
@@ -68,6 +70,7 @@
 includeProject(":media", "media")
 includeProject(":mediarouter", "mediarouter")
 includeProject(":palette", "palette")
+includeProject(":palette-ktx", "palette/ktx")
 includeProject(":percentlayout", "percent")
 includeProject(":preference", "preference")
 includeProject(":print", "print")
@@ -78,6 +81,7 @@
 includeProject(":slices-view", "slices/view")
 includeProject(":slices-builders", "slices/builders")
 includeProject(":slidingpanelayout", "slidingpanelayout")
+includeProject(":fragment-ktx", "fragment/ktx")
 includeProject(":swiperefreshlayout", "swiperefreshlayout")
 includeProject(":textclassifier", "textclassifier")
 includeProject(":transition", "transition")
@@ -136,6 +140,7 @@
 /////////////////////////////
 
 includeProject(":internal-testutils", "testutils")
+includeProject(":internal-testutils-ktx", "testutils-ktx")
 
 /////////////////////////////
 //
diff --git a/slices/view/src/main/java/androidx/slice/SliceManagerWrapper.java b/slices/view/src/main/java/androidx/slice/SliceManagerWrapper.java
index 040baf6..f322a19 100644
--- a/slices/view/src/main/java/androidx/slice/SliceManagerWrapper.java
+++ b/slices/view/src/main/java/androidx/slice/SliceManagerWrapper.java
@@ -19,7 +19,6 @@
 import static androidx.slice.SliceConvert.unwrap;
 import static androidx.slice.widget.SliceLiveData.SUPPORTED_SPECS;
 
-import android.app.slice.SliceManager;
 import android.app.slice.SliceSpec;
 import android.content.Context;
 import android.content.Intent;
@@ -43,12 +42,6 @@
 
     private final android.app.slice.SliceManager mManager;
     private final List<SliceSpec> mSpecs;
-    private final SliceManager.SliceCallback mCallback = new SliceManager.SliceCallback() {
-        @Override
-        public void onSliceUpdated(@NonNull android.app.slice.Slice s) {
-
-        }
-    };
 
     SliceManagerWrapper(Context context) {
         this(context, context.getSystemService(android.app.slice.SliceManager.class));
@@ -62,12 +55,12 @@
 
     @Override
     public void pinSlice(@NonNull Uri uri) {
-        mManager.registerSliceCallback(uri, mSpecs, mCallback);
+        mManager.pinSlice(uri, mSpecs);
     }
 
     @Override
     public void unpinSlice(@NonNull Uri uri) {
-        mManager.unregisterSliceCallback(uri, mCallback);
+        mManager.unpinSlice(uri);
     }
 
     @Override
@@ -92,8 +85,6 @@
     @Nullable
     @Override
     public Uri mapIntentToUri(@NonNull Intent intent) {
-        // TODO: Switch over to mapIntentToUri once it lands in prebuilt.
-        Slice slice = bindSlice(intent);
-        return slice != null ? slice.getUri() : null;
+        return mManager.mapIntentToUri(intent);
     }
 }
diff --git a/slices/view/src/main/java/androidx/slice/widget/SliceLiveData.java b/slices/view/src/main/java/androidx/slice/widget/SliceLiveData.java
index 2ffc02c..8639893 100644
--- a/slices/view/src/main/java/androidx/slice/widget/SliceLiveData.java
+++ b/slices/view/src/main/java/androidx/slice/widget/SliceLiveData.java
@@ -63,8 +63,7 @@
 
     /**
      * Produces an {@link LiveData} that tracks a Slice for a given Uri. To use
-     * this method your app must have the permission to the slice Uri or hold
-     * {@link android.Manifest.permission#BIND_SLICE}).
+     * this method your app must have the permission to the slice Uri.
      */
     public static LiveData<Slice> fromUri(Context context, Uri uri) {
         return new SliceLiveDataImpl(context.getApplicationContext(), uri);
@@ -72,8 +71,7 @@
 
     /**
      * Produces an {@link LiveData} that tracks a Slice for a given Intent. To use
-     * this method your app must have the permission to the slice Uri or hold
-     * {@link android.Manifest.permission#BIND_SLICE}).
+     * this method your app must have the permission to the slice Uri.
      */
     public static LiveData<Slice> fromIntent(@NonNull Context context, @NonNull Intent intent) {
         return new SliceLiveDataImpl(context.getApplicationContext(), intent);
diff --git a/slices/view/src/main/res/values-af/strings.xml b/slices/view/src/main/res/values-af/strings.xml
index ea5ab25..812f811 100644
--- a/slices/view/src/main/res/values-af/strings.xml
+++ b/slices/view/src/main/res/values-af/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Meer"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Wys meer"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-am/strings.xml b/slices/view/src/main/res/values-am/strings.xml
index ea5ab25..86c2c4e 100644
--- a/slices/view/src/main/res/values-am/strings.xml
+++ b/slices/view/src/main/res/values-am/strings.xml
@@ -18,4 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"ተጨማሪ"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"ተጨማሪ አሳይ"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-ar/strings.xml b/slices/view/src/main/res/values-ar/strings.xml
index 21aa8a4..3acde5d 100644
--- a/slices/view/src/main/res/values-ar/strings.xml
+++ b/slices/view/src/main/res/values-ar/strings.xml
@@ -18,4 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"بالإضافة إلى <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"المزيد"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"عرض المزيد"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-az/strings.xml b/slices/view/src/main/res/values-az/strings.xml
index ea5ab25..8ff3908 100644
--- a/slices/view/src/main/res/values-az/strings.xml
+++ b/slices/view/src/main/res/values-az/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Digər"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Digərinə baxın"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-b+sr+Latn/strings.xml b/slices/view/src/main/res/values-b+sr+Latn/strings.xml
index ffd9b9b..22e42e7 100644
--- a/slices/view/src/main/res/values-b+sr+Latn/strings.xml
+++ b/slices/view/src/main/res/values-b+sr+Latn/strings.xml
@@ -18,4 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"i još <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Još"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Prikaži više"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-be/strings.xml b/slices/view/src/main/res/values-be/strings.xml
index df8e965..6ea856b 100644
--- a/slices/view/src/main/res/values-be/strings.xml
+++ b/slices/view/src/main/res/values-be/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"Яшчэ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Яшчэ"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Яшчэ"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-bg/strings.xml b/slices/view/src/main/res/values-bg/strings.xml
index ea5ab25..882def9 100644
--- a/slices/view/src/main/res/values-bg/strings.xml
+++ b/slices/view/src/main/res/values-bg/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Още"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Показване на още"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-bn/strings.xml b/slices/view/src/main/res/values-bn/strings.xml
index 8737d8c..eb83395 100644
--- a/slices/view/src/main/res/values-bn/strings.xml
+++ b/slices/view/src/main/res/values-bn/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>টি"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"আরও"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"আরও দেখুন"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-bs/strings.xml b/slices/view/src/main/res/values-bs/strings.xml
index ea5ab25..693f885 100644
--- a/slices/view/src/main/res/values-bs/strings.xml
+++ b/slices/view/src/main/res/values-bs/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Više"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Prikaži više"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ca/strings.xml b/slices/view/src/main/res/values-ca/strings.xml
index 8ae6f78..4ac9c6d 100644
--- a/slices/view/src/main/res/values-ca/strings.xml
+++ b/slices/view/src/main/res/values-ca/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> més"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Més"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Mostra\'n més"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-cs/strings.xml b/slices/view/src/main/res/values-cs/strings.xml
index 1d39c0f..278810c 100644
--- a/slices/view/src/main/res/values-cs/strings.xml
+++ b/slices/view/src/main/res/values-cs/strings.xml
@@ -18,4 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"a ještě <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Více"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Zobrazit více"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-da/strings.xml b/slices/view/src/main/res/values-da/strings.xml
index 40de41d..806a5fe 100644
--- a/slices/view/src/main/res/values-da/strings.xml
+++ b/slices/view/src/main/res/values-da/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> mere"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Mere"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Se mere"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-de/strings.xml b/slices/view/src/main/res/values-de/strings.xml
index 9d9bede..f6a1e32 100644
--- a/slices/view/src/main/res/values-de/strings.xml
+++ b/slices/view/src/main/res/values-de/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Mehr"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Mehr anzeigen"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-el/strings.xml b/slices/view/src/main/res/values-el/strings.xml
index ea5ab25..19963f2 100644
--- a/slices/view/src/main/res/values-el/strings.xml
+++ b/slices/view/src/main/res/values-el/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Περισσότ."</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Εμφάνιση περισσότερων"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-en-rAU/strings.xml b/slices/view/src/main/res/values-en-rAU/strings.xml
index ea5ab25..f222ba5 100644
--- a/slices/view/src/main/res/values-en-rAU/strings.xml
+++ b/slices/view/src/main/res/values-en-rAU/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"More"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Show more"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-en-rCA/strings.xml b/slices/view/src/main/res/values-en-rCA/strings.xml
index ea5ab25..f222ba5 100644
--- a/slices/view/src/main/res/values-en-rCA/strings.xml
+++ b/slices/view/src/main/res/values-en-rCA/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"More"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Show more"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-en-rGB/strings.xml b/slices/view/src/main/res/values-en-rGB/strings.xml
index ea5ab25..f222ba5 100644
--- a/slices/view/src/main/res/values-en-rGB/strings.xml
+++ b/slices/view/src/main/res/values-en-rGB/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"More"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Show more"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-en-rIN/strings.xml b/slices/view/src/main/res/values-en-rIN/strings.xml
index ea5ab25..f222ba5 100644
--- a/slices/view/src/main/res/values-en-rIN/strings.xml
+++ b/slices/view/src/main/res/values-en-rIN/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"More"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Show more"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-en-rXC/strings.xml b/slices/view/src/main/res/values-en-rXC/strings.xml
index b793412..243dccb 100644
--- a/slices/view/src/main/res/values-en-rXC/strings.xml
+++ b/slices/view/src/main/res/values-en-rXC/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‏‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎+ ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%1$d</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‎‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎More‎‏‎‎‏‎"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎Show more‎‏‎‎‏‎"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-es-rUS/strings.xml b/slices/view/src/main/res/values-es-rUS/strings.xml
index a445505..7fc5b56 100644
--- a/slices/view/src/main/res/values-es-rUS/strings.xml
+++ b/slices/view/src/main/res/values-es-rUS/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> más"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Más"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Mostrar más"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-es/strings.xml b/slices/view/src/main/res/values-es/strings.xml
index dcdd33e..b81e23c 100644
--- a/slices/view/src/main/res/values-es/strings.xml
+++ b/slices/view/src/main/res/values-es/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> más"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Más"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Ver más"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-et/strings.xml b/slices/view/src/main/res/values-et/strings.xml
index a1675ff..80bec54 100644
--- a/slices/view/src/main/res/values-et/strings.xml
+++ b/slices/view/src/main/res/values-et/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"ja veel <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Rohkem"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Kuva rohkem"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-eu/strings.xml b/slices/view/src/main/res/values-eu/strings.xml
index 1c79d4a..295f184 100644
--- a/slices/view/src/main/res/values-eu/strings.xml
+++ b/slices/view/src/main/res/values-eu/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"Beste <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Gehiago"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Erakutsi gehiago"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-fa/strings.xml b/slices/view/src/main/res/values-fa/strings.xml
index 2b2abd2..3ef8f85 100644
--- a/slices/view/src/main/res/values-fa/strings.xml
+++ b/slices/view/src/main/res/values-fa/strings.xml
@@ -18,4 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"‎+ <xliff:g id="NUMBER">%1$d</xliff:g>‎"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"بیشتر"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"نمایش موارد بیشتر"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-fi/strings.xml b/slices/view/src/main/res/values-fi/strings.xml
index ea5ab25..0e37b9d 100644
--- a/slices/view/src/main/res/values-fi/strings.xml
+++ b/slices/view/src/main/res/values-fi/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Lisää"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Näytä lisää"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-fr-rCA/strings.xml b/slices/view/src/main/res/values-fr-rCA/strings.xml
index ea5ab25..cc10117 100644
--- a/slices/view/src/main/res/values-fr-rCA/strings.xml
+++ b/slices/view/src/main/res/values-fr-rCA/strings.xml
@@ -17,5 +17,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Plus"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Plus"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-fr/strings.xml b/slices/view/src/main/res/values-fr/strings.xml
index 73685ce..b4f147b 100644
--- a/slices/view/src/main/res/values-fr/strings.xml
+++ b/slices/view/src/main/res/values-fr/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> autres"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Plus"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Afficher plus"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-gl/strings.xml b/slices/view/src/main/res/values-gl/strings.xml
index 573eae9..f8686de 100644
--- a/slices/view/src/main/res/values-gl/strings.xml
+++ b/slices/view/src/main/res/values-gl/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> máis"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Máis"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Amosar máis"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-gu/strings.xml b/slices/view/src/main/res/values-gu/strings.xml
index ea5ab25..4cf8b47 100644
--- a/slices/view/src/main/res/values-gu/strings.xml
+++ b/slices/view/src/main/res/values-gu/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"વધુ"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"વધુ બતાવો"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-hi/strings.xml b/slices/view/src/main/res/values-hi/strings.xml
index ea5ab25..3688497 100644
--- a/slices/view/src/main/res/values-hi/strings.xml
+++ b/slices/view/src/main/res/values-hi/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"ज़्यादा देखें"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"ज़्यादा देखें"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-hr/strings.xml b/slices/view/src/main/res/values-hr/strings.xml
index 7ecedf6..5ec52b8 100644
--- a/slices/view/src/main/res/values-hr/strings.xml
+++ b/slices/view/src/main/res/values-hr/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"još <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Više"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Prikaži više"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-hu/strings.xml b/slices/view/src/main/res/values-hu/strings.xml
index ea5ab25..957dd68 100644
--- a/slices/view/src/main/res/values-hu/strings.xml
+++ b/slices/view/src/main/res/values-hu/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Több"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Több megjelenítése"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-hy/strings.xml b/slices/view/src/main/res/values-hy/strings.xml
index ea5ab25..49e731b 100644
--- a/slices/view/src/main/res/values-hy/strings.xml
+++ b/slices/view/src/main/res/values-hy/strings.xml
@@ -18,4 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Ավելին"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Ցուցադրել ավելի շատ"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-in/strings.xml b/slices/view/src/main/res/values-in/strings.xml
index ea5ab25..7d46931 100644
--- a/slices/view/src/main/res/values-in/strings.xml
+++ b/slices/view/src/main/res/values-in/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Lainnya"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Tampilkan lainnya"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-is/strings.xml b/slices/view/src/main/res/values-is/strings.xml
index ea5ab25..231dd20 100644
--- a/slices/view/src/main/res/values-is/strings.xml
+++ b/slices/view/src/main/res/values-is/strings.xml
@@ -18,4 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Meira"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Sýna meira"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-it/strings.xml b/slices/view/src/main/res/values-it/strings.xml
index ea5ab25..8f0a761 100644
--- a/slices/view/src/main/res/values-it/strings.xml
+++ b/slices/view/src/main/res/values-it/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Altro"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Mostra altro"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-iw/strings.xml b/slices/view/src/main/res/values-iw/strings.xml
index ea5ab25..c160611 100644
--- a/slices/view/src/main/res/values-iw/strings.xml
+++ b/slices/view/src/main/res/values-iw/strings.xml
@@ -18,4 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"עוד"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"הצג יותר"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-ja/strings.xml b/slices/view/src/main/res/values-ja/strings.xml
index ed51803..a18751f 100644
--- a/slices/view/src/main/res/values-ja/strings.xml
+++ b/slices/view/src/main/res/values-ja/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"他 <xliff:g id="NUMBER">%1$d</xliff:g> 件"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"もっと見る"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"もっと見る"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ka/strings.xml b/slices/view/src/main/res/values-ka/strings.xml
index ea5ab25..8701f5d 100644
--- a/slices/view/src/main/res/values-ka/strings.xml
+++ b/slices/view/src/main/res/values-ka/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"მეტი"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"მეტის ჩვენება"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-kk/strings.xml b/slices/view/src/main/res/values-kk/strings.xml
index ea5ab25..1867ada 100644
--- a/slices/view/src/main/res/values-kk/strings.xml
+++ b/slices/view/src/main/res/values-kk/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Тағы"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Толығырақ көрсету"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-km/strings.xml b/slices/view/src/main/res/values-km/strings.xml
index ea5ab25..3f50a99 100644
--- a/slices/view/src/main/res/values-km/strings.xml
+++ b/slices/view/src/main/res/values-km/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"ច្រើន​ទៀត"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"បង្ហាញ​ច្រើនទៀត"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-kn/strings.xml b/slices/view/src/main/res/values-kn/strings.xml
index ea5ab25..e8224f3 100644
--- a/slices/view/src/main/res/values-kn/strings.xml
+++ b/slices/view/src/main/res/values-kn/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"ಇನ್ನಷ್ಟು"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"ಹೆಚ್ಚು ತೋರಿಸಿ"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ko/strings.xml b/slices/view/src/main/res/values-ko/strings.xml
index 2dc0279..8e7cb24 100644
--- a/slices/view/src/main/res/values-ko/strings.xml
+++ b/slices/view/src/main/res/values-ko/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g>개 더보기"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"더보기"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"더보기"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ky/strings.xml b/slices/view/src/main/res/values-ky/strings.xml
index ea5ab25..910ae6d 100644
--- a/slices/view/src/main/res/values-ky/strings.xml
+++ b/slices/view/src/main/res/values-ky/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Дагы"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Дагы көрсөтүү"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-lo/strings.xml b/slices/view/src/main/res/values-lo/strings.xml
index ea5ab25..d266a43 100644
--- a/slices/view/src/main/res/values-lo/strings.xml
+++ b/slices/view/src/main/res/values-lo/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"ເພີ່ມເຕີມ"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"ສະແດງເພີ່ມເຕີມ"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-lt/strings.xml b/slices/view/src/main/res/values-lt/strings.xml
index bb6bcb3..cc4b804 100644
--- a/slices/view/src/main/res/values-lt/strings.xml
+++ b/slices/view/src/main/res/values-lt/strings.xml
@@ -18,4 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"Dar <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Daugiau"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Rodyti daugiau"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-lv/strings.xml b/slices/view/src/main/res/values-lv/strings.xml
index 79ccb99..042436d 100644
--- a/slices/view/src/main/res/values-lv/strings.xml
+++ b/slices/view/src/main/res/values-lv/strings.xml
@@ -18,4 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"Vēl <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Vēl"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Rādīt vairāk"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-mk/strings.xml b/slices/view/src/main/res/values-mk/strings.xml
index ea5ab25..b3c5da4 100644
--- a/slices/view/src/main/res/values-mk/strings.xml
+++ b/slices/view/src/main/res/values-mk/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Повеќе"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Прикажи повеќе"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ml/strings.xml b/slices/view/src/main/res/values-ml/strings.xml
index ea5ab25..e2dc0b1 100644
--- a/slices/view/src/main/res/values-ml/strings.xml
+++ b/slices/view/src/main/res/values-ml/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"കൂടുതൽ"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"കൂടുതൽ കാണിക്കുക"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-mn/strings.xml b/slices/view/src/main/res/values-mn/strings.xml
index ea5ab25..740f455 100644
--- a/slices/view/src/main/res/values-mn/strings.xml
+++ b/slices/view/src/main/res/values-mn/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Бусад"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Дэлгэрэнгүй үзэх"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-mr/strings.xml b/slices/view/src/main/res/values-mr/strings.xml
index ea5ab25..ab06bea 100644
--- a/slices/view/src/main/res/values-mr/strings.xml
+++ b/slices/view/src/main/res/values-mr/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"आणखी"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"आणखी दाखवा"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ms/strings.xml b/slices/view/src/main/res/values-ms/strings.xml
index ea5ab25..03bda10 100644
--- a/slices/view/src/main/res/values-ms/strings.xml
+++ b/slices/view/src/main/res/values-ms/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Lagi"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Tunjukkan lagi"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-my/strings.xml b/slices/view/src/main/res/values-my/strings.xml
index ea5ab25..754d40e 100644
--- a/slices/view/src/main/res/values-my/strings.xml
+++ b/slices/view/src/main/res/values-my/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"နောက်ထပ်"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"နောက်ထပ် ပြပါ"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-nb/strings.xml b/slices/view/src/main/res/values-nb/strings.xml
index ea5ab25..e977965 100644
--- a/slices/view/src/main/res/values-nb/strings.xml
+++ b/slices/view/src/main/res/values-nb/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Mer"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Vis mer"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ne/strings.xml b/slices/view/src/main/res/values-ne/strings.xml
index ea5ab25..6a95860 100644
--- a/slices/view/src/main/res/values-ne/strings.xml
+++ b/slices/view/src/main/res/values-ne/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"थप"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"थप देखाउनुहोस्"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-nl/strings.xml b/slices/view/src/main/res/values-nl/strings.xml
index ea5ab25..ed28ef2 100644
--- a/slices/view/src/main/res/values-nl/strings.xml
+++ b/slices/view/src/main/res/values-nl/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Meer"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Meer weergeven"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-pa/strings.xml b/slices/view/src/main/res/values-pa/strings.xml
index ea5ab25..cd6db9b 100644
--- a/slices/view/src/main/res/values-pa/strings.xml
+++ b/slices/view/src/main/res/values-pa/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"ਹੋਰ"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"ਹੋਰ ਦਿਖਾਓ"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-pl/strings.xml b/slices/view/src/main/res/values-pl/strings.xml
index 9d9bede..5fe2d2b 100644
--- a/slices/view/src/main/res/values-pl/strings.xml
+++ b/slices/view/src/main/res/values-pl/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Więcej"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Pokaż więcej"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-pt-rBR/strings.xml b/slices/view/src/main/res/values-pt-rBR/strings.xml
index 629ba48..a163c4a 100644
--- a/slices/view/src/main/res/values-pt-rBR/strings.xml
+++ b/slices/view/src/main/res/values-pt-rBR/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"Mais <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Mais"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Mostrar mais"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-pt-rPT/strings.xml b/slices/view/src/main/res/values-pt-rPT/strings.xml
index ea5ab25..7d4c127 100644
--- a/slices/view/src/main/res/values-pt-rPT/strings.xml
+++ b/slices/view/src/main/res/values-pt-rPT/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Mais"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Mostrar mais"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-pt/strings.xml b/slices/view/src/main/res/values-pt/strings.xml
index 629ba48..a163c4a 100644
--- a/slices/view/src/main/res/values-pt/strings.xml
+++ b/slices/view/src/main/res/values-pt/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"Mais <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Mais"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Mostrar mais"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ro/strings.xml b/slices/view/src/main/res/values-ro/strings.xml
index ea5ab25..ed61fde 100644
--- a/slices/view/src/main/res/values-ro/strings.xml
+++ b/slices/view/src/main/res/values-ro/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Mai mult"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Vedeți mai multe"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ru/strings.xml b/slices/view/src/main/res/values-ru/strings.xml
index 9d9bede..e3e95f7 100644
--- a/slices/view/src/main/res/values-ru/strings.xml
+++ b/slices/view/src/main/res/values-ru/strings.xml
@@ -18,4 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Ещё"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Ещё"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-si/strings.xml b/slices/view/src/main/res/values-si/strings.xml
index ea5ab25..58feb78 100644
--- a/slices/view/src/main/res/values-si/strings.xml
+++ b/slices/view/src/main/res/values-si/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"තව"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"තව පෙන්වන්න"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-sk/strings.xml b/slices/view/src/main/res/values-sk/strings.xml
index ea5ab25..fe77506 100644
--- a/slices/view/src/main/res/values-sk/strings.xml
+++ b/slices/view/src/main/res/values-sk/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Viac"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Zobraziť viac"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-sl/strings.xml b/slices/view/src/main/res/values-sl/strings.xml
index 59bf101..802caf1 100644
--- a/slices/view/src/main/res/values-sl/strings.xml
+++ b/slices/view/src/main/res/values-sl/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"in še <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Več"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Pokaži več"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-sq/strings.xml b/slices/view/src/main/res/values-sq/strings.xml
index ea5ab25..e1cdae8 100644
--- a/slices/view/src/main/res/values-sq/strings.xml
+++ b/slices/view/src/main/res/values-sq/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Më shumë"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Shfaq më shumë"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-sr/strings.xml b/slices/view/src/main/res/values-sr/strings.xml
index a66220a..627ede6 100644
--- a/slices/view/src/main/res/values-sr/strings.xml
+++ b/slices/view/src/main/res/values-sr/strings.xml
@@ -18,4 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"и још <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Још"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Прикажи више"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-sv/strings.xml b/slices/view/src/main/res/values-sv/strings.xml
index cbcec4f..f8ed0c7 100644
--- a/slices/view/src/main/res/values-sv/strings.xml
+++ b/slices/view/src/main/res/values-sv/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> till"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Mer"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Visa mer"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-sw/strings.xml b/slices/view/src/main/res/values-sw/strings.xml
index ea5ab25..b23ed5e 100644
--- a/slices/view/src/main/res/values-sw/strings.xml
+++ b/slices/view/src/main/res/values-sw/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Mengine"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Onyesha mengine"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ta/strings.xml b/slices/view/src/main/res/values-ta/strings.xml
index ea5ab25..9f2be0e 100644
--- a/slices/view/src/main/res/values-ta/strings.xml
+++ b/slices/view/src/main/res/values-ta/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"மேலும்"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"மேலும் காட்டு"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-te/strings.xml b/slices/view/src/main/res/values-te/strings.xml
index ea5ab25..0eb1da7 100644
--- a/slices/view/src/main/res/values-te/strings.xml
+++ b/slices/view/src/main/res/values-te/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"మరింత"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"మరింత చూపు"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-th/strings.xml b/slices/view/src/main/res/values-th/strings.xml
index ea5ab25..4cdd991 100644
--- a/slices/view/src/main/res/values-th/strings.xml
+++ b/slices/view/src/main/res/values-th/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"เพิ่มเติม"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"แสดงเพิ่ม"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-tl/strings.xml b/slices/view/src/main/res/values-tl/strings.xml
index ea5ab25..05917b0 100644
--- a/slices/view/src/main/res/values-tl/strings.xml
+++ b/slices/view/src/main/res/values-tl/strings.xml
@@ -18,4 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Higit pa"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Magpakita pa"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-tr/strings.xml b/slices/view/src/main/res/values-tr/strings.xml
index ea5ab25..09a589e 100644
--- a/slices/view/src/main/res/values-tr/strings.xml
+++ b/slices/view/src/main/res/values-tr/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Diğer"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Daha fazla göster"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-uk/strings.xml b/slices/view/src/main/res/values-uk/strings.xml
index ea5ab25..06c02bc 100644
--- a/slices/view/src/main/res/values-uk/strings.xml
+++ b/slices/view/src/main/res/values-uk/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Більше"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Показати більше"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ur/strings.xml b/slices/view/src/main/res/values-ur/strings.xml
index ce427c0..f12d6b3 100644
--- a/slices/view/src/main/res/values-ur/strings.xml
+++ b/slices/view/src/main/res/values-ur/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"‎‎‎‎‎+ <xliff:g id="NUMBER">%1$d</xliff:g>‎‎"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"مزید"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"مزید دکھائیں"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-uz/strings.xml b/slices/view/src/main/res/values-uz/strings.xml
index ea5ab25..cbc9979 100644
--- a/slices/view/src/main/res/values-uz/strings.xml
+++ b/slices/view/src/main/res/values-uz/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Yana"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Yana"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-vi/strings.xml b/slices/view/src/main/res/values-vi/strings.xml
index ea5ab25..3890636 100644
--- a/slices/view/src/main/res/values-vi/strings.xml
+++ b/slices/view/src/main/res/values-vi/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Thêm"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Hiển thị thêm"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-zh-rCN/strings.xml b/slices/view/src/main/res/values-zh-rCN/strings.xml
index ea5ab25..ffb63a4 100644
--- a/slices/view/src/main/res/values-zh-rCN/strings.xml
+++ b/slices/view/src/main/res/values-zh-rCN/strings.xml
@@ -18,4 +18,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"更多"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"显示更多"</string>
 </resources>
diff --git a/slices/view/src/main/res/values-zh-rHK/strings.xml b/slices/view/src/main/res/values-zh-rHK/strings.xml
index ea5ab25..565b565 100644
--- a/slices/view/src/main/res/values-zh-rHK/strings.xml
+++ b/slices/view/src/main/res/values-zh-rHK/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"更多"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"顯示更多"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-zh-rTW/strings.xml b/slices/view/src/main/res/values-zh-rTW/strings.xml
index ea5ab25..565b565 100644
--- a/slices/view/src/main/res/values-zh-rTW/strings.xml
+++ b/slices/view/src/main/res/values-zh-rTW/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"更多"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"顯示更多"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-zu/strings.xml b/slices/view/src/main/res/values-zu/strings.xml
index ea5ab25..c5ebb10 100644
--- a/slices/view/src/main/res/values-zu/strings.xml
+++ b/slices/view/src/main/res/values-zu/strings.xml
@@ -18,4 +18,10 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="abc_slice_more" msgid="1983560225998630901">"Okuningi"</string>
+    <string name="abc_slice_show_more" msgid="1567717014004692768">"Bonisa okuningi"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/testutils-ktx/NO_DOCS b/testutils-ktx/NO_DOCS
new file mode 100644
index 0000000..4dad694
--- /dev/null
+++ b/testutils-ktx/NO_DOCS
@@ -0,0 +1,17 @@
+# 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.
+
+Having this file, named NO_DOCS, in a directory will prevent
+Android javadocs from being generated for java files under
+the directory. This is especially useful for test projects.
diff --git a/testutils-ktx/OWNERS b/testutils-ktx/OWNERS
new file mode 100644
index 0000000..e450f4c
--- /dev/null
+++ b/testutils-ktx/OWNERS
@@ -0,0 +1 @@
+jakew@google.com
diff --git a/testutils-ktx/build.gradle b/testutils-ktx/build.gradle
new file mode 100644
index 0000000..5f33da1
--- /dev/null
+++ b/testutils-ktx/build.gradle
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2018 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.
+ */
+
+import static androidx.build.dependencies.DependenciesKt.*
+
+plugins {
+    id("SupportKotlinLibraryPlugin")
+}
+
+dependencies {
+    compile(KOTLIN_STDLIB)
+    compile(TRUTH)
+}
diff --git a/testutils-ktx/src/main/java/androidx/testutils/assertions.kt b/testutils-ktx/src/main/java/androidx/testutils/assertions.kt
new file mode 100644
index 0000000..b67948a
--- /dev/null
+++ b/testutils-ktx/src/main/java/androidx/testutils/assertions.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018 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 androidx.testutils
+
+import com.google.common.truth.ThrowableSubject
+import com.google.common.truth.Truth.assertThat
+
+inline fun <reified T : Throwable> assertThrows(body: () -> Unit): ThrowableSubject {
+    try {
+        body()
+    } catch (e: Throwable) {
+        if (e is T) {
+            return assertThat(e)
+        }
+        throw e
+    }
+    throw AssertionError("Body completed successfully. Expected ${T::class.java.simpleName}.")
+}
+
+fun fail(message: String? = null): Nothing = throw AssertionError(message)
diff --git a/v7/appcompat/res/values-af/strings.xml b/v7/appcompat/res/values-af/strings.xml
index 15ed3b2..b7dd9bc 100644
--- a/v7/appcompat/res/values-af/strings.xml
+++ b/v7/appcompat/res/values-af/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"AAN"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"AF"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Soek"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Kieslys+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Simbool+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Funksie+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"spasiebalk"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-am/strings.xml b/v7/appcompat/res/values-am/strings.xml
index 42bbc06..485ffad 100644
--- a/v7/appcompat/res/values-am/strings.xml
+++ b/v7/appcompat/res/values-am/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"በርቷል"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ጠፍቷል"</string>
     <string name="search_menu_title" msgid="146198913615257606">"ፈልግ"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"ምናሌ+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"ሰርዝ"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ar/strings.xml b/v7/appcompat/res/values-ar/strings.xml
index 3278162..a7683ce 100644
--- a/v7/appcompat/res/values-ar/strings.xml
+++ b/v7/appcompat/res/values-ar/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"تشغيل"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"إيقاف"</string>
     <string name="search_menu_title" msgid="146198913615257606">"البحث"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"القائمة+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-az/strings.xml b/v7/appcompat/res/values-az/strings.xml
index 29e00dd..aae3b94 100644
--- a/v7/appcompat/res/values-az/strings.xml
+++ b/v7/appcompat/res/values-az/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"AKTİV"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"DEAKTİV"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Axtarış"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menyu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Funksiya+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"kosmos"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"daxil olun"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"silin"</string>
 </resources>
diff --git a/v7/appcompat/res/values-b+sr+Latn/strings.xml b/v7/appcompat/res/values-b+sr+Latn/strings.xml
index c3462f6..734525b 100644
--- a/v7/appcompat/res/values-b+sr+Latn/strings.xml
+++ b/v7/appcompat/res/values-b+sr+Latn/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"UKLJUČI"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ISKLJUČI"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Pretraži"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"taster za razmak"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-be/strings.xml b/v7/appcompat/res/values-be/strings.xml
index 99ee19f..f04076a 100644
--- a/v7/appcompat/res/values-be/strings.xml
+++ b/v7/appcompat/res/values-be/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"УКЛ."</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ВЫКЛ."</string>
     <string name="search_menu_title" msgid="146198913615257606">"Пошук"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Меню +"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta +"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl +"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt +"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift +"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym +"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Fn +"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"Прабел"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-bg/strings.xml b/v7/appcompat/res/values-bg/strings.xml
index 1d37d0d..2c607a1 100644
--- a/v7/appcompat/res/values-bg/strings.xml
+++ b/v7/appcompat/res/values-bg/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ВКЛ."</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ИЗКЛ."</string>
     <string name="search_menu_title" msgid="146198913615257606">"Търсене"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"клавиша за интервал"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-bn/strings.xml b/v7/appcompat/res/values-bn/strings.xml
index 2ea7591..a6be993 100644
--- a/v7/appcompat/res/values-bn/strings.xml
+++ b/v7/appcompat/res/values-bn/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"চালু"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"বন্ধ"</string>
     <string name="search_menu_title" msgid="146198913615257606">"খুঁজুন"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"মেনু+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"স্পেস"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"মুছুন"</string>
 </resources>
diff --git a/v7/appcompat/res/values-bs/strings.xml b/v7/appcompat/res/values-bs/strings.xml
index 07d1411..91281fc 100644
--- a/v7/appcompat/res/values-bs/strings.xml
+++ b/v7/appcompat/res/values-bs/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"UKLJUČI"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ISKLJUČI"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Pretraži"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"razmaknica"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ca/strings.xml b/v7/appcompat/res/values-ca/strings.xml
index 03ebec3..c4f3b4d 100644
--- a/v7/appcompat/res/values-ca/strings.xml
+++ b/v7/appcompat/res/values-ca/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVAT"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"DESACTIVAT"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Cerca"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menú+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Maj+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Funció+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"Espai"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Retorn"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Supr"</string>
 </resources>
diff --git a/v7/appcompat/res/values-cs/strings.xml b/v7/appcompat/res/values-cs/strings.xml
index 05cd4e0..9111883 100644
--- a/v7/appcompat/res/values-cs/strings.xml
+++ b/v7/appcompat/res/values-cs/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ZAPNUTO"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"VYPNUTO"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Hledat"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Fn+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"mezerník"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-da/strings.xml b/v7/appcompat/res/values-da/strings.xml
index 813885a..f05e142 100644
--- a/v7/appcompat/res/values-da/strings.xml
+++ b/v7/appcompat/res/values-da/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"TIL"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"FRA"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Søg"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Fn+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"mellemrum"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-de/strings.xml b/v7/appcompat/res/values-de/strings.xml
index 0b57259..fb0dd6a 100644
--- a/v7/appcompat/res/values-de/strings.xml
+++ b/v7/appcompat/res/values-de/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"An"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"Aus"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Suchen"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menütaste +"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta-Taste +"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Strg +"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt +"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Umschalttaste +"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym-Taste +"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Funktionstaste +"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"Leertaste +"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Eingabetaste"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Löschen"</string>
 </resources>
diff --git a/v7/appcompat/res/values-el/strings.xml b/v7/appcompat/res/values-el/strings.xml
index ec7a666..b7da605 100644
--- a/v7/appcompat/res/values-el/strings.xml
+++ b/v7/appcompat/res/values-el/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ΕΝΕΡΓΟΠΟΙΗΣΗ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ΑΠΕΝΕΡΓΟΠΟΙΗΣΗ"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Αναζήτηση"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"διάστημα"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-en-rAU/strings.xml b/v7/appcompat/res/values-en-rAU/strings.xml
index a4d048c..a315670 100644
--- a/v7/appcompat/res/values-en-rAU/strings.xml
+++ b/v7/appcompat/res/values-en-rAU/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Search"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-en-rCA/strings.xml b/v7/appcompat/res/values-en-rCA/strings.xml
index a4d048c..a315670 100644
--- a/v7/appcompat/res/values-en-rCA/strings.xml
+++ b/v7/appcompat/res/values-en-rCA/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Search"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-en-rGB/strings.xml b/v7/appcompat/res/values-en-rGB/strings.xml
index a4d048c..a315670 100644
--- a/v7/appcompat/res/values-en-rGB/strings.xml
+++ b/v7/appcompat/res/values-en-rGB/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Search"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-en-rIN/strings.xml b/v7/appcompat/res/values-en-rIN/strings.xml
index a4d048c..a315670 100644
--- a/v7/appcompat/res/values-en-rIN/strings.xml
+++ b/v7/appcompat/res/values-en-rIN/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Search"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-en-rXC/strings.xml b/v7/appcompat/res/values-en-rXC/strings.xml
index b1d5f93..2e8e581 100644
--- a/v7/appcompat/res/values-en-rXC/strings.xml
+++ b/v7/appcompat/res/values-en-rXC/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‎‏‎‎‎‏‎‎‎‎‎‎‎‎‏‏‏‎‏‏‏‎‏‏‎ON‎‏‎‎‏‎"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‎‏‎‏‏‏‎‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‏‎‎‎‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‎‏‎‎‏‎OFF‎‏‎‎‏‎"</string>
     <string name="search_menu_title" msgid="146198913615257606">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‏‎‏‎‏‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎Search‎‏‎‎‏‎"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‎‎‏‏‎‏‏‎‏‎‎‏‏‎‏‎‏‏‏‎‏‎‎‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‎‎‏‏‎‎‎‏‏‎‏‎Menu+‎‏‎‎‏‎"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‎‏‏‎‏‎‎‏‎‏‏‎‏‎‎‎‎‎‏‏‎‎‎‎‎‎‏‏‎‎‏‎‏‎‎‏‏‎‎‎‎‏‏‎‏‎‏‎‏‎‏‎Meta+‎‏‎‎‏‎"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‎‏‎‏‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‎‏‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‎‎‎Ctrl+‎‏‎‎‏‎"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‏‎‎‏‎‏‎‏‎‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎Alt+‎‏‎‎‏‎"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‎‏‏‎‎‎‎‎‏‏‎‏‎‏‏‎‎‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‏‎‏‎‎‎Shift+‎‏‎‎‏‎"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‏‎‏‎‏‎‏‏‎‎‎‏‎‏‎‏‎‏‎‎‏‎‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‎‏‎‎‎‎‎‎‏‎Sym+‎‏‎‎‏‎"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‎‎‏‏‏‎‏‎‎‎‎‎‏‏‎‏‏‏‎‎‏‏‎‏‏‎‎‎‎‏‎‏‎‎‏‏‎Function+‎‏‎‎‏‎"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‏‏‏‎‎‎‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎space‎‏‎‎‏‎"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎enter‎‏‎‎‏‎"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‎‎‏‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‎‎‎‎‎‏‏‎‎delete‎‏‎‎‏‎"</string>
 </resources>
diff --git a/v7/appcompat/res/values-es-rUS/strings.xml b/v7/appcompat/res/values-es-rUS/strings.xml
index 0cc8a70..5d58df0 100644
--- a/v7/appcompat/res/values-es-rUS/strings.xml
+++ b/v7/appcompat/res/values-es-rUS/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVADO"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"DESACTIVADO"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Buscar"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menú+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Mayúscula+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Función+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"espacio"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"intro"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"borrar"</string>
 </resources>
diff --git a/v7/appcompat/res/values-es/strings.xml b/v7/appcompat/res/values-es/strings.xml
index 3e0828b..5238229 100644
--- a/v7/appcompat/res/values-es/strings.xml
+++ b/v7/appcompat/res/values-es/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVADO"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"DESACTIVADO"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Buscar"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menú +"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta +"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl +"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt +"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Mayús +"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym +"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Función +"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"Espacio"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Intro"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Eliminar"</string>
 </resources>
diff --git a/v7/appcompat/res/values-et/strings.xml b/v7/appcompat/res/values-et/strings.xml
index 3a3dcbf..b944f77 100644
--- a/v7/appcompat/res/values-et/strings.xml
+++ b/v7/appcompat/res/values-et/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"SEES"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"VÄLJAS"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Otsing"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menüü +"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta +"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl +"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt +"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Tõstuklahv +"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym +"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Funktsiooniklahv +"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"tühik"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"sisestusklahv"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"kustutamisklahv"</string>
 </resources>
diff --git a/v7/appcompat/res/values-eu/strings.xml b/v7/appcompat/res/values-eu/strings.xml
index a651036..5a45e61 100644
--- a/v7/appcompat/res/values-eu/strings.xml
+++ b/v7/appcompat/res/values-eu/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"AKTIBATUTA"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"DESAKTIBATUTA"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Bilatu"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menua +"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta +"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ktrl +"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt +"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Maius +"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym +"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Funtzioa +"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"Zuriunea"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Sartu"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Ezabatu"</string>
 </resources>
diff --git a/v7/appcompat/res/values-fa/strings.xml b/v7/appcompat/res/values-fa/strings.xml
index 9b844b0..35e6596 100644
--- a/v7/appcompat/res/values-fa/strings.xml
+++ b/v7/appcompat/res/values-fa/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"روشن"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"خاموش"</string>
     <string name="search_menu_title" msgid="146198913615257606">"جستجو"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"منو+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"‎Meta+‎"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"‎Ctrl+‎"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"‎Alt+‎"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"‎Shift+‎"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"‎Sym+‎"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"‎Function+‎"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"کلید فاصله"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-fi/strings.xml b/v7/appcompat/res/values-fi/strings.xml
index e9bd952..829b6bb 100644
--- a/v7/appcompat/res/values-fi/strings.xml
+++ b/v7/appcompat/res/values-fi/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"KÄYTÖSSÄ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"POIS KÄYTÖSTÄ"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Haku"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Valikko+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Vaihto+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Fn+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"välilyönti"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-fr-rCA/strings.xml b/v7/appcompat/res/values-fr-rCA/strings.xml
index a3e763b..9e83462 100644
--- a/v7/appcompat/res/values-fr-rCA/strings.xml
+++ b/v7/appcompat/res/values-fr-rCA/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVÉ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"DÉSACTIVÉ"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Rechercher"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Méta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Maj+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Fonction+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"espace"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"entrée"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"supprimer"</string>
 </resources>
diff --git a/v7/appcompat/res/values-fr/strings.xml b/v7/appcompat/res/values-fr/strings.xml
index 1e412ec..5df86b5 100644
--- a/v7/appcompat/res/values-fr/strings.xml
+++ b/v7/appcompat/res/values-fr/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVÉ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"DÉSACTIVÉ"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Rechercher"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Méta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Maj+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Fonction+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"espace"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"entrée"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"supprimer"</string>
 </resources>
diff --git a/v7/appcompat/res/values-gl/strings.xml b/v7/appcompat/res/values-gl/strings.xml
index 2af80a1..c500af5 100644
--- a/v7/appcompat/res/values-gl/strings.xml
+++ b/v7/appcompat/res/values-gl/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVAR"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"DESACTIVAR"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Buscar"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menú +"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta +"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl +"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt +"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Maiús +"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sim +"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Función +"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"espazo"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Intro"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"eliminar"</string>
 </resources>
diff --git a/v7/appcompat/res/values-gu/strings.xml b/v7/appcompat/res/values-gu/strings.xml
index 7a243ed..a8b0c48 100644
--- a/v7/appcompat/res/values-gu/strings.xml
+++ b/v7/appcompat/res/values-gu/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ચાલુ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"બંધ"</string>
     <string name="search_menu_title" msgid="146198913615257606">"શોધો"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"મેનૂ+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"Spacebar"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"ડિલીટ કરો"</string>
 </resources>
diff --git a/v7/appcompat/res/values-hi/strings.xml b/v7/appcompat/res/values-hi/strings.xml
index a31ab90..16dc7ce 100644
--- a/v7/appcompat/res/values-hi/strings.xml
+++ b/v7/appcompat/res/values-hi/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"चालू"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"बंद"</string>
     <string name="search_menu_title" msgid="146198913615257606">"सर्च"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-hr/strings.xml b/v7/appcompat/res/values-hr/strings.xml
index 27a1c2e..9253fb9 100644
--- a/v7/appcompat/res/values-hr/strings.xml
+++ b/v7/appcompat/res/values-hr/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"UKLJUČENO"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ISKLJUČENO"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Pretraživanje"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"razmaknica"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-hu/strings.xml b/v7/appcompat/res/values-hu/strings.xml
index d3e413f..714ef47 100644
--- a/v7/appcompat/res/values-hu/strings.xml
+++ b/v7/appcompat/res/values-hu/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"BE"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"KI"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Keresés"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"Szóköz"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-hy/strings.xml b/v7/appcompat/res/values-hy/strings.xml
index 1c41ef6..59c9ee5 100644
--- a/v7/appcompat/res/values-hy/strings.xml
+++ b/v7/appcompat/res/values-hy/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ՄԻԱՑՎԱԾ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ԱՆՋԱՏՎԱԾ"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Որոնել"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"բացատ"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-in/strings.xml b/v7/appcompat/res/values-in/strings.xml
index 2e9fbb7..1ae3f90 100644
--- a/v7/appcompat/res/values-in/strings.xml
+++ b/v7/appcompat/res/values-in/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"AKTIF"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"NONAKTIF"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Telusuri"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"spasi"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-is/strings.xml b/v7/appcompat/res/values-is/strings.xml
index 3f61d84..3ae59da 100644
--- a/v7/appcompat/res/values-is/strings.xml
+++ b/v7/appcompat/res/values-is/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"KVEIKT"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"SLÖKKT"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Leita"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Valmynd+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Aðgerðarlykill+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"bilslá"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-it/strings.xml b/v7/appcompat/res/values-it/strings.xml
index fbd2c58..04b64ce 100644
--- a/v7/appcompat/res/values-it/strings.xml
+++ b/v7/appcompat/res/values-it/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Ricerca"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"MENU +"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"META +"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"CTRL +"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"ALT +"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"MAIUSC +"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"SYM +"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"FUNZIONE +"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"barra spaziatrice"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"INVIO"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"CANC"</string>
 </resources>
diff --git a/v7/appcompat/res/values-iw/strings.xml b/v7/appcompat/res/values-iw/strings.xml
index 0a7d0bb..d0f2211 100644
--- a/v7/appcompat/res/values-iw/strings.xml
+++ b/v7/appcompat/res/values-iw/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"פועל"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"כבוי"</string>
     <string name="search_menu_title" msgid="146198913615257606">"חיפוש"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"תפריט+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+‎"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"מקש רווח"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ja/strings.xml b/v7/appcompat/res/values-ja/strings.xml
index c4d0e20..db163f3 100644
--- a/v7/appcompat/res/values-ja/strings.xml
+++ b/v7/appcompat/res/values-ja/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ON"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"OFF"</string>
     <string name="search_menu_title" msgid="146198913615257606">"検索"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"Space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ka/strings.xml b/v7/appcompat/res/values-ka/strings.xml
index 3b077a3..6d9c08b 100644
--- a/v7/appcompat/res/values-ka/strings.xml
+++ b/v7/appcompat/res/values-ka/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ჩართულია"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"გამორთულია"</string>
     <string name="search_menu_title" msgid="146198913615257606">"ძიება"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"შეყვანა"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"წაშლა"</string>
 </resources>
diff --git a/v7/appcompat/res/values-kk/strings.xml b/v7/appcompat/res/values-kk/strings.xml
index c32045b..9d206bc 100644
--- a/v7/appcompat/res/values-kk/strings.xml
+++ b/v7/appcompat/res/values-kk/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ҚОСУЛЫ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ӨШІРУЛІ"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Іздеу"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Mәзір+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"бос орын"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-km/strings.xml b/v7/appcompat/res/values-km/strings.xml
index ffe289a..f42da7a 100644
--- a/v7/appcompat/res/values-km/strings.xml
+++ b/v7/appcompat/res/values-km/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"បើក"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"បិទ"</string>
     <string name="search_menu_title" msgid="146198913615257606">"ស្វែងរក"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-kn/strings.xml b/v7/appcompat/res/values-kn/strings.xml
index 4218bd6..ce28303 100644
--- a/v7/appcompat/res/values-kn/strings.xml
+++ b/v7/appcompat/res/values-kn/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ಆನ್"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ಆಫ್"</string>
     <string name="search_menu_title" msgid="146198913615257606">"ಹುಡುಕಿ"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ko/strings.xml b/v7/appcompat/res/values-ko/strings.xml
index 6c84a2a..db0903f 100644
--- a/v7/appcompat/res/values-ko/strings.xml
+++ b/v7/appcompat/res/values-ko/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"사용"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"사용 안함"</string>
     <string name="search_menu_title" msgid="146198913615257606">"검색"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"스페이스바"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"입력"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"삭제"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ky/strings.xml b/v7/appcompat/res/values-ky/strings.xml
index 66202f7..1aba4f0 100644
--- a/v7/appcompat/res/values-ky/strings.xml
+++ b/v7/appcompat/res/values-ky/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"КҮЙҮК"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ӨЧҮК"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Издөө"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"боштук"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-lo/strings.xml b/v7/appcompat/res/values-lo/strings.xml
index 1b92df0..c53a987 100644
--- a/v7/appcompat/res/values-lo/strings.xml
+++ b/v7/appcompat/res/values-lo/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ເປີດ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ປິດ"</string>
     <string name="search_menu_title" msgid="146198913615257606">"ຊອກຫາ"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-lt/strings.xml b/v7/appcompat/res/values-lt/strings.xml
index 5793069..ab9f25c 100644
--- a/v7/appcompat/res/values-lt/strings.xml
+++ b/v7/appcompat/res/values-lt/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ĮJUNGTI"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"IŠJUNGTA"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Paieška"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"„Menu“ +"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"„Meta“ +"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"„Ctrl“ +"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"„Alt“ +"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"„Shift“ +"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"„Sym“ +"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"„Function“ +"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"tarpo klavišas"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"„Enter“"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"„Delete“"</string>
 </resources>
diff --git a/v7/appcompat/res/values-lv/strings.xml b/v7/appcompat/res/values-lv/strings.xml
index 67e18d3..67904a1 100644
--- a/v7/appcompat/res/values-lv/strings.xml
+++ b/v7/appcompat/res/values-lv/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"IESLĒGTS"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"IZSLĒGTS"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Meklēt"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Poga Izvēlne +"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta taustiņš +"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Vadīšanas taustiņš +"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alternēšanas taustiņš +"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Pārslēgšanas taustiņš +"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Simbolu taustiņš +"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Funkcijas taustiņš +"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"atstarpes taustiņš"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"ievadīšanas taustiņš"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"dzēšanas taustiņš"</string>
 </resources>
diff --git a/v7/appcompat/res/values-mk/strings.xml b/v7/appcompat/res/values-mk/strings.xml
index b12a235..408edb1 100644
--- a/v7/appcompat/res/values-mk/strings.xml
+++ b/v7/appcompat/res/values-mk/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ВКЛУЧЕНО"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ИСКЛУЧЕНО"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Пребарај"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Мени+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"копче Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"копче Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"копче Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"копче Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"копче Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"копче Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"вселена"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"копче enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"избриши"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ml/strings.xml b/v7/appcompat/res/values-ml/strings.xml
index 9033f8a..e880ebb 100644
--- a/v7/appcompat/res/values-ml/strings.xml
+++ b/v7/appcompat/res/values-ml/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ഓൺ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ഓഫ്"</string>
     <string name="search_menu_title" msgid="146198913615257606">"തിരയുക"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"മെനു+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"മെറ്റ+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"ഫംഗ്ഷന്‍+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"സ്‌പെയ്‌സ്"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"ഇല്ലാതാക്കുക"</string>
 </resources>
diff --git a/v7/appcompat/res/values-mn/strings.xml b/v7/appcompat/res/values-mn/strings.xml
index 56036ea..856e9f6 100644
--- a/v7/appcompat/res/values-mn/strings.xml
+++ b/v7/appcompat/res/values-mn/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ИДЭВХТЭЙ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ИДЭВХГҮЙ"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Хайлт"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Цэс+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Мета+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Функц+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"зай"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"оруулах"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"устгах"</string>
 </resources>
diff --git a/v7/appcompat/res/values-mr/strings.xml b/v7/appcompat/res/values-mr/strings.xml
index 26ada80..ed3463c 100644
--- a/v7/appcompat/res/values-mr/strings.xml
+++ b/v7/appcompat/res/values-mr/strings.xml
@@ -30,8 +30,18 @@
     <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"एक अ‍ॅप निवडा"</string>
     <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"सर्व पहा"</string>
     <string name="abc_shareactionprovider_share_with_application" msgid="3300176832234831527">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> सह शेअर करा"</string>
-    <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"यांच्यासह सामायिक करा"</string>
+    <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"यांच्यासह शेअर करा"</string>
     <string name="abc_capital_on" msgid="3405795526292276155">"चालू"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"बंद"</string>
     <string name="search_menu_title" msgid="146198913615257606">"शोधा"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"मेनू+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"spacebar"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"एंटर करा"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"हटवा"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ms/strings.xml b/v7/appcompat/res/values-ms/strings.xml
index 18f84ce..8af4c13 100644
--- a/v7/appcompat/res/values-ms/strings.xml
+++ b/v7/appcompat/res/values-ms/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"HIDUP"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"MATI"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Cari"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Fungsi+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"ruang"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"padam"</string>
 </resources>
diff --git a/v7/appcompat/res/values-my/strings.xml b/v7/appcompat/res/values-my/strings.xml
index cbc8791..cfd6625 100644
--- a/v7/appcompat/res/values-my/strings.xml
+++ b/v7/appcompat/res/values-my/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ဖွင့်"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ပိတ်"</string>
     <string name="search_menu_title" msgid="146198913615257606">"ရှာဖွေပါ"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-nb/strings.xml b/v7/appcompat/res/values-nb/strings.xml
index 6005234..f9fd80e 100644
--- a/v7/appcompat/res/values-nb/strings.xml
+++ b/v7/appcompat/res/values-nb/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"PÅ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"AV"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Søk"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Meny+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Funksjon+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"mellomrom"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ne/strings.xml b/v7/appcompat/res/values-ne/strings.xml
index 96b1042..0a0de14 100644
--- a/v7/appcompat/res/values-ne/strings.xml
+++ b/v7/appcompat/res/values-ne/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"सक्रिय गर्नुहोस्"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"निष्क्रिय पार्नुहोस्"</string>
     <string name="search_menu_title" msgid="146198913615257606">"खोज्नुहोस्"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-nl/strings.xml b/v7/appcompat/res/values-nl/strings.xml
index e0d2044..ffcb3d9 100644
--- a/v7/appcompat/res/values-nl/strings.xml
+++ b/v7/appcompat/res/values-nl/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"AAN"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"UIT"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Zoeken"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu +"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta +"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl +"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt +"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift +"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym +"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Functie +"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"spatie"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"verwijderen"</string>
 </resources>
diff --git a/v7/appcompat/res/values-or/strings.xml b/v7/appcompat/res/values-or/strings.xml
index 4dc6eb4..4486724 100644
--- a/v7/appcompat/res/values-or/strings.xml
+++ b/v7/appcompat/res/values-or/strings.xml
@@ -32,10 +32,27 @@
     <!-- no translation found for abc_shareactionprovider_share_with_application (3300176832234831527) -->
     <skip />
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"ଏହାଙ୍କ ସହ ଶେୟାର୍‌ କରନ୍ତୁ"</string>
-    <!-- no translation found for abc_capital_on (3405795526292276155) -->
+    <string name="abc_capital_on" msgid="3405795526292276155">"ଅନ୍"</string>
+    <string name="abc_capital_off" msgid="121134116657445385">"ଅଫ୍"</string>
+    <string name="search_menu_title" msgid="146198913615257606">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
+    <!-- no translation found for abc_prepend_shortcut_label (1351762916121158029) -->
     <skip />
-    <!-- no translation found for abc_capital_off (121134116657445385) -->
+    <!-- no translation found for abc_menu_meta_shortcut_label (7643535737296831317) -->
     <skip />
-    <!-- no translation found for search_menu_title (146198913615257606) -->
+    <!-- no translation found for abc_menu_ctrl_shortcut_label (1324831542140195728) -->
+    <skip />
+    <!-- no translation found for abc_menu_alt_shortcut_label (1302280443949172191) -->
+    <skip />
+    <!-- no translation found for abc_menu_shift_shortcut_label (8126296154200614004) -->
+    <skip />
+    <!-- no translation found for abc_menu_sym_shortcut_label (9002602288060866689) -->
+    <skip />
+    <!-- no translation found for abc_menu_function_shortcut_label (4792426091847145555) -->
+    <skip />
+    <!-- no translation found for abc_menu_space_shortcut_label (2378550843553983978) -->
+    <skip />
+    <!-- no translation found for abc_menu_enter_shortcut_label (8341180395196749340) -->
+    <skip />
+    <!-- no translation found for abc_menu_delete_shortcut_label (8362206064229013510) -->
     <skip />
 </resources>
diff --git a/v7/appcompat/res/values-pa/strings.xml b/v7/appcompat/res/values-pa/strings.xml
index 7f28ac8..fc1fdba 100644
--- a/v7/appcompat/res/values-pa/strings.xml
+++ b/v7/appcompat/res/values-pa/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ਤੇ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ਬੰਦ"</string>
     <string name="search_menu_title" msgid="146198913615257606">"ਖੋਜੋ"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-pl/strings.xml b/v7/appcompat/res/values-pl/strings.xml
index d706241..af26367 100644
--- a/v7/appcompat/res/values-pl/strings.xml
+++ b/v7/appcompat/res/values-pl/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"WŁ."</string>
     <string name="abc_capital_off" msgid="121134116657445385">"WYŁ."</string>
     <string name="search_menu_title" msgid="146198913615257606">"Szukaj"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Funkcyjny+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"spacja"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-pt-rBR/strings.xml b/v7/appcompat/res/values-pt-rBR/strings.xml
index 90461ec..17d8593 100644
--- a/v7/appcompat/res/values-pt-rBR/strings.xml
+++ b/v7/appcompat/res/values-pt-rBR/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ATIVAR"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"DESATIVAR"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Pesquisar"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"espaço"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-pt-rPT/strings.xml b/v7/appcompat/res/values-pt-rPT/strings.xml
index 40f6499..f8c0fa7 100644
--- a/v7/appcompat/res/values-pt-rPT/strings.xml
+++ b/v7/appcompat/res/values-pt-rPT/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ATIVADO"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"DESATIVADO"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Pesquisar"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu +"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta +"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl +"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt +"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift +"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym +"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Função +"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"espaço"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"eliminar"</string>
 </resources>
diff --git a/v7/appcompat/res/values-pt/strings.xml b/v7/appcompat/res/values-pt/strings.xml
index 90461ec..17d8593 100644
--- a/v7/appcompat/res/values-pt/strings.xml
+++ b/v7/appcompat/res/values-pt/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ATIVAR"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"DESATIVAR"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Pesquisar"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"espaço"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ro/strings.xml b/v7/appcompat/res/values-ro/strings.xml
index 6d04be9..86495fd 100644
--- a/v7/appcompat/res/values-ro/strings.xml
+++ b/v7/appcompat/res/values-ro/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ACTIVAT"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"DEZACTIVAȚI"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Căutați"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Meniu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Funcție+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"spațiu"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ru/strings.xml b/v7/appcompat/res/values-ru/strings.xml
index 2b28958..c505bf5 100644
--- a/v7/appcompat/res/values-ru/strings.xml
+++ b/v7/appcompat/res/values-ru/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ВКЛ."</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ОТКЛ."</string>
     <string name="search_menu_title" msgid="146198913615257606">"Поиск"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Меню +"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta +"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl +"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt +"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift +"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym +"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Fn +"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"Пробел"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Ввод"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-si/strings.xml b/v7/appcompat/res/values-si/strings.xml
index 7631288..c154686 100644
--- a/v7/appcompat/res/values-si/strings.xml
+++ b/v7/appcompat/res/values-si/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ක්‍රියාත්මකයි"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ක්‍රියාවිරහිතයි"</string>
     <string name="search_menu_title" msgid="146198913615257606">"සොයන්න"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"මකන්න"</string>
 </resources>
diff --git a/v7/appcompat/res/values-sk/strings.xml b/v7/appcompat/res/values-sk/strings.xml
index 03faf14..67184b0 100644
--- a/v7/appcompat/res/values-sk/strings.xml
+++ b/v7/appcompat/res/values-sk/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ZAPNUTÉ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"VYPNUTÉ"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Vyhľadávanie"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"medzerník"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"odstrániť"</string>
 </resources>
diff --git a/v7/appcompat/res/values-sl/strings.xml b/v7/appcompat/res/values-sl/strings.xml
index 22b8bd4..e38e5ea 100644
--- a/v7/appcompat/res/values-sl/strings.xml
+++ b/v7/appcompat/res/values-sl/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"VKLOPLJENO"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"IZKLOPLJENO"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Iskanje"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Meni +"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta +"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl +"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt +"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift +"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym +"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Fn +"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"preslednica"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-sq/strings.xml b/v7/appcompat/res/values-sq/strings.xml
index 1a1f02e..8b958a2 100644
--- a/v7/appcompat/res/values-sq/strings.xml
+++ b/v7/appcompat/res/values-sq/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"AKTIV"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"JOAKTIV"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Kërko"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menyja+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Funksioni+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"hapësirë"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-sr/strings.xml b/v7/appcompat/res/values-sr/strings.xml
index 5678341..4c702bc 100644
--- a/v7/appcompat/res/values-sr/strings.xml
+++ b/v7/appcompat/res/values-sr/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"УКЉУЧИ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ИСКЉУЧИ"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Претражи"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"тастер за размак"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-sv/strings.xml b/v7/appcompat/res/values-sv/strings.xml
index 62d470f..72b7f88 100644
--- a/v7/appcompat/res/values-sv/strings.xml
+++ b/v7/appcompat/res/values-sv/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"PÅ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"AV"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Sök"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Meny + "</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta + "</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl + "</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt + "</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Skift + "</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Symbol + "</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Funktion + "</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"blanksteg"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"retur"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-sw/strings.xml b/v7/appcompat/res/values-sw/strings.xml
index c575ae0..1c623b7 100644
--- a/v7/appcompat/res/values-sw/strings.xml
+++ b/v7/appcompat/res/values-sw/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"IMEWASHWA"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"IMEZIMWA"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Tafuta"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menyu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"nafasi"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"futa"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ta/strings.xml b/v7/appcompat/res/values-ta/strings.xml
index 971a3db..7aa031a 100644
--- a/v7/appcompat/res/values-ta/strings.xml
+++ b/v7/appcompat/res/values-ta/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ஆன்"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ஆஃப்"</string>
     <string name="search_menu_title" msgid="146198913615257606">"தேடு"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"மெனு மற்றும்"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"மெட்டா மற்றும்"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"கண்ட்ரோல் மற்றும்"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"ஆல்ட் மற்றும்"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"ஷிஃப்ட் மற்றும்"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"சிம்பல் மற்றும்"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"ஃபங்ஷன் மற்றும்"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"ஸ்பேஸ்"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"எண்டர்"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"டெலிட்"</string>
 </resources>
diff --git a/v7/appcompat/res/values-te/strings.xml b/v7/appcompat/res/values-te/strings.xml
index f7d7577..818f0e3 100644
--- a/v7/appcompat/res/values-te/strings.xml
+++ b/v7/appcompat/res/values-te/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"ఆన్ చేయి"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ఆఫ్ చేయి"</string>
     <string name="search_menu_title" msgid="146198913615257606">"వెతుకు"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"స్పేస్"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-th/strings.xml b/v7/appcompat/res/values-th/strings.xml
index f8ea1cd..5ecec86 100644
--- a/v7/appcompat/res/values-th/strings.xml
+++ b/v7/appcompat/res/values-th/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"เปิด"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ปิด"</string>
     <string name="search_menu_title" msgid="146198913615257606">"ค้นหา"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"เมนู+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"Space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-tl/strings.xml b/v7/appcompat/res/values-tl/strings.xml
index 1ad2689..3ef5df6 100644
--- a/v7/appcompat/res/values-tl/strings.xml
+++ b/v7/appcompat/res/values-tl/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"I-ON"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"I-OFF"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Maghanap"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-tr/strings.xml b/v7/appcompat/res/values-tr/strings.xml
index fae41d3..153e2c2 100644
--- a/v7/appcompat/res/values-tr/strings.xml
+++ b/v7/appcompat/res/values-tr/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"AÇ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"KAPAT"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Ara"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menü+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Üst Karakter+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"İşlev+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"boşluk"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"sil"</string>
 </resources>
diff --git a/v7/appcompat/res/values-uk/strings.xml b/v7/appcompat/res/values-uk/strings.xml
index afc74ff..7aed219 100644
--- a/v7/appcompat/res/values-uk/strings.xml
+++ b/v7/appcompat/res/values-uk/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"УВІМК."</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ВИМК."</string>
     <string name="search_menu_title" msgid="146198913615257606">"Пошук"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"пробіл"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-ur/strings.xml b/v7/appcompat/res/values-ur/strings.xml
index 60ec34a..997d594 100644
--- a/v7/appcompat/res/values-ur/strings.xml
+++ b/v7/appcompat/res/values-ur/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"آن"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"آف"</string>
     <string name="search_menu_title" msgid="146198913615257606">"تلاش"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+‎"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+‎"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+‎"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+‎"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+‎"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+‎"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+‎"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-uz/strings.xml b/v7/appcompat/res/values-uz/strings.xml
index 0417cba..f925bd6 100644
--- a/v7/appcompat/res/values-uz/strings.xml
+++ b/v7/appcompat/res/values-uz/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"YONIQ"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"O‘CHIQ"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Qidirish"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menyu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Fn+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"Probel"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-vi/strings.xml b/v7/appcompat/res/values-vi/strings.xml
index 4560b4b..e07efed 100644
--- a/v7/appcompat/res/values-vi/strings.xml
+++ b/v7/appcompat/res/values-vi/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"BẬT"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"TẮT"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Tìm kiếm"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"phím cách"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"delete"</string>
 </resources>
diff --git a/v7/appcompat/res/values-zh-rCN/strings.xml b/v7/appcompat/res/values-zh-rCN/strings.xml
index 7b23457..6dc1ea2 100644
--- a/v7/appcompat/res/values-zh-rCN/strings.xml
+++ b/v7/appcompat/res/values-zh-rCN/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"开启"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"关闭"</string>
     <string name="search_menu_title" msgid="146198913615257606">"搜索"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Fn+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"空格键"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Enter 键"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Delete 键"</string>
 </resources>
diff --git a/v7/appcompat/res/values-zh-rHK/strings.xml b/v7/appcompat/res/values-zh-rHK/strings.xml
index fc32117..ce753fd 100644
--- a/v7/appcompat/res/values-zh-rHK/strings.xml
+++ b/v7/appcompat/res/values-zh-rHK/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"開啟"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"關閉"</string>
     <string name="search_menu_title" msgid="146198913615257606">"搜尋"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu +"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta +"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl +"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt +"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift +"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym +"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Fn +"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"空白鍵"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Enter 鍵"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"刪除"</string>
 </resources>
diff --git a/v7/appcompat/res/values-zh-rTW/strings.xml b/v7/appcompat/res/values-zh-rTW/strings.xml
index 35be873..0f29b8e 100644
--- a/v7/appcompat/res/values-zh-rTW/strings.xml
+++ b/v7/appcompat/res/values-zh-rTW/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"開啟"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"關閉"</string>
     <string name="search_menu_title" msgid="146198913615257606">"搜尋"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Menu +"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta +"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl +"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt +"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift +"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym +"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Fn +"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"空格鍵"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"Enter 鍵"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"Delete 鍵"</string>
 </resources>
diff --git a/v7/appcompat/res/values-zu/strings.xml b/v7/appcompat/res/values-zu/strings.xml
index e84ba7a..e3032f1 100644
--- a/v7/appcompat/res/values-zu/strings.xml
+++ b/v7/appcompat/res/values-zu/strings.xml
@@ -34,4 +34,14 @@
     <string name="abc_capital_on" msgid="3405795526292276155">"VULIWE"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"VALIWE"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Sesha"</string>
+    <string name="abc_prepend_shortcut_label" msgid="1351762916121158029">"Imenyu+"</string>
+    <string name="abc_menu_meta_shortcut_label" msgid="7643535737296831317">"Meta+"</string>
+    <string name="abc_menu_ctrl_shortcut_label" msgid="1324831542140195728">"Ctrl+"</string>
+    <string name="abc_menu_alt_shortcut_label" msgid="1302280443949172191">"Alt+"</string>
+    <string name="abc_menu_shift_shortcut_label" msgid="8126296154200614004">"Shift+"</string>
+    <string name="abc_menu_sym_shortcut_label" msgid="9002602288060866689">"Sym+"</string>
+    <string name="abc_menu_function_shortcut_label" msgid="4792426091847145555">"Function+"</string>
+    <string name="abc_menu_space_shortcut_label" msgid="2378550843553983978">"space"</string>
+    <string name="abc_menu_enter_shortcut_label" msgid="8341180395196749340">"enter"</string>
+    <string name="abc_menu_delete_shortcut_label" msgid="8362206064229013510">"susa"</string>
 </resources>
diff --git a/webkit/api/current.txt b/webkit/api/current.txt
new file mode 100644
index 0000000..fb15e2f
--- /dev/null
+++ b/webkit/api/current.txt
@@ -0,0 +1,52 @@
+package androidx.webkit {
+
+  public abstract class ServiceWorkerClientCompat {
+    ctor public ServiceWorkerClientCompat();
+    method public abstract android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebResourceRequest);
+  }
+
+  public abstract class ServiceWorkerControllerCompat {
+    method public static androidx.webkit.ServiceWorkerControllerCompat getInstance();
+    method public abstract androidx.webkit.ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings();
+    method public abstract void setServiceWorkerClient(androidx.webkit.ServiceWorkerClientCompat);
+  }
+
+  public abstract class ServiceWorkerWebSettingsCompat {
+    method public abstract boolean getAllowContentAccess();
+    method public abstract boolean getAllowFileAccess();
+    method public abstract boolean getBlockNetworkLoads();
+    method public abstract int getCacheMode();
+    method public abstract void setAllowContentAccess(boolean);
+    method public abstract void setAllowFileAccess(boolean);
+    method public abstract void setBlockNetworkLoads(boolean);
+    method public abstract void setCacheMode(int);
+  }
+
+  public class WebSettingsCompat {
+    method public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
+    method public static boolean getOffscreenPreRaster(android.webkit.WebSettings);
+    method public static boolean getSafeBrowsingEnabled(android.webkit.WebSettings);
+    method public static void setDisabledActionModeMenuItems(android.webkit.WebSettings, int);
+    method public static void setOffscreenPreRaster(android.webkit.WebSettings, boolean);
+    method public static void setSafeBrowsingEnabled(android.webkit.WebSettings, boolean);
+  }
+
+  public class WebViewCompat {
+    method public static android.content.pm.PackageInfo getCurrentWebViewPackage(android.content.Context);
+    method public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
+    method public static void postVisualStateCallback(android.webkit.WebView, long, androidx.webkit.WebViewCompat.VisualStateCallback);
+    method public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String>, android.webkit.ValueCallback<java.lang.Boolean>);
+    method public static void startSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean>);
+  }
+
+  public static abstract interface WebViewCompat.VisualStateCallback {
+    method public abstract void onComplete(long);
+  }
+
+  public class WebViewFeature {
+    method public static boolean isFeatureSupported(java.lang.String);
+    field public static final java.lang.String VISUAL_STATE_CALLBACK = "VISUAL_STATE_CALLBACK";
+  }
+
+}
+
diff --git a/webkit/build.gradle b/webkit/build.gradle
index 06f3801..d610dad 100644
--- a/webkit/build.gradle
+++ b/webkit/build.gradle
@@ -38,14 +38,17 @@
         // Allow compiling the WebView support library boundary interfaces from this project.
         main.java.srcDirs += new File(webviewBoundaryInterfacesDir, "src").getAbsolutePath()
     }
+
+    buildTypes.all {
+        consumerProguardFiles new File(webviewBoundaryInterfacesDir, "proguard.flags")
+    }
 }
 
 supportLibrary {
     name = "WebView Support Library"
-    publish = false
+    publish = true
     mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.WEBKIT
     inceptionYear = "2017"
     description = "The WebView Support Library is a static library you can add to your Android application in order to use android.webkit APIs that are not available for older platform versions."
-    minSdkVersion = 21
 }
diff --git a/webkit/src/androidTest/java/androidx/webkit/PollingCheck.java b/webkit/src/androidTest/java/androidx/webkit/PollingCheck.java
new file mode 100644
index 0000000..4c59a3e
--- /dev/null
+++ b/webkit/src/androidTest/java/androidx/webkit/PollingCheck.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2018 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 androidx.webkit;
+
+import junit.framework.Assert;
+
+import java.util.concurrent.Callable;
+
+/**
+ * A class for checking a specific statement {@link #check()} through polling, either until the
+ * statement is true, or until timing out.
+ *
+ * Copy-pasted from CTS: com.android.compatibility.common.util.PollingCheck.
+ */
+public abstract class PollingCheck {
+    private static final long TIME_SLICE = 50;
+    private long mTimeout = 3000;
+
+    public PollingCheck(long timeout) {
+        mTimeout = timeout;
+    }
+
+    protected abstract boolean check();
+
+    public void run() {
+        if (check()) {
+            return;
+        }
+
+        long timeout = mTimeout;
+        while (timeout > 0) {
+            try {
+                Thread.sleep(TIME_SLICE);
+            } catch (InterruptedException e) {
+                Assert.fail("unexpected InterruptedException");
+            }
+
+            if (check()) {
+                return;
+            }
+
+            timeout -= TIME_SLICE;
+        }
+
+        Assert.fail("unexpected timeout");
+    }
+
+    public static void check(CharSequence message, long timeout, Callable<Boolean> condition)
+            throws Exception {
+        while (timeout > 0) {
+            if (condition.call()) {
+                return;
+            }
+
+            Thread.sleep(TIME_SLICE);
+            timeout -= TIME_SLICE;
+        }
+
+        Assert.fail(message.toString());
+    }
+}
diff --git a/webkit/src/androidTest/java/androidx/webkit/ServiceWorkerClientCompatTest.java b/webkit/src/androidTest/java/androidx/webkit/ServiceWorkerClientCompatTest.java
new file mode 100644
index 0000000..aecbc34
--- /dev/null
+++ b/webkit/src/androidTest/java/androidx/webkit/ServiceWorkerClientCompatTest.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2018 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 androidx.webkit;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Build;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.webkit.JavascriptInterface;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
+import android.webkit.WebView;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ServiceWorkerClientCompatTest {
+
+    // The BASE_URL does not matter since the tests will intercept the load, but it should be https
+    // for the Service Worker registration to succeed.
+    private static final String BASE_URL = "https://www.example.com/";
+    private static final String INDEX_URL = BASE_URL + "index.html";
+    private static final String SW_URL = BASE_URL + "sw.js";
+    private static final String FETCH_URL = BASE_URL + "fetch.html";
+
+    private static final String JS_INTERFACE_NAME = "Android";
+    private static final int POLLING_TIMEOUT = 10 * 1000;
+
+    // static HTML page always injected instead of the url loaded.
+    private static final String INDEX_RAW_HTML =
+            "<!DOCTYPE html>\n"
+                    + "<html>\n"
+                    + "  <body>\n"
+                    + "    <script>\n"
+                    + "      navigator.serviceWorker.register('sw.js').then(function(reg) {\n"
+                    + "         " + JS_INTERFACE_NAME + ".registrationSuccess();\n"
+                    + "      }).catch(function(err) {\n"
+                    + "         console.error(err);\n"
+                    + "      });\n"
+                    + "    </script>\n"
+                    + "  </body>\n"
+                    + "</html>\n";
+    private static final String SW_RAW_HTML = "fetch('fetch.html');";
+    private static final String SW_UNREGISTER_RAW_JS =
+            "navigator.serviceWorker.getRegistration().then(function(r) {"
+                    + "  r.unregister().then(function(success) {"
+                    + "    if (success) " + JS_INTERFACE_NAME + ".unregisterSuccess();"
+                    + "    else console.error('unregister() was not successful');"
+                    + "  });"
+                    + "}).catch(function(err) {"
+                    + "   console.error(err);"
+                    + "});";
+
+    private JavascriptStatusReceiver mJavascriptStatusReceiver;
+    private WebViewOnUiThread mOnUiThread;
+
+    // Both this test and WebViewOnUiThread need to override some of the methods on WebViewClient,
+    // so this test subclasses the WebViewClient from WebViewOnUiThread.
+    private static class InterceptClient extends WebViewOnUiThread.WaitForLoadedClient {
+
+        InterceptClient(WebViewOnUiThread webViewOnUiThread) throws Exception {
+            super(webViewOnUiThread);
+        }
+
+        @Override
+        public WebResourceResponse shouldInterceptRequest(WebView view,
+                WebResourceRequest request) {
+            // Only return content for INDEX_URL, deny all other requests.
+            try {
+                if (request.getUrl().toString().equals(INDEX_URL)) {
+                    return new WebResourceResponse("text/html", "utf-8",
+                            new ByteArrayInputStream(INDEX_RAW_HTML.getBytes("UTF-8")));
+                }
+            } catch (java.io.UnsupportedEncodingException e) { }
+            return new WebResourceResponse("text/html", "UTF-8", null);
+        }
+    }
+
+    public static class InterceptServiceWorkerClient extends ServiceWorkerClientCompat {
+        private List<WebResourceRequest> mInterceptedRequests = new ArrayList<WebResourceRequest>();
+
+        @Override
+        public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) {
+            // Records intercepted requests and only return content for SW_URL.
+            mInterceptedRequests.add(request);
+            try {
+                if (request.getUrl().toString().equals(SW_URL)) {
+                    return new WebResourceResponse("application/javascript", "utf-8",
+                            new ByteArrayInputStream(SW_RAW_HTML.getBytes("UTF-8")));
+                }
+            } catch (java.io.UnsupportedEncodingException e) { }
+            return new WebResourceResponse("text/html", "UTF-8", null);
+        }
+
+        List<WebResourceRequest> getInterceptedRequests() {
+            return mInterceptedRequests;
+        }
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mOnUiThread = new WebViewOnUiThread();
+        mOnUiThread.getSettings().setJavaScriptEnabled(true);
+
+        mJavascriptStatusReceiver = new JavascriptStatusReceiver();
+        mOnUiThread.addJavascriptInterface(mJavascriptStatusReceiver, JS_INTERFACE_NAME);
+        mOnUiThread.setWebViewClient(new InterceptClient(mOnUiThread));
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (mOnUiThread != null) {
+            mOnUiThread.cleanUp();
+        }
+    }
+
+    // Test correct invocation of shouldInterceptRequest for Service Workers.
+    @Test
+    public void testServiceWorkerClientInterceptCallback() throws Exception {
+        // TODO(gsennton) activate this test for pre-N devices when we can pre-install a WebView APK
+        // containing support for the WebView Support Library, see b/73454652.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return;
+
+        final InterceptServiceWorkerClient mInterceptServiceWorkerClient =
+                new InterceptServiceWorkerClient();
+        ServiceWorkerControllerCompat swController = ServiceWorkerControllerCompat.getInstance();
+        swController.setServiceWorkerClient(mInterceptServiceWorkerClient);
+
+        mOnUiThread.loadUrlAndWaitForCompletion(INDEX_URL);
+
+        Callable<Boolean> registrationSuccess = new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                return mJavascriptStatusReceiver.mRegistrationSuccess;
+            }
+        };
+        PollingCheck.check("JS could not register Service Worker", POLLING_TIMEOUT,
+                registrationSuccess);
+
+        Callable<Boolean> receivedRequest = new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                return mInterceptServiceWorkerClient.getInterceptedRequests().size() >= 2;
+            }
+        };
+        PollingCheck.check("Service Worker intercept callbacks not invoked", POLLING_TIMEOUT,
+                receivedRequest);
+
+        List<WebResourceRequest> requests = mInterceptServiceWorkerClient.getInterceptedRequests();
+        assertEquals(2, requests.size());
+        assertEquals(SW_URL, requests.get(0).getUrl().toString());
+        assertEquals(FETCH_URL, requests.get(1).getUrl().toString());
+
+        // Clean-up, make sure to unregister the Service Worker.
+        mOnUiThread.evaluateJavascript(SW_UNREGISTER_RAW_JS, null);
+        Callable<Boolean> unregisterSuccess = new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                return mJavascriptStatusReceiver.mUnregisterSuccess;
+            }
+        };
+        PollingCheck.check("JS could not unregister Service Worker", POLLING_TIMEOUT,
+                unregisterSuccess);
+    }
+
+    // Object added to the page via AddJavascriptInterface() that is used by the test Javascript to
+    // notify back to Java if the Service Worker registration was successful.
+    public static final class JavascriptStatusReceiver {
+        public volatile boolean mRegistrationSuccess = false;
+        public volatile boolean mUnregisterSuccess = false;
+
+        @JavascriptInterface
+        public void registrationSuccess() {
+            mRegistrationSuccess = true;
+        }
+
+        @JavascriptInterface
+        public void unregisterSuccess() {
+            mUnregisterSuccess = true;
+        }
+    }
+}
diff --git a/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java b/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
index 3c64b9c..bd77fdb 100644
--- a/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
+++ b/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -28,6 +29,7 @@
 import android.os.Looper;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
+import android.support.test.filters.Suppress;
 import android.support.test.runner.AndroidJUnit4;
 import android.webkit.SafeBrowsingResponse;
 import android.webkit.ValueCallback;
@@ -83,6 +85,7 @@
         assertTrue(callbackLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
     }
 
+    @Suppress // TODO(gsennton) remove @Suppress when b/76202025 has been resolved
     @Test
     public void testCheckThread() {
         try {
@@ -235,4 +238,22 @@
             Assert.fail("The privacy policy URL should be a well-formed URL");
         }
     }
+
+    /**
+     * WebViewCompat.getCurrentWebViewPackage should be null on pre-L devices.
+     * On L+ devices WebViewCompat.getCurrentWebViewPackage should be null only in exceptional
+     * circumstances - like when the WebView APK is being updated, or for Wear devices. The L+
+     * devices used in support library testing should have a non-null WebView package.
+     */
+    @Test
+    public void testGetCurrentWebViewPackage() {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+            assertNull(WebViewCompat.getCurrentWebViewPackage(
+                    InstrumentationRegistry.getTargetContext()));
+        } else {
+            assertNotNull(
+                    WebViewCompat.getCurrentWebViewPackage(
+                            InstrumentationRegistry.getTargetContext()));
+        }
+    }
 }
diff --git a/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java b/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
index 9b4c9e9..6e817c3 100644
--- a/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
+++ b/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
@@ -16,12 +16,42 @@
 
 package androidx.webkit;
 
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.graphics.Bitmap;
+import android.os.Looper;
+import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
 import android.webkit.WebSettings;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 
-public class WebViewOnUiThread {
+import java.util.concurrent.Callable;
+
+class WebViewOnUiThread {
+    /**
+     * The maximum time, in milliseconds (10 seconds) to wait for a load
+     * to be triggered.
+     */
+    private static final long LOAD_TIMEOUT = 10000;
+
+    /**
+     * Set to true after onPageFinished is called.
+     */
+    private boolean mLoaded;
+
+    /**
+     * The progress, in percentage, of the page load. Valid values are between
+     * 0 and 100.
+     */
+    private int mProgress;
+
+    /**
+     * The WebView that calls will be made on.
+     */
     private WebView mWebView;
 
     public WebViewOnUiThread() {
@@ -29,6 +59,8 @@
             @Override
             public void run() {
                 mWebView = new WebView(InstrumentationRegistry.getTargetContext());
+                mWebView.setWebViewClient(new WaitForLoadedClient(WebViewOnUiThread.this));
+                mWebView.setWebChromeClient(new WaitForProgressClient(WebViewOnUiThread.this));
             }
         });
     }
@@ -70,10 +102,208 @@
         });
     }
 
-    public WebView getWebViewOnCurrentThread() {
+    public void addJavascriptInterface(final Object object, final String name) {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.addJavascriptInterface(object, name);
+            }
+        });
+    }
+
+    /**
+     * Called after a test is complete and the WebView should be disengaged from
+     * the tests.
+     */
+    public void cleanUp() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.clearHistory();
+                mWebView.clearCache(true);
+                mWebView.setWebChromeClient(null);
+                mWebView.setWebViewClient(null);
+                mWebView.destroy();
+            }
+        });
+    }
+
+    WebView getWebViewOnCurrentThread() {
         return mWebView;
     }
 
+    /**
+     * Called from WaitForLoadedClient.
+     */
+    synchronized void onPageStarted() {}
+
+    /**
+     * Called from WaitForLoadedClient, this is used to indicate that
+     * the page is loaded, but not drawn yet.
+     */
+    synchronized void onPageFinished() {
+        mLoaded = true;
+        this.notifyAll();
+    }
+
+    /**
+     * Called from the WebChrome client, this sets the current progress
+     * for a page.
+     * @param progress The progress made so far between 0 and 100.
+     */
+    synchronized void onProgressChanged(int progress) {
+        mProgress = progress;
+        this.notifyAll();
+    }
+
+    /**
+     * Calls loadUrl on the WebView and then waits onPageFinished,
+     * onNewPicture and onProgressChange to reach 100.
+     * Test fails if the load timeout elapses.
+     * @param url The URL to load.
+     */
+    void loadUrlAndWaitForCompletion(final String url) {
+        callAndWait(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.loadUrl(url);
+            }
+        });
+    }
+
+    /**
+     * Use this only when JavaScript causes a page load to wait for the
+     * page load to complete. Otherwise use loadUrlAndWaitForCompletion or
+     * similar functions.
+     */
+    void waitForLoadCompletion() {
+        waitForCriteria(LOAD_TIMEOUT,
+                new Callable<Boolean>() {
+                    @Override
+                    public Boolean call() {
+                        return isLoaded();
+                    }
+                });
+        clearLoad();
+    }
+
+    private void waitForCriteria(long timeout, Callable<Boolean> doneCriteria) {
+        if (isUiThread()) {
+            waitOnUiThread(timeout, doneCriteria);
+        } else {
+            waitOnTestThread(timeout, doneCriteria);
+        }
+    }
+
+    void evaluateJavascript(final String script, final ValueCallback<String> result) {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.evaluateJavascript(script, result);
+            }
+        });
+    }
+
+    /**
+     * Returns true if the current thread is the UI thread based on the
+     * Looper.
+     */
+    private static boolean isUiThread() {
+        return (Looper.myLooper() == Looper.getMainLooper());
+    }
+
+    /**
+     * @return Whether or not the load has finished.
+     */
+    private synchronized boolean isLoaded() {
+        return mLoaded && mProgress == 100;
+    }
+
+    /**
+     * Makes a WebView call, waits for completion and then resets the
+     * load state in preparation for the next load call.
+     * @param call The call to make on the UI thread prior to waiting.
+     */
+    private void callAndWait(Runnable call) {
+        assertTrue("WebViewOnUiThread.load*AndWaitForCompletion calls "
+                        + "may not be mixed with load* calls directly on WebView "
+                        + "without calling waitForLoadCompletion after the load",
+                !isLoaded());
+        clearLoad(); // clear any extraneous signals from a previous load.
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(call);
+        waitForLoadCompletion();
+    }
+
+    /**
+     * Called whenever a load has been completed so that a subsequent call to
+     * waitForLoadCompletion doesn't return immediately.
+     */
+    private synchronized void clearLoad() {
+        mLoaded = false;
+        mProgress = 0;
+    }
+
+    /**
+     * Uses a polling mechanism, while pumping messages to check when the
+     * criteria is met.
+     */
+    private void waitOnUiThread(long timeout, final Callable<Boolean> doneCriteria) {
+        new PollingCheck(timeout) {
+            @Override
+            protected boolean check() {
+                pumpMessages();
+                try {
+                    return doneCriteria.call();
+                } catch (Exception e) {
+                    fail("Unexpected error while checking the criteria: " + e.getMessage());
+                    return true;
+                }
+            }
+        }.run();
+    }
+
+    /**
+     * Uses a wait/notify to check when the criteria is met.
+     */
+    private synchronized void waitOnTestThread(long timeout, Callable<Boolean> doneCriteria) {
+        try {
+            long waitEnd = SystemClock.uptimeMillis() + timeout;
+            long timeRemaining = timeout;
+            while (!doneCriteria.call() && timeRemaining > 0) {
+                this.wait(timeRemaining);
+                timeRemaining = waitEnd - SystemClock.uptimeMillis();
+            }
+            assertTrue("Action failed to complete before timeout", doneCriteria.call());
+        } catch (InterruptedException e) {
+            // We'll just drop out of the loop and fail
+        } catch (Exception e) {
+            fail("Unexpected error while checking the criteria: " + e.getMessage());
+        }
+    }
+
+    /**
+     * Pumps all currently-queued messages in the UI thread and then exits.
+     * This is useful to force processing while running tests in the UI thread.
+     */
+    private void pumpMessages() {
+        class ExitLoopException extends RuntimeException {
+        }
+
+        // Force loop to exit when processing this. Loop.quit() doesn't
+        // work because this is the main Loop.
+        mWebView.getHandler().post(new Runnable() {
+            @Override
+            public void run() {
+                throw new ExitLoopException(); // exit loop!
+            }
+        });
+        try {
+            // Pump messages until our message gets through.
+            Looper.loop();
+        } catch (ExitLoopException e) {
+        }
+    }
+
     private <T> T getValue(ValueGetter<T> getter) {
         InstrumentationRegistry.getInstrumentation().runOnMainSync(getter);
         return getter.getValue();
@@ -93,4 +323,51 @@
             return mValue;
         }
     }
+
+    /**
+     * A WebChromeClient used to capture the onProgressChanged for use
+     * in waitFor functions. If a test must override the WebChromeClient,
+     * it can derive from this class or call onProgressChanged
+     * directly.
+     */
+    public static class WaitForProgressClient extends WebChromeClient {
+        private WebViewOnUiThread mOnUiThread;
+
+        WaitForProgressClient(WebViewOnUiThread onUiThread) {
+            mOnUiThread = onUiThread;
+        }
+
+        @Override
+        public void onProgressChanged(WebView view, int newProgress) {
+            super.onProgressChanged(view, newProgress);
+            mOnUiThread.onProgressChanged(newProgress);
+        }
+    }
+
+    /**
+     * A WebViewClient that captures the onPageFinished for use in
+     * waitFor functions. Using initializeWebView sets the WaitForLoadedClient
+     * into the WebView. If a test needs to set a specific WebViewClient and
+     * needs the waitForCompletion capability then it should derive from
+     * WaitForLoadedClient or call WebViewOnUiThread.onPageFinished.
+     */
+    public static class WaitForLoadedClient extends WebViewClient {
+        private WebViewOnUiThread mOnUiThread;
+
+        WaitForLoadedClient(WebViewOnUiThread onUiThread) {
+            mOnUiThread = onUiThread;
+        }
+
+        @Override
+        public void onPageFinished(WebView view, String url) {
+            super.onPageFinished(view, url);
+            mOnUiThread.onPageFinished();
+        }
+
+        @Override
+        public void onPageStarted(WebView view, String url, Bitmap favicon) {
+            super.onPageStarted(view, url, favicon);
+            mOnUiThread.onPageStarted();
+        }
+    }
 }
diff --git a/webkit/src/main/java/androidx/webkit/ServiceWorkerClientCompat.java b/webkit/src/main/java/androidx/webkit/ServiceWorkerClientCompat.java
new file mode 100644
index 0000000..19aab8c
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/ServiceWorkerClientCompat.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 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 androidx.webkit;
+
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Base class for clients to capture Service Worker related callbacks,
+ * see {@link ServiceWorkerControllerCompat} for usage example.
+ */
+public abstract class ServiceWorkerClientCompat {
+    /**
+     *
+     * Notify the host application of a resource request and allow the
+     * application to return the data. If the return value is {@code null}, the
+     * Service Worker will continue to load the resource as usual.
+     * Otherwise, the return response and data will be used.
+     *
+     * <p class="note"><b>Note:</b> This method is called on a thread other than the UI thread so
+     * clients should exercise caution when accessing private data or the view system.
+     *
+     * @param request Object containing the details of the request.
+     * @return A {@link android.webkit.WebResourceResponse} containing the
+     * response information or {@code null} if the WebView should load the
+     * resource itself.
+     * @see android.webkit.WebViewClient#shouldInterceptRequest(android.webkit.WebView,
+     * WebResourceRequest)
+     *
+     */
+    public abstract WebResourceResponse shouldInterceptRequest(@NonNull WebResourceRequest request);
+}
diff --git a/webkit/src/main/java/androidx/webkit/ServiceWorkerControllerCompat.java b/webkit/src/main/java/androidx/webkit/ServiceWorkerControllerCompat.java
new file mode 100644
index 0000000..3eb55d2
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/ServiceWorkerControllerCompat.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2018 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 androidx.webkit;
+
+import android.os.Build;
+import android.webkit.ServiceWorkerController;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.webkit.internal.FrameworkServiceWorkerController;
+import androidx.webkit.internal.ServiceWorkerControllerAdapter;
+import androidx.webkit.internal.WebViewGlueCommunicator;
+
+// TODO(gsennton) guard APIs with isFeatureSupported(String)
+
+/**
+ * Manages Service Workers used by WebView.
+ *
+ * <p>Example usage:
+ * <pre class="prettyprint">
+ * ServiceWorkerControllerCompat swController = ServiceWorkerControllerCompat.getInstance();
+ * swController.setServiceWorkerClient(new ServiceWorkerClientCompat() {
+ *   {@literal @}Override
+ *   public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) {
+ *     // Capture request here and generate response or allow pass-through
+ *     // by returning null.
+ *     return null;
+ *   }
+ * });
+ * </pre>
+ */
+public abstract class ServiceWorkerControllerCompat {
+    /**
+     *
+     * @hide Don't allow apps to sub-class this class.
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public ServiceWorkerControllerCompat() {}
+
+    /**
+     * Returns the default ServiceWorkerController instance. At present there is
+     * only one ServiceWorkerController instance for all WebView instances,
+     * however this restriction may be relaxed in the future.
+     *
+     * @return the default ServiceWorkerController instance
+     */
+    @NonNull
+    public static ServiceWorkerControllerCompat getInstance() {
+        return LAZY_HOLDER.INSTANCE;
+    }
+
+    private static class LAZY_HOLDER {
+        static final ServiceWorkerControllerCompat INSTANCE =
+                Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
+                        ? getFrameworkControllerCompat() : getSupportLibraryControllerCompat();
+    }
+
+    /**
+     * Return a version of {@link ServiceWorkerControllerCompat} that only uses framework APIs.
+     */
+    @RequiresApi(Build.VERSION_CODES.N)
+    private static ServiceWorkerControllerCompat getFrameworkControllerCompat() {
+        return new FrameworkServiceWorkerController(
+                ServiceWorkerController.getInstance());
+    }
+
+    private static ServiceWorkerControllerCompat getSupportLibraryControllerCompat() {
+        return new ServiceWorkerControllerAdapter(
+                WebViewGlueCommunicator.getFactory().getServiceWorkerController());
+    }
+
+    /**
+     *
+     * Gets the settings for all service workers.
+     *
+     * @return the current {@link ServiceWorkerWebSettingsCompat}
+     *
+     */
+    @NonNull
+    public abstract ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings();
+
+    /**
+     *
+     * Sets the client to capture service worker related callbacks.
+     *
+     * A {@link ServiceWorkerClientCompat} should be set before any service workers are
+     * active, e.g. a safe place is before any WebView instances are created or
+     * pages loaded.
+     *
+     */
+    public abstract void setServiceWorkerClient(@Nullable ServiceWorkerClientCompat client);
+}
diff --git a/webkit/src/main/java/androidx/webkit/ServiceWorkerWebSettingsCompat.java b/webkit/src/main/java/androidx/webkit/ServiceWorkerWebSettingsCompat.java
new file mode 100644
index 0000000..61c46c3
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/ServiceWorkerWebSettingsCompat.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2018 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 androidx.webkit;
+
+import android.webkit.WebSettings;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.RestrictTo;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Manages settings state for all Service Workers. These settings are not tied to
+ * the lifetime of any WebView because service workers can outlive WebView instances.
+ * The settings are similar to {@link WebSettings} but only settings relevant to
+ * Service Workers are supported.
+ */
+public abstract class ServiceWorkerWebSettingsCompat {
+    /**
+     * @hide Don't allow apps to sub-class this class.
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public ServiceWorkerWebSettingsCompat() {}
+
+    /** @hide */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @IntDef(value = {
+            WebSettings.LOAD_DEFAULT,
+            WebSettings.LOAD_CACHE_ELSE_NETWORK,
+            WebSettings.LOAD_NO_CACHE,
+            WebSettings.LOAD_CACHE_ONLY
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CacheMode {}
+
+    /**
+     *
+     * Overrides the way the cache is used, see {@link WebSettings#setCacheMode}.
+     *
+     * @param mode the mode to use. One of {@link WebSettings#LOAD_DEFAULT},
+     * {@link WebSettings#LOAD_CACHE_ELSE_NETWORK}, {@link WebSettings#LOAD_NO_CACHE}
+     * or {@link WebSettings#LOAD_CACHE_ONLY}. The default value is
+     * {@link WebSettings#LOAD_DEFAULT}.
+     *
+     */
+    public abstract void setCacheMode(@CacheMode int mode);
+
+    /**
+     *
+     * Gets the current setting for overriding the cache mode.
+     *
+     * @return the current setting for overriding the cache mode
+     * @see #setCacheMode
+     *
+     */
+    public abstract @CacheMode int getCacheMode();
+
+    /**
+     *
+     * Enables or disables content URL access from Service Workers, see
+     * {@link WebSettings#setAllowContentAccess}.
+     *
+     */
+    public abstract void setAllowContentAccess(boolean allow);
+
+    /**
+     *
+     * Gets whether Service Workers support content URL access.
+     *
+     * @see #setAllowContentAccess
+     *
+     */
+    public abstract boolean getAllowContentAccess();
+
+    /**
+     *
+     * Enables or disables file access within Service Workers, see
+     * {@link WebSettings#setAllowFileAccess}.
+     *
+     */
+    public abstract void setAllowFileAccess(boolean allow);
+
+    /**
+     *
+     * Gets whether Service Workers support file access.
+     *
+     * @see #setAllowFileAccess
+     *
+     */
+    public abstract boolean getAllowFileAccess();
+
+    /**
+     *
+     * Sets whether Service Workers should not load resources from the network,
+     * see {@link WebSettings#setBlockNetworkLoads}.
+     *
+     * @param flag {@code true} means block network loads by the Service Workers
+     *
+     */
+    public abstract void setBlockNetworkLoads(boolean flag);
+
+    /**
+     *
+     * Gets whether Service Workers are prohibited from loading any resources from the network.
+     *
+     * @return {@code true} if the Service Workers are not allowed to load any resources from the
+     * network
+     * @see #setBlockNetworkLoads
+     *
+     */
+    public abstract boolean getBlockNetworkLoads();
+}
diff --git a/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java b/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
index c73cda6..12d7e63 100644
--- a/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
+++ b/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
@@ -19,6 +19,13 @@
 import android.os.Build;
 import android.webkit.WebSettings;
 
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.RestrictTo;
 import androidx.webkit.internal.WebSettingsAdapter;
 import androidx.webkit.internal.WebViewGlueCommunicator;
 
@@ -102,10 +109,25 @@
     }
 
     /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @IntDef(flag = true, value = {
+            WebSettings.MENU_ITEM_NONE,
+            WebSettings.MENU_ITEM_SHARE,
+            WebSettings.MENU_ITEM_WEB_SEARCH,
+            WebSettings.MENU_ITEM_PROCESS_TEXT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @Target({ElementType.PARAMETER, ElementType.METHOD})
+    public @interface MenuItemFlags {}
+
+    /**
      * Disables the action mode menu items according to {@code menuItems} flag.
      * @param menuItems an integer field flag for the menu items to be disabled.
      */
-    public static void setDisabledActionModeMenuItems(WebSettings webSettings, int menuItems) {
+    public static void setDisabledActionModeMenuItems(WebSettings webSettings,
+            @MenuItemFlags int menuItems) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
             webSettings.setDisabledActionModeMenuItems(menuItems);
         } else {
@@ -119,7 +141,7 @@
      *
      * @return all the disabled menu item flags combined with bitwise OR.
      */
-    public static int getDisabledActionModeMenuItems(WebSettings webSettings) {
+    public static @MenuItemFlags int getDisabledActionModeMenuItems(WebSettings webSettings) {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
             return webSettings.getDisabledActionModeMenuItems();
         } else {
diff --git a/webkit/src/main/java/androidx/webkit/WebViewCompat.java b/webkit/src/main/java/androidx/webkit/WebViewCompat.java
index 6a48e35..45def2e 100644
--- a/webkit/src/main/java/androidx/webkit/WebViewCompat.java
+++ b/webkit/src/main/java/androidx/webkit/WebViewCompat.java
@@ -17,6 +17,8 @@
 package androidx.webkit;
 
 import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Looper;
@@ -25,7 +27,9 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.RequiresFeature;
 import androidx.core.os.BuildCompat;
+import androidx.webkit.internal.WebViewFeatureInternal;
 import androidx.webkit.internal.WebViewGlueCommunicator;
 import androidx.webkit.internal.WebViewProviderAdapter;
 import androidx.webkit.internal.WebViewProviderFactoryAdapter;
@@ -104,13 +108,22 @@
      * {@link android.webkit.WebSettings#setOffscreenPreRaster} for more details and do consider its
      * caveats.
      *
+     * This method should only be called if
+     * {@link WebViewFeature#isFeatureSupported(String)}
+     * returns true for {@link WebViewFeature#VISUAL_STATE_CALLBACK}.
+     *
      * @param requestId An id that will be returned in the callback to allow callers to match
      *                  requests with callbacks.
      * @param callback  The callback to be invoked.
      */
+    @SuppressWarnings("NewApi")
+    @RequiresFeature(name = WebViewFeature.VISUAL_STATE_CALLBACK,
+            enforcement = "androidx.webkit.WebViewFeature#isFeatureSupported")
     public static void postVisualStateCallback(@NonNull WebView webview, long requestId,
             @NonNull final VisualStateCallback callback) {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+        WebViewFeatureInternal webViewFeature =
+                WebViewFeatureInternal.getFeature(WebViewFeature.VISUAL_STATE_CALLBACK);
+        if (webViewFeature.isSupportedByFramework()) {
             webview.postVisualStateCallback(requestId,
                     new android.webkit.WebView.VisualStateCallback() {
                         @Override
@@ -118,10 +131,11 @@
                             callback.onComplete(l);
                         }
                     });
-        } else {
-            // TODO(gsennton): guard with if WebViewApk.hasFeature(POSTVISUALSTATECALLBACK)
+        } else if (webViewFeature.isSupportedByWebView()) {
             checkThread(webview);
             getProvider(webview).insertVisualStateCallback(requestId, callback);
+        } else {
+            WebViewFeatureInternal.throwUnsupportedOperationException("postVisualStateCallback");
         }
     }
 
@@ -198,6 +212,92 @@
         }
     }
 
+    /**
+     * If WebView has already been loaded into the current process this method will return the
+     * package that was used to load it. Otherwise, the package that would be used if the WebView
+     * was loaded right now will be returned; this does not cause WebView to be loaded, so this
+     * information may become outdated at any time.
+     * The WebView package changes either when the current WebView package is updated, disabled, or
+     * uninstalled. It can also be changed through a Developer Setting.
+     * If the WebView package changes, any app process that has loaded WebView will be killed. The
+     * next time the app starts and loads WebView it will use the new WebView package instead.
+     * @return the current WebView package, or {@code null} if there is none.
+     */
+    // Note that this API is not protected by a {@link androidx.webkit.WebViewFeature} since
+    // this feature is not dependent on the WebView APK.
+    @Nullable
+    public static PackageInfo getCurrentWebViewPackage(@NonNull Context context) {
+        // There was no WebView Package before Lollipop, the WebView code was part of the framework
+        // back then.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+            return null;
+        }
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            return WebView.getCurrentWebViewPackage();
+        } else { // L-N
+            try {
+                PackageInfo loadedWebViewPackageInfo = getLoadedWebViewPackageInfo();
+                if (loadedWebViewPackageInfo != null) return loadedWebViewPackageInfo;
+            } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException
+                | NoSuchMethodException  e) {
+                return null;
+            }
+
+            // If WebViewFactory.getLoadedPackageInfo() returns null then WebView hasn't been loaded
+            // yet, in that case we need to fetch the name of the WebView package, and fetch the
+            // corresponding PackageInfo through the PackageManager
+            return getNotYetLoadedWebViewPackageInfo(context);
+        }
+    }
+
+    /**
+     * Return the PackageInfo of the currently loaded WebView APK. This method uses reflection and
+     * propagates any exceptions thrown, to the caller.
+     */
+    private static PackageInfo getLoadedWebViewPackageInfo()
+            throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
+            IllegalAccessException {
+        Class webViewFactoryClass = Class.forName("android.webkit.WebViewFactory");
+        PackageInfo webviewPackageInfo =
+                (PackageInfo) webViewFactoryClass.getMethod(
+                        "getLoadedPackageInfo").invoke(null);
+        return webviewPackageInfo;
+    }
+
+    /**
+     * Return the PackageInfo of the WebView APK that would have been used as WebView implementation
+     * if WebView was to be loaded right now.
+     */
+    private static PackageInfo getNotYetLoadedWebViewPackageInfo(Context context) {
+        String webviewPackageName = null;
+        try {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
+                    && Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
+                Class webViewFactoryClass = null;
+                webViewFactoryClass = Class.forName("android.webkit.WebViewFactory");
+
+                webviewPackageName = (String) webViewFactoryClass.getMethod(
+                        "getWebViewPackageName").invoke(null);
+            } else {
+                Class webviewUpdateServiceClass =
+                        Class.forName("android.webkit.WebViewUpdateService");
+                webviewPackageName = (String) webviewUpdateServiceClass.getMethod(
+                        "getCurrentWebViewPackageName").invoke(null);
+            }
+        } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException
+                | NoSuchMethodException  e) {
+            return null;
+        }
+        if (webviewPackageName == null) return null;
+        PackageManager pm = context.getPackageManager();
+        try {
+            return pm.getPackageInfo(webviewPackageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            return null;
+        }
+    }
+
     private static WebViewProviderAdapter getProvider(WebView webview) {
         return new WebViewProviderAdapter(createProvider(webview));
     }
diff --git a/webkit/src/main/java/androidx/webkit/WebViewFeature.java b/webkit/src/main/java/androidx/webkit/WebViewFeature.java
new file mode 100644
index 0000000..d514477
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/WebViewFeature.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018 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 androidx.webkit;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.StringDef;
+import androidx.webkit.internal.WebViewFeatureInternal;
+
+import org.chromium.support_lib_boundary.util.Features;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Utility class for checking which WebView Support Library features are supported on the device.
+ */
+public class WebViewFeature {
+
+    private WebViewFeature() {}
+
+    /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @StringDef(value = {
+            VISUAL_STATE_CALLBACK,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @Target({ElementType.PARAMETER, ElementType.METHOD})
+    public @interface WebViewSupportFeature {}
+
+    /**
+     * Feature for {@link #isFeatureSupported(String)}.
+     * This feature covers
+     * {@link androidx.webkit.WebViewCompat#postVisualStateCallback(android.webkit.WebView, long,
+     * WebViewCompat.VisualStateCallback)}.
+     */
+    public static final String VISUAL_STATE_CALLBACK = Features.VISUAL_STATE_CALLBACK;
+
+    /**
+     * Return whether a feature is supported at run-time. This depends on the Android version of the
+     * device and the WebView APK on the device.
+     */
+    public static boolean isFeatureSupported(@NonNull @WebViewSupportFeature String feature) {
+        WebViewFeatureInternal webviewFeature = WebViewFeatureInternal.getFeature(feature);
+        return webviewFeature.isSupportedByFramework() || webviewFeature.isSupportedByWebView();
+    }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/FrameworkServiceWorkerClient.java b/webkit/src/main/java/androidx/webkit/internal/FrameworkServiceWorkerClient.java
new file mode 100644
index 0000000..c28346e
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/FrameworkServiceWorkerClient.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 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 androidx.webkit.internal;
+
+import android.os.Build;
+import android.webkit.ServiceWorkerClient;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
+
+import androidx.annotation.RequiresApi;
+import androidx.webkit.ServiceWorkerClientCompat;
+
+/**
+ * A shim class that implements {@link ServiceWorkerClient} by delegating to a
+ * {@link ServiceWorkerClientCompat}.
+ * This class is used on up-to-date devices to avoid using reflection to call into WebView APK code.
+ */
+@RequiresApi(Build.VERSION_CODES.N)
+public class FrameworkServiceWorkerClient extends ServiceWorkerClient {
+    private final ServiceWorkerClientCompat mImpl;
+
+    public FrameworkServiceWorkerClient(ServiceWorkerClientCompat impl) {
+        mImpl = impl;
+    }
+
+    @Override
+    public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) {
+        return mImpl.shouldInterceptRequest(request);
+    }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/FrameworkServiceWorkerController.java b/webkit/src/main/java/androidx/webkit/internal/FrameworkServiceWorkerController.java
new file mode 100644
index 0000000..2e02777
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/FrameworkServiceWorkerController.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 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 androidx.webkit.internal;
+
+import android.os.Build;
+import android.webkit.ServiceWorkerController;
+
+import androidx.annotation.RequiresApi;
+import androidx.webkit.ServiceWorkerClientCompat;
+import androidx.webkit.ServiceWorkerControllerCompat;
+import androidx.webkit.ServiceWorkerWebSettingsCompat;
+
+/**
+ * Implementation of {@link ServiceWorkerControllerCompat} meant for use on up-to-date platforms.
+ * This class does not use reflection to bypass framework APIs - instead it uses android.webkit
+ * APIs.
+ */
+@RequiresApi(Build.VERSION_CODES.N)
+public class FrameworkServiceWorkerController extends ServiceWorkerControllerCompat {
+    private final ServiceWorkerController mImpl;
+    private ServiceWorkerWebSettingsCompat mSettings;
+
+    public FrameworkServiceWorkerController(ServiceWorkerController impl) {
+        mImpl = impl;
+    }
+
+    @Override
+    public ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings() {
+        if (mSettings == null) {
+            mSettings = new FrameworksServiceWorkerWebSettings(mImpl.getServiceWorkerWebSettings());
+        }
+        return mSettings;
+    }
+
+    @Override
+    public void setServiceWorkerClient(ServiceWorkerClientCompat client) {
+        mImpl.setServiceWorkerClient(new FrameworkServiceWorkerClient(client));
+    }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/FrameworksServiceWorkerWebSettings.java b/webkit/src/main/java/androidx/webkit/internal/FrameworksServiceWorkerWebSettings.java
new file mode 100644
index 0000000..4373756
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/FrameworksServiceWorkerWebSettings.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2018 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 androidx.webkit.internal;
+
+import android.os.Build;
+import android.webkit.ServiceWorkerWebSettings;
+
+import androidx.annotation.RequiresApi;
+import androidx.webkit.ServiceWorkerWebSettingsCompat;
+
+/**
+ * Implementation of {@link ServiceWorkerWebSettingsCompat} meant for use on up-to-date platforms.
+ * This class does not use reflection to bypass framework APIs - instead it uses android.webkit
+ * APIs.
+ */
+@RequiresApi(Build.VERSION_CODES.N)
+public class FrameworksServiceWorkerWebSettings extends ServiceWorkerWebSettingsCompat {
+    private final ServiceWorkerWebSettings mImpl;
+
+    public FrameworksServiceWorkerWebSettings(ServiceWorkerWebSettings impl) {
+        mImpl = impl;
+    }
+
+    @Override
+    public void setCacheMode(int mode) {
+        mImpl.setCacheMode(mode);
+    }
+
+    @Override
+    public int getCacheMode() {
+        return mImpl.getCacheMode();
+    }
+
+    @Override
+    public void setAllowContentAccess(boolean allow) {
+        mImpl.setAllowContentAccess(allow);
+    }
+
+    @Override
+    public boolean getAllowContentAccess() {
+        return mImpl.getAllowContentAccess();
+    }
+
+    @Override
+    public void setAllowFileAccess(boolean allow) {
+        mImpl.setAllowContentAccess(allow);
+    }
+
+    @Override
+    public boolean getAllowFileAccess() {
+        return mImpl.getAllowFileAccess();
+    }
+
+    @Override
+    public void setBlockNetworkLoads(boolean flag) {
+        mImpl.setAllowContentAccess(flag);
+    }
+
+    @Override
+    public boolean getBlockNetworkLoads() {
+        return mImpl.getBlockNetworkLoads();
+    }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerClientAdapter.java b/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerClientAdapter.java
new file mode 100644
index 0000000..3ffeb83
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerClientAdapter.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2018 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 androidx.webkit.internal;
+
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
+
+import androidx.webkit.ServiceWorkerClientCompat;
+
+import org.chromium.support_lib_boundary.ServiceWorkerClientBoundaryInterface;
+
+/**
+ * Adapter between {@link ServiceWorkerClientCompat} and
+ * {@link ServiceWorkerClientBoundaryInterface} (the corresponding interface shared with the support
+ * library glue in the WebView APK).
+ */
+public class ServiceWorkerClientAdapter implements ServiceWorkerClientBoundaryInterface {
+    private final ServiceWorkerClientCompat mClient;
+
+    public ServiceWorkerClientAdapter(ServiceWorkerClientCompat client) {
+        mClient = client;
+    }
+
+    @Override
+    public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) {
+        return mClient.shouldInterceptRequest(request);
+    }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerControllerAdapter.java b/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerControllerAdapter.java
new file mode 100644
index 0000000..4baa3ea
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerControllerAdapter.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 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 androidx.webkit.internal;
+
+import androidx.webkit.ServiceWorkerClientCompat;
+import androidx.webkit.ServiceWorkerControllerCompat;
+import androidx.webkit.ServiceWorkerWebSettingsCompat;
+
+import org.chromium.support_lib_boundary.ServiceWorkerControllerBoundaryInterface;
+import org.chromium.support_lib_boundary.ServiceWorkerWebSettingsBoundaryInterface;
+import org.chromium.support_lib_boundary.util.BoundaryInterfaceReflectionUtil;
+
+/**
+ * Adapter between {@link ServiceWorkerControllerCompat} and
+ * {@link ServiceWorkerControllerBoundaryInterface} (the corresponding interface shared with the
+ * support library glue in the WebView APK).
+ */
+public class ServiceWorkerControllerAdapter extends ServiceWorkerControllerCompat {
+    private final ServiceWorkerControllerBoundaryInterface mImpl;
+    private final ServiceWorkerWebSettingsCompat mWebSettings;
+
+    public ServiceWorkerControllerAdapter(ServiceWorkerControllerBoundaryInterface impl) {
+        mImpl = impl;
+        mWebSettings = new ServiceWorkerWebSettingsAdapter(
+                BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+                        ServiceWorkerWebSettingsBoundaryInterface.class,
+                        mImpl.getServiceWorkerWebSettings()));
+    }
+
+    @Override
+    public ServiceWorkerWebSettingsCompat getServiceWorkerWebSettings() {
+        return mWebSettings;
+    }
+
+    @Override
+    public void setServiceWorkerClient(ServiceWorkerClientCompat client) {
+        mImpl.setServiceWorkerClient(BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(
+                new ServiceWorkerClientAdapter(client)));
+    }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerWebSettingsAdapter.java b/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerWebSettingsAdapter.java
new file mode 100644
index 0000000..fd49396
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/ServiceWorkerWebSettingsAdapter.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2018 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 androidx.webkit.internal;
+
+import androidx.webkit.ServiceWorkerWebSettingsCompat;
+
+import org.chromium.support_lib_boundary.ServiceWorkerWebSettingsBoundaryInterface;
+
+/**
+ * Adapter between {@link ServiceWorkerWebSettingsCompat} and
+ * {@link ServiceWorkerWebSettingsBoundaryInterface} (the corresponding interface shared with the
+ * support library glue in the WebView APK).
+ */
+public class ServiceWorkerWebSettingsAdapter extends ServiceWorkerWebSettingsCompat {
+    private final ServiceWorkerWebSettingsBoundaryInterface mImpl;
+
+    public ServiceWorkerWebSettingsAdapter(ServiceWorkerWebSettingsBoundaryInterface impl) {
+        mImpl = impl;
+    }
+
+    @Override
+    public void setCacheMode(int mode) {
+        mImpl.setCacheMode(mode);
+    }
+
+    @Override
+    public int getCacheMode() {
+        return mImpl.getCacheMode();
+    }
+
+    @Override
+    public void setAllowContentAccess(boolean allow) {
+        mImpl.setAllowContentAccess(allow);
+    }
+
+    @Override
+    public boolean getAllowContentAccess() {
+        return mImpl.getAllowContentAccess();
+    }
+
+    @Override
+    public void setAllowFileAccess(boolean allow) {
+        mImpl.setAllowFileAccess(allow);
+    }
+
+    @Override
+    public boolean getAllowFileAccess() {
+        return mImpl.getAllowFileAccess();
+    }
+
+    @Override
+    public void setBlockNetworkLoads(boolean flag) {
+        mImpl.setBlockNetworkLoads(flag);
+    }
+
+    @Override
+    public boolean getBlockNetworkLoads() {
+        return mImpl.getBlockNetworkLoads();
+    }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/SupportLibraryInfo.java b/webkit/src/main/java/androidx/webkit/internal/SupportLibraryInfo.java
new file mode 100644
index 0000000..da8a02c
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/SupportLibraryInfo.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018 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 androidx.webkit.internal;
+
+import org.chromium.support_lib_boundary.SupportLibraryInfoBoundaryInterface;
+import org.chromium.support_lib_boundary.util.Features;
+
+/**
+ * Contains information about the Android Support Library part of the WebView Support Library - this
+ * information is passed to the WebView APK code with the first WebView Support Library call.
+ */
+public class SupportLibraryInfo implements SupportLibraryInfoBoundaryInterface {
+    // Features supported by the support library itself (regardless of what the WebView APK
+    // supports).
+    private static final String[] SUPPORTED_FEATURES =
+            new String[] {
+                    Features.VISUAL_STATE_CALLBACK
+            };
+
+    @Override
+    public String[] getSupportedFeatures() {
+        return SUPPORTED_FEATURES;
+    }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewFeatureInternal.java b/webkit/src/main/java/androidx/webkit/internal/WebViewFeatureInternal.java
new file mode 100644
index 0000000..d16713c
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewFeatureInternal.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2018 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 androidx.webkit.internal;
+
+import android.os.Build;
+
+import androidx.webkit.WebViewFeature;
+import androidx.webkit.WebViewFeature.WebViewSupportFeature;
+
+/**
+ * Enum representing a WebView feature, this provides functionality for determining whether a
+ * feature is supported by the current framework and/or WebView APK.
+ */
+public enum WebViewFeatureInternal {
+    /**
+     * This feature covers
+     * {@link androidx.webkit.WebViewCompat#postVisualStateCallback(android.webkit.WebView, long,
+     * androidx.webkit.WebViewCompat.VisualStateCallback)}.
+     */
+    VISUAL_STATE_CALLBACK_FEATURE(WebViewFeature.VISUAL_STATE_CALLBACK, Build.VERSION_CODES.M);
+
+    private final String mFeatureValue;
+    private final int mOsVersion;
+
+    WebViewFeatureInternal(@WebViewSupportFeature String featureValue, int osVersion) {
+        mFeatureValue = featureValue;
+        mOsVersion = osVersion;
+    }
+
+    /**
+     * Return the {@link WebViewFeatureInternal} corresponding to {@param feature}.
+     */
+    public static WebViewFeatureInternal getFeature(@WebViewSupportFeature String feature) {
+        switch (feature) {
+            case WebViewFeature.VISUAL_STATE_CALLBACK:
+                return VISUAL_STATE_CALLBACK_FEATURE;
+            default:
+                throw new RuntimeException("Unknown feature " + feature);
+        }
+    }
+
+    /**
+     * Return whether this {@link WebViewFeature} is supported by the framework of the current
+     * device.
+     */
+    public boolean isSupportedByFramework() {
+        return Build.VERSION.SDK_INT >= mOsVersion;
+    }
+
+    /**
+     * Return whether this {@link WebViewFeature} is supported by the current WebView APK.
+     */
+    public boolean isSupportedByWebView() {
+        String[] webviewFeatures = LAZY_HOLDER.WEBVIEW_APK_FEATURES;
+        for (String webviewFeature : webviewFeatures) {
+            if (webviewFeature.equals(mFeatureValue)) return true;
+        }
+        return false;
+    }
+
+    private static class LAZY_HOLDER {
+        static final String[] WEBVIEW_APK_FEATURES =
+                WebViewGlueCommunicator.getFactory().getWebViewFeatures();
+    }
+
+    /**
+     * Utility method for throwing an exception explaining that the feature the app trying to use
+     * isn't supported.
+     */
+    public static void throwUnsupportedOperationException(String feature) {
+        throw new UnsupportedOperationException("Feature " + feature
+                + " is not supported by the current version of the framework and WebView APK");
+    }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java b/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
index 1325ed0..22cc1f4 100644
--- a/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
@@ -61,10 +61,14 @@
             Class<?> glueFactoryProviderFetcherClass = Class.forName(
                     GLUE_FACTORY_PROVIDER_FETCHER_CLASS, false, getWebViewClassLoader());
             Method createProviderFactoryMethod = glueFactoryProviderFetcherClass.getDeclaredMethod(
-                    GLUE_FACTORY_PROVIDER_FETCHER_METHOD);
-            return (InvocationHandler) createProviderFactoryMethod.invoke(null);
+                    GLUE_FACTORY_PROVIDER_FETCHER_METHOD, InvocationHandler.class);
+            return (InvocationHandler) createProviderFactoryMethod.invoke(null,
+                    BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(
+                            new SupportLibraryInfo()));
         } catch (IllegalAccessException | InvocationTargetException | ClassNotFoundException
                 | NoSuchMethodException e) {
+            // TODO(gsennton) if this happens we should avoid throwing an exception! And probably
+            // declare that the list of features supported by the WebView APK is empty.
             throw new RuntimeException(e);
         }
     }
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
index 62ce41e..efe0e64 100644
--- a/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
@@ -18,6 +18,7 @@
 
 import android.webkit.WebView;
 
+import org.chromium.support_lib_boundary.ServiceWorkerControllerBoundaryInterface;
 import org.chromium.support_lib_boundary.StaticsBoundaryInterface;
 import org.chromium.support_lib_boundary.WebViewProviderBoundaryInterface;
 import org.chromium.support_lib_boundary.WebViewProviderFactoryBoundaryInterface;
@@ -63,4 +64,20 @@
         return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
                 StaticsBoundaryInterface.class, mImpl.getStatics());
     }
+
+    /**
+     * Adapter method for fetching the features supported by the current WebView APK.
+     */
+    public String[] getWebViewFeatures() {
+        return mImpl.getSupportedFeatures();
+    }
+
+    /**
+     * Adapter method for fetching the support library class representing
+     * {@link android.webkit.ServiceWorkerController}.
+     */
+    public ServiceWorkerControllerBoundaryInterface getServiceWorkerController() {
+        return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+                ServiceWorkerControllerBoundaryInterface.class, mImpl.getServiceWorkerController());
+    }
 }