Merge "Fix the sample for SaveableStateHolder" into androidx-main
diff --git a/activity/activity-compose/src/androidTest/java/androidx/activity/compose/ActivityResultRegistryTest.kt b/activity/activity-compose/src/androidTest/java/androidx/activity/compose/ActivityResultRegistryTest.kt
index 84d3ec1..203b808 100644
--- a/activity/activity-compose/src/androidTest/java/androidx/activity/compose/ActivityResultRegistryTest.kt
+++ b/activity/activity-compose/src/androidTest/java/androidx/activity/compose/ActivityResultRegistryTest.kt
@@ -16,6 +16,7 @@
 
 package androidx.activity.compose
 
+import android.app.Activity.RESULT_OK
 import android.content.Intent
 import androidx.activity.ComponentActivity
 import androidx.activity.result.ActivityResultLauncher
@@ -23,16 +24,22 @@
 import androidx.activity.result.ActivityResultRegistryOwner
 import androidx.activity.result.contract.ActivityResultContract
 import androidx.activity.result.contract.ActivityResultContracts
+import androidx.compose.material.Button
+import androidx.compose.material.Text
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
 import androidx.core.app.ActivityOptionsCompat
 import androidx.lifecycle.Lifecycle
 import androidx.test.core.app.ActivityScenario
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Assert.fail
 import org.junit.Rule
@@ -109,4 +116,95 @@
                 .isEqualTo(1)
         }
     }
+
+    @Test
+    fun testRegisterForActivityResultOnResult() {
+        var counter = 0
+        var code = 0
+        val registry = object : ActivityResultRegistry() {
+            override fun <I : Any?, O : Any?> onLaunch(
+                requestCode: Int,
+                contract: ActivityResultContract<I, O>,
+                input: I,
+                options: ActivityOptionsCompat?
+            ) {
+                code = requestCode
+                launchCount++
+            }
+        }
+        val owner = ActivityResultRegistryOwner { registry }
+        composeTestRule.setContent {
+            var recompose by remember { mutableStateOf(false) }
+            CompositionLocalProvider(
+                LocalActivityResultRegistryOwner provides owner
+            ) {
+                @Suppress("ControlFlowWithEmptyBody") // triggering recompose
+                if (recompose) { }
+                val launcher = registerForActivityResult(
+                    ActivityResultContracts.StartActivityForResult()
+                ) {
+                    counter++
+                }
+                Button(
+                    onClick = {
+                        launcher.launch(null)
+                        recompose = true
+                    }
+                ) {
+                    Text(text = "Launch")
+                }
+            }
+        }
+
+        composeTestRule.onNodeWithText("Launch").performClick()
+        composeTestRule.runOnIdle {
+            registry.dispatchResult(code, RESULT_OK, Intent())
+            assertThat(counter).isEqualTo(1)
+        }
+    }
+
+    @Test
+    fun testRegisterForActivityResultOnResultSameContract() {
+        var counter = 0
+        var code = 0
+        val registry = object : ActivityResultRegistry() {
+            override fun <I : Any?, O : Any?> onLaunch(
+                requestCode: Int,
+                contract: ActivityResultContract<I, O>,
+                input: I,
+                options: ActivityOptionsCompat?
+            ) {
+                code = requestCode
+                launchCount++
+            }
+        }
+        val owner = ActivityResultRegistryOwner { registry }
+        val contract = ActivityResultContracts.StartActivityForResult()
+        composeTestRule.setContent {
+            var recompose by remember { mutableStateOf(false) }
+            CompositionLocalProvider(
+                LocalActivityResultRegistryOwner provides owner
+            ) {
+                @Suppress("ControlFlowWithEmptyBody") // triggering recompose
+                if (recompose) { }
+                val launcher = registerForActivityResult(contract) {
+                    counter++
+                }
+                Button(
+                    onClick = {
+                        launcher.launch(null)
+                        recompose = true
+                    }
+                ) {
+                    Text(text = "Launch")
+                }
+            }
+        }
+
+        composeTestRule.onNodeWithText("Launch").performClick()
+        composeTestRule.runOnIdle {
+            registry.dispatchResult(code, RESULT_OK, Intent())
+            assertThat(counter).isEqualTo(1)
+        }
+    }
 }
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LayoutInflaterFactoryTestCase.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LayoutInflaterFactoryTestCase.java
index 1b0a1da..15d4194 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LayoutInflaterFactoryTestCase.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/LayoutInflaterFactoryTestCase.java
@@ -92,6 +92,16 @@
     @UiThreadTest
     @Test
     @SmallTest
+    public void testAndroidThemeWithIncludeInflation() {
+        LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
+        final ViewGroup root = (ViewGroup) inflater.inflate(
+                R.layout.layout_android_theme_with_include, null);
+        assertThemedContext(root.findViewById(R.id.included_view));
+    }
+
+    @UiThreadTest
+    @Test
+    @SmallTest
     public void testThemedInflationWithUnattachedParent() {
         final Context activity = mActivityTestRule.getActivity();
 
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateRecreatesActivityWithConfigTestCase.kt b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateRecreatesActivityWithConfigTestCase.kt
index 9a73838..f3e217c 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateRecreatesActivityWithConfigTestCase.kt
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/app/NightModeRotateRecreatesActivityWithConfigTestCase.kt
@@ -28,6 +28,7 @@
 import androidx.lifecycle.Lifecycle
 import androidx.test.espresso.Espresso.onView
 import androidx.test.espresso.matcher.ViewMatchers
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.LargeTest
 import androidx.testutils.LifecycleOwnerUtils
 import org.junit.After
@@ -59,6 +60,7 @@
         }
     }
 
+    @FlakyTest // b/182209264
     @Test
     public fun testRotateRecreatesActivityWithConfig() {
         // Don't run this test on SDK 26 because it has issues with setRequestedOrientation. Also
diff --git a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatEditTextReceiveContentTest.java b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatEditTextReceiveContentTest.java
index 3fc3605..b532d36 100644
--- a/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatEditTextReceiveContentTest.java
+++ b/appcompat/appcompat/src/androidTest/java/androidx/appcompat/widget/AppCompatEditTextReceiveContentTest.java
@@ -40,6 +40,7 @@
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Parcelable;
 import android.text.SpannableStringBuilder;
 import android.view.DragEvent;
 import android.view.inputmethod.EditorInfo;
@@ -525,7 +526,9 @@
         }
         EditorInfo editorInfo = new EditorInfo();
         InputConnection ic = mEditText.onCreateInputConnection(editorInfo);
-        return InputConnectionCompat.commitContent(ic, editorInfo, contentInfo, 0, opts);
+        int flags = (Build.VERSION.SDK_INT >= 25)
+                ? InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION : 0;
+        return InputConnectionCompat.commitContent(ic, editorInfo, contentInfo, flags, opts);
     }
 
     private boolean triggerImeCommitContentDirect(String mimeType) {
@@ -535,7 +538,9 @@
                 null);
         EditorInfo editorInfo = new EditorInfo();
         InputConnection ic = mEditText.onCreateInputConnection(editorInfo);
-        return ic.commitContent(contentInfo, 0, null);
+        int flags = (Build.VERSION.SDK_INT >= 25)
+                ? InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION : 0;
+        return ic.commitContent(contentInfo, flags, null);
     }
 
     private boolean triggerDropEvent(ClipData clip) {
@@ -594,15 +599,15 @@
         @Nullable
         private final Uri mLinkUri;
         @Nullable
-        private final String mExtra;
+        private final String mExtraValue;
 
         private PayloadArgumentMatcher(@NonNull ClipData clip, int source, int flags,
-                @Nullable Uri linkUri, @Nullable String extra) {
+                @Nullable Uri linkUri, @Nullable String extraValue) {
             mClip = clip;
             mSource = source;
             mFlags = flags;
             mLinkUri = linkUri;
-            mExtra = extra;
+            mExtraValue = extraValue;
         }
 
         @Override
@@ -618,11 +623,16 @@
         }
 
         private boolean extrasMatch(Bundle actualExtras) {
-            if (mExtra == null) {
+            if (mSource == SOURCE_INPUT_METHOD && Build.VERSION.SDK_INT >= 25) {
+                assertThat(actualExtras).isNotNull();
+                Parcelable actualInputContentInfoExtra = actualExtras.getParcelable(
+                        "androidx.core.view.extra.INPUT_CONTENT_INFO");
+                assertThat(actualInputContentInfoExtra).isInstanceOf(InputContentInfo.class);
+            } else if (mExtraValue == null) {
                 return actualExtras == null;
             }
             String actualExtraValue = actualExtras.getString(EXTRA_KEY);
-            return ObjectsCompat.equals(mExtra, actualExtraValue);
+            return ObjectsCompat.equals(mExtraValue, actualExtraValue);
         }
     }
 }
diff --git a/appcompat/appcompat/src/androidTest/res/layout/layout_android_theme_included_view.xml b/appcompat/appcompat/src/androidTest/res/layout/layout_android_theme_included_view.xml
new file mode 100644
index 0000000..03c8d42
--- /dev/null
+++ b/appcompat/appcompat/src/androidTest/res/layout/layout_android_theme_included_view.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:text="Test" />
diff --git a/appcompat/appcompat/src/androidTest/res/layout/layout_android_theme_with_include.xml b/appcompat/appcompat/src/androidTest/res/layout/layout_android_theme_with_include.xml
new file mode 100644
index 0000000..f5e6dc9
--- /dev/null
+++ b/appcompat/appcompat/src/androidTest/res/layout/layout_android_theme_with_include.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:theme="@style/MagentaThemeOverlay">
+
+    <include layout="@layout/layout_android_theme_included_view"
+        android:id="@+id/included_view" />
+
+</FrameLayout>
\ No newline at end of file
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java b/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java
index 22792d7..90f4b18 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatDelegateImpl.java
@@ -281,6 +281,7 @@
     private Rect mTempRect2;
 
     private AppCompatViewInflater mAppCompatViewInflater;
+    private LayoutIncludeDetector mLayoutIncludeDetector;
 
     AppCompatDelegateImpl(Activity activity, AppCompatCallback callback) {
         this(activity, null, callback, activity);
@@ -1543,11 +1544,20 @@
 
         boolean inheritContext = false;
         if (IS_PRE_LOLLIPOP) {
-            inheritContext = (attrs instanceof XmlPullParser)
-                    // If we have a XmlPullParser, we can detect where we are in the layout
-                    ? ((XmlPullParser) attrs).getDepth() > 1
-                    // Otherwise we have to use the old heuristic
-                    : shouldInheritContext((ViewParent) parent);
+            if (mLayoutIncludeDetector == null) {
+                mLayoutIncludeDetector = new LayoutIncludeDetector();
+            }
+            if (mLayoutIncludeDetector.detect(attrs)) {
+                // The view being inflated is the root of an <include>d view, so make sure
+                // we carry over any themed context.
+                inheritContext = true;
+            } else {
+                inheritContext = (attrs instanceof XmlPullParser)
+                        // If we have a XmlPullParser, we can detect where we are in the layout
+                        ? ((XmlPullParser) attrs).getDepth() > 1
+                        // Otherwise we have to use the old heuristic
+                        : shouldInheritContext((ViewParent) parent);
+            }
         }
 
         return mAppCompatViewInflater.createView(parent, name, context, attrs, inheritContext,
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/app/LayoutIncludeDetector.java b/appcompat/appcompat/src/main/java/androidx/appcompat/app/LayoutIncludeDetector.java
new file mode 100644
index 0000000..71963ec
--- /dev/null
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/app/LayoutIncludeDetector.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2021 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.appcompat.app;
+
+import android.util.AttributeSet;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+/**
+ * Used on KitKat and below to determine if the currently inflated view is the start of
+ * an included layout file. If so, any themed context (android:theme) needs to be manually
+ * carried over to preserve it as expected.
+ */
+class LayoutIncludeDetector {
+
+    @NonNull
+    private final Deque<WeakReference<XmlPullParser>> mXmlParserStack = new ArrayDeque<>();
+
+    /**
+     * Returns true if this is the start of an included layout file, otherwise false.
+     */
+    boolean detect(@NonNull AttributeSet attrs) {
+        if (attrs instanceof XmlPullParser) {
+            XmlPullParser xmlAttrs = (XmlPullParser) attrs;
+            if (xmlAttrs.getDepth() == 1) {
+                // This is either beginning of an inflate or an include.
+                // Start by popping XmlPullParsers which are no longer valid since we may
+                // have returned from any number of sub-includes
+                XmlPullParser ancestorXmlAttrs = popOutdatedAttrHolders(mXmlParserStack);
+                // Then store current attrs for possible future use
+                mXmlParserStack.push(new WeakReference<>(xmlAttrs));
+                // Finally check if we need to inherit the parent context based on the
+                // current and ancestor attribute set
+                if (shouldInheritContext(xmlAttrs, ancestorXmlAttrs)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static boolean shouldInheritContext(@NonNull XmlPullParser parser,
+            @Nullable XmlPullParser previousParser) {
+        if (previousParser != null && parser != previousParser) {
+
+            // First check event type since that should avoid accessing native side with
+            // possibly nulled native ptr. We do this since the previous parser could be
+            // either the parent parser for an <include> (in which case it is still active,
+            // with event type == START_TAG) or a parser from a separate inflate() call (in
+            // which case the parser has been closed and would typically have event type
+            // END_TAG or possibly END_DOCUMENT)
+            try {
+                if (previousParser.getEventType() == XmlPullParser.START_TAG) {
+                    // Check if the parent parser is actually on an <include> tag,
+                    // if so we need to inherit the parent context
+                    return "include".equals(previousParser.getName());
+                }
+            } catch (XmlPullParserException e) {
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * Pops any outdated {@link XmlPullParser}s from the given stack.
+     * @param xmlParserStack stack to purge
+     * @return most recent {@link XmlPullParser} that is not outdated
+     */
+    @Nullable
+    private static XmlPullParser popOutdatedAttrHolders(@NonNull
+            Deque<WeakReference<XmlPullParser>> xmlParserStack) {
+        while (!xmlParserStack.isEmpty()) {
+            XmlPullParser parser = xmlParserStack.peek().get();
+            if (isParserOutdated(parser)) {
+                xmlParserStack.pop();
+            } else {
+                return parser;
+            }
+        }
+        return null;
+    }
+
+    private static boolean isParserOutdated(@Nullable XmlPullParser parser) {
+        try {
+            return parser == null || (parser.getEventType() == XmlPullParser.END_TAG
+                    || parser.getEventType() == XmlPullParser.END_DOCUMENT);
+        } catch (XmlPullParserException e) {
+            return true;
+        }
+    }
+}
diff --git a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatReceiveContentHelper.java b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatReceiveContentHelper.java
index 7f90cef..af01fd7 100644
--- a/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatReceiveContentHelper.java
+++ b/appcompat/appcompat/src/main/java/androidx/appcompat/widget/AppCompatReceiveContentHelper.java
@@ -20,6 +20,7 @@
 import static androidx.core.view.ContentInfoCompat.SOURCE_CLIPBOARD;
 import static androidx.core.view.ContentInfoCompat.SOURCE_DRAG_AND_DROP;
 import static androidx.core.view.ContentInfoCompat.SOURCE_INPUT_METHOD;
+import static androidx.core.view.inputmethod.InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION;
 
 import android.app.Activity;
 import android.content.ClipData;
@@ -34,6 +35,7 @@
 import android.view.DragEvent;
 import android.view.View;
 import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputContentInfo;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
@@ -178,7 +180,9 @@
             @Override
             public boolean onCommitContent(InputContentInfoCompat inputContentInfo, int flags,
                     Bundle opts) {
-                if ((flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
+                Bundle extras = opts;
+                if (Build.VERSION.SDK_INT >= 25
+                        && (flags & INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
                     try {
                         inputContentInfo.requestPermission();
                     } catch (Exception e) {
@@ -186,15 +190,33 @@
                                 "Can't insert content from IME; requestPermission() failed", e);
                         return false;
                     }
+                    // Permissions granted above are revoked automatically by the platform when the
+                    // corresponding InputContentInfo object is garbage collected. To prevent
+                    // this from happening prematurely (before the receiving app has had a chance
+                    // to process the content), we set the InputContentInfo object into the
+                    // extras of the payload passed to OnReceiveContentListener.
+                    InputContentInfo inputContentInfoFmk =
+                            (InputContentInfo) inputContentInfo.unwrap();
+                    extras = (opts == null) ? new Bundle() : new Bundle(opts);
+                    extras.putParcelable(EXTRA_INPUT_CONTENT_INFO, inputContentInfoFmk);
                 }
                 ClipData clip = new ClipData(inputContentInfo.getDescription(),
                         new ClipData.Item(inputContentInfo.getContentUri()));
                 ContentInfoCompat payload = new ContentInfoCompat.Builder(clip, SOURCE_INPUT_METHOD)
                         .setLinkUri(inputContentInfo.getLinkUri())
-                        .setExtras(opts)
+                        .setExtras(extras)
                         .build();
                 return ViewCompat.performReceiveContent(view, payload) == null;
             }
         };
     }
+
+    /**
+     * Key for extras in {@link ContentInfoCompat}, to hold the {@link InputContentInfo} object
+     * passed by the IME. Apps should not access/read this object; it is only set in the extras
+     * in order to prevent premature garbage collection of {@link InputContentInfo} which in
+     * turn causes premature revocation of URI permissions.
+     */
+    private static final String EXTRA_INPUT_CONTENT_INFO =
+            "androidx.core.view.extra.INPUT_CONTENT_INFO";
 }
diff --git a/benchmark/common/api/public_plus_experimental_current.txt b/benchmark/common/api/public_plus_experimental_current.txt
index 315fd22..6f98a41 100644
--- a/benchmark/common/api/public_plus_experimental_current.txt
+++ b/benchmark/common/api/public_plus_experimental_current.txt
@@ -1,13 +1,6 @@
 // Signature format: 4.0
 package androidx.benchmark {
 
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class Arguments {
-    method public java.util.Set<java.lang.String> getSuppressedErrors();
-    method public java.io.File testOutputFile(String filename);
-    property public final java.util.Set<java.lang.String> suppressedErrors;
-    field public static final androidx.benchmark.Arguments INSTANCE;
-  }
-
   public final class ArgumentsKt {
   }
 
@@ -60,7 +53,7 @@
     ctor public InstrumentationResultScope(optional android.os.Bundle bundle);
     method public void fileRecord(String key, String path);
     method public android.os.Bundle getBundle();
-    method public void ideSummaryRecord(String value);
+    method public void ideSummaryRecord(String summaryV1, optional String summaryV2);
     property public final android.os.Bundle bundle;
   }
 
@@ -98,16 +91,20 @@
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class Stats {
     ctor public Stats(long[] data, String name);
     method public long getMax();
-    method public double getMean();
+    method public int getMaxIndex();
     method public long getMedian();
+    method public int getMedianIndex();
     method public long getMin();
+    method public int getMinIndex();
     method public String getName();
     method public double getStandardDeviation();
     method public void putInBundle(android.os.Bundle status, String prefix);
     property public final long max;
-    property public final double mean;
+    property public final int maxIndex;
     property public final long median;
+    property public final int medianIndex;
     property public final long min;
+    property public final int minIndex;
     property public final String name;
     property public final double standardDeviation;
   }
diff --git a/benchmark/common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt b/benchmark/common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt
index ef9b83d..2c6518d 100644
--- a/benchmark/common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt
+++ b/benchmark/common/src/androidTest/java/androidx/benchmark/BenchmarkStateTest.kt
@@ -36,11 +36,11 @@
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
-class BenchmarkStateTest {
+public class BenchmarkStateTest {
     private fun us2ns(ms: Long): Long = TimeUnit.MICROSECONDS.toNanos(ms)
 
     @get:Rule
-    val writePermissionRule =
+    public val writePermissionRule: GrantPermissionRule =
         GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE)!!
 
     /**
@@ -58,7 +58,7 @@
     }
 
     @Test
-    fun validateMetrics() {
+    public fun validateMetrics() {
         val state = BenchmarkState()
         while (state.keepRunning()) {
             runAndSpin(durationUs = 300) {
@@ -88,7 +88,7 @@
     }
 
     @Test
-    fun keepRunningMissingResume() {
+    public fun keepRunningMissingResume() {
         val state = BenchmarkState()
 
         assertEquals(true, state.keepRunning())
@@ -97,7 +97,7 @@
     }
 
     @Test
-    fun pauseCalledTwice() {
+    public fun pauseCalledTwice() {
         val state = BenchmarkState()
 
         assertEquals(true, state.keepRunning())
@@ -107,7 +107,7 @@
 
     @SdkSuppress(minSdkVersion = 24)
     @Test
-    fun priorityJitThread() {
+    public fun priorityJitThread() {
         assertEquals(
             "JIT priority should not yet be modified",
             ThreadPriority.JIT_INITIAL_PRIORITY,
@@ -128,7 +128,7 @@
     }
 
     @Test
-    fun priorityBenchThread() {
+    public fun priorityBenchThread() {
         val initialPriority = ThreadPriority.get()
         assertNotEquals(
             "Priority should not be max",
@@ -172,12 +172,12 @@
     }
 
     @Test
-    fun iterationCheck_simple() {
+    public fun iterationCheck_simple() {
         iterationCheck(checkingForThermalThrottling = true)
     }
 
     @Test
-    fun iterationCheck_withAllocations() {
+    public fun iterationCheck_withAllocations() {
         if (CpuInfo.locked ||
             IsolationActivity.sustainedPerformanceModeInUse ||
             Errors.isEmulator
@@ -191,7 +191,7 @@
     }
 
     @Test
-    fun bundle() {
+    public fun bundle() {
         val bundle = BenchmarkState().apply {
             while (keepRunning()) {
                 // nothing, we're ignoring numbers
@@ -221,7 +221,7 @@
     }
 
     @Test
-    fun notStarted() {
+    public fun notStarted() {
         val initialPriority = ThreadPriority.get()
         try {
             BenchmarkState().getReport().getStats("timeNs").median
@@ -234,7 +234,7 @@
     }
 
     @Test
-    fun notFinished() {
+    public fun notFinished() {
         val initialPriority = ThreadPriority.get()
         try {
             BenchmarkState().run {
@@ -252,7 +252,7 @@
     @Suppress("DEPRECATION")
     @UseExperimental(ExperimentalExternalReport::class)
     @Test
-    fun reportResult() {
+    public fun reportResult() {
         BenchmarkState.reportData(
             className = "className",
             testName = "testName",
diff --git a/benchmark/common/src/androidTest/java/androidx/benchmark/InstrumentationResultsTest.kt b/benchmark/common/src/androidTest/java/androidx/benchmark/InstrumentationResultsTest.kt
index bfd01c8..fbd23ee 100644
--- a/benchmark/common/src/androidTest/java/androidx/benchmark/InstrumentationResultsTest.kt
+++ b/benchmark/common/src/androidTest/java/androidx/benchmark/InstrumentationResultsTest.kt
@@ -24,7 +24,7 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
-class InstrumentationResultsTest {
+public class InstrumentationResultsTest {
     @Test
     public fun ideSummary_alignment() {
         val summary1 = InstrumentationResults.ideSummaryLine("foo", 1000, 100)
diff --git a/benchmark/common/src/androidTest/java/androidx/benchmark/MetricCaptureTest.kt b/benchmark/common/src/androidTest/java/androidx/benchmark/MetricCaptureTest.kt
index 5f652a0..285fc54 100644
--- a/benchmark/common/src/androidTest/java/androidx/benchmark/MetricCaptureTest.kt
+++ b/benchmark/common/src/androidTest/java/androidx/benchmark/MetricCaptureTest.kt
@@ -23,16 +23,16 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
-class AllocationCountCaptureTest {
+public class AllocationCountCaptureTest {
     @Test
-    fun simple() {
+    public fun simple() {
         AllocationCountCapture().verifyMedian(100..110) {
             allocate(100)
         }
     }
 
     @Test
-    fun pauseResume() {
+    public fun pauseResume() {
         AllocationCountCapture().verifyMedian(100..110) {
             allocate(100)
 
diff --git a/benchmark/common/src/androidTest/java/androidx/benchmark/ProfilerTest.kt b/benchmark/common/src/androidTest/java/androidx/benchmark/ProfilerTest.kt
index acc43f2..6e2f2be 100644
--- a/benchmark/common/src/androidTest/java/androidx/benchmark/ProfilerTest.kt
+++ b/benchmark/common/src/androidTest/java/androidx/benchmark/ProfilerTest.kt
@@ -31,9 +31,9 @@
 
 @MediumTest
 @RunWith(AndroidJUnit4::class)
-class ProfilerTest {
+public class ProfilerTest {
     @Test
-    fun getByName() {
+    public fun getByName() {
         assertSame(MethodSampling, Profiler.getByName("MethodSampling"))
         assertSame(MethodTracing, Profiler.getByName("MethodTracing"))
         assertSame(ConnectedAllocation, Profiler.getByName("ConnectedAllocation"))
@@ -69,15 +69,15 @@
     }
 
     @Test
-    fun methodSampling() = verifyProfiler(
+    public fun methodSampling(): Unit = verifyProfiler(
         profiler = MethodSampling,
-        file = Arguments.testOutputFile("test-methodSampling.trace")
+        file = Outputs.testOutputFile("test-methodSampling.trace")
     )
 
     @Test
-    fun methodTracing() = verifyProfiler(
+    public fun methodTracing(): Unit = verifyProfiler(
         profiler = MethodTracing,
-        file = Arguments.testOutputFile("test-methodTracing.trace")
+        file = Outputs.testOutputFile("test-methodTracing.trace")
     )
 
     @Ignore(
@@ -86,7 +86,7 @@
     )
     @SdkSuppress(minSdkVersion = 28)
     @Test
-    fun methodSamplingSimpleperf() = verifyProfiler(
+    public fun methodSamplingSimpleperf(): Unit = verifyProfiler(
         profiler = MethodSamplingSimpleperf,
         file = File("/data/data/androidx.benchmark.test/simpleperf_data/test.data")
     )
diff --git a/benchmark/common/src/androidTest/java/androidx/benchmark/ResultWriterTest.kt b/benchmark/common/src/androidTest/java/androidx/benchmark/ResultWriterTest.kt
index 8712916..3b91c72 100644
--- a/benchmark/common/src/androidTest/java/androidx/benchmark/ResultWriterTest.kt
+++ b/benchmark/common/src/androidTest/java/androidx/benchmark/ResultWriterTest.kt
@@ -30,7 +30,7 @@
 @RunWith(AndroidJUnit4::class)
 public class ResultWriterTest {
     @get:Rule
-    val tempFolder = TemporaryFolder()
+    public val tempFolder: TemporaryFolder = TemporaryFolder()
 
     private val metricResults = listOf(
         MetricResult(
@@ -59,7 +59,7 @@
     )
 
     @Test
-    fun shouldClearExistingContent() {
+    public fun shouldClearExistingContent() {
         val tempFile = tempFolder.newFile()
 
         val fakeText = "This text should not be in the final output"
@@ -70,7 +70,7 @@
     }
 
     @Test
-    fun validateJson() {
+    public fun validateJson() {
         val tempFile = tempFolder.newFile()
 
         val sustainedPerformanceModeInUse = IsolationActivity.sustainedPerformanceModeInUse
@@ -146,7 +146,7 @@
     }
 
     @Test
-    fun validateJsonWithParams() {
+    public fun validateJsonWithParams() {
         val reportWithParams = BenchmarkResult(
             testName = "MethodWithParams[number=2,primeNumber=true]",
             className = "package.Class",
@@ -175,7 +175,7 @@
     }
 
     @Test
-    fun validateJsonWithInvalidParams() {
+    public fun validateJsonWithInvalidParams() {
         val reportWithInvalidParams = BenchmarkResult(
             testName = "MethodWithParams[number=2,=true,]",
             className = "package.Class",
diff --git a/benchmark/common/src/androidTest/java/androidx/benchmark/StatsTest.kt b/benchmark/common/src/androidTest/java/androidx/benchmark/StatsTest.kt
index 4af0b67..7638320 100644
--- a/benchmark/common/src/androidTest/java/androidx/benchmark/StatsTest.kt
+++ b/benchmark/common/src/androidTest/java/androidx/benchmark/StatsTest.kt
@@ -25,39 +25,48 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
-class StatsTest {
+public class StatsTest {
     @Test
-    fun repeat() {
+    public fun repeat() {
         val stats = Stats(longArrayOf(10, 10, 10, 10), "test")
-        assertEquals(10.0, stats.mean, 0.0)
-        assertEquals(10, stats.median)
-        assertEquals(10, stats.max)
         assertEquals(10, stats.min)
+        assertEquals(10, stats.max)
+        assertEquals(10, stats.median)
         assertEquals(0.0, stats.standardDeviation, 0.0)
+
+        assertEquals(0, stats.minIndex)
+        assertEquals(0, stats.maxIndex)
+        assertEquals(2, stats.medianIndex)
     }
 
     @Test
-    fun one() {
+    public fun one() {
         val stats = Stats(longArrayOf(10), "test")
-        assertEquals(10.0, stats.mean, 0.0)
-        assertEquals(10, stats.median)
-        assertEquals(10, stats.max)
         assertEquals(10, stats.min)
-        assertEquals(Double.NaN, stats.standardDeviation, 0.0)
+        assertEquals(10, stats.max)
+        assertEquals(10, stats.median)
+        assertEquals(0.0, stats.standardDeviation, 0.0)
+
+        assertEquals(0, stats.minIndex)
+        assertEquals(0, stats.maxIndex)
+        assertEquals(0, stats.medianIndex)
     }
 
     @Test
-    fun simple() {
+    public fun simple() {
         val stats = Stats((1L..100L).toList().toLongArray(), "test")
-        assertEquals(50.5, stats.mean, 0.0)
         assertTrue(stats.median == 50L || stats.median == 51L)
         assertEquals(100, stats.max)
         assertEquals(1, stats.min)
         assertEquals(29.01, stats.standardDeviation, 0.05)
+
+        assertEquals(0, stats.minIndex)
+        assertEquals(99, stats.maxIndex)
+        assertEquals(50, stats.medianIndex)
     }
 
     @Test
-    fun lerp() {
+    public fun lerp() {
         assertEquals(Stats.lerp(0, 1000, 0.5), 500)
         assertEquals(Stats.lerp(0, 1000, 0.75), 750)
         assertEquals(Stats.lerp(0, 1000, 0.25), 250)
@@ -65,7 +74,7 @@
     }
 
     @Test
-    fun getPercentile() {
+    public fun getPercentile() {
         (0..100).forEach {
             assertEquals(it.toLong(), Stats.getPercentile(listOf(0L, 25L, 50L, 75L, 100L), it))
         }
diff --git a/benchmark/common/src/androidTest/java/androidx/benchmark/WarmupManagerTest.kt b/benchmark/common/src/androidTest/java/androidx/benchmark/WarmupManagerTest.kt
index c1d0efd..9b2eac8 100644
--- a/benchmark/common/src/androidTest/java/androidx/benchmark/WarmupManagerTest.kt
+++ b/benchmark/common/src/androidTest/java/androidx/benchmark/WarmupManagerTest.kt
@@ -26,10 +26,10 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
-class WarmupManagerTest {
+public class WarmupManagerTest {
 
     @Test
-    fun minDuration() {
+    public fun minDuration() {
         // even with tiny, predictable inputs, we require min warmup duration
         val warmup = WarmupManager()
         while (!warmup.onNextIteration(100)) {}
@@ -37,7 +37,7 @@
     }
 
     @Test
-    fun maxDuration() {
+    public fun maxDuration() {
         // even if values are warming up slowly, we require max warmup duration
         val warmup = WarmupManager()
         warmup.warmupOnFakeData(
@@ -53,7 +53,7 @@
     }
 
     @Test
-    fun minIterations() {
+    public fun minIterations() {
         // min iterations overrides max duration
         val warmup = WarmupManager()
         while (!warmup.onNextIteration(TimeUnit.SECONDS.toNanos(2))) {}
@@ -61,7 +61,7 @@
     }
 
     @Test
-    fun similarIterationCount() {
+    public fun similarIterationCount() {
         // mock warmup data, and validate we detect convergence
         val warmup = WarmupManager()
         val warmupNeededNs = TimeUnit.SECONDS.toNanos(2)
diff --git a/benchmark/common/src/main/java/androidx/benchmark/Arguments.kt b/benchmark/common/src/main/java/androidx/benchmark/Arguments.kt
index 33223ea..c14a978 100644
--- a/benchmark/common/src/main/java/androidx/benchmark/Arguments.kt
+++ b/benchmark/common/src/main/java/androidx/benchmark/Arguments.kt
@@ -20,19 +20,21 @@
 import android.util.Log
 import androidx.annotation.RestrictTo
 import androidx.test.platform.app.InstrumentationRegistry
-import java.io.File
-import java.lang.IllegalStateException
 
 /**
  * This allows tests to override arguments from code
  *
- * @suppress
+ * @hide
  */
 @RestrictTo(RestrictTo.Scope.TESTS)
 public var argumentSource: Bundle? = null
 
+/**
+ * @hide
+ */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public object Arguments {
+
     // public properties are shared by micro + macro benchmarks
     public val suppressedErrors: Set<String>
 
@@ -45,8 +47,7 @@
     internal val profilerSampleDurationSeconds: Long
 
     internal var error: String? = null
-
-    private val testOutputDir: File
+    internal val additionalTestOutputDir: String?
 
     private const val prefix = "androidx.benchmark."
 
@@ -105,17 +106,6 @@
                     "$profilerSampleFrequency, duration $profilerSampleDurationSeconds"
             )
         }
-
-        val additionalTestOutputDir = arguments.getString("additionalTestOutputDir")
-        testOutputDir = additionalTestOutputDir?.let { File(it) }
-            ?: InstrumentationRegistry.getInstrumentation().context.externalCacheDir
-            ?: throw IllegalStateException(
-                "Unable to read externalCacheDir for writing files, " +
-                    "additionalTestOutputDir argument required to declare output dir."
-            )
+        additionalTestOutputDir = arguments.getString("additionalTestOutputDir")
     }
-
-    public fun testOutputFile(filename: String): File {
-        return File(testOutputDir, filename)
-    }
-}
\ No newline at end of file
+}
diff --git a/benchmark/common/src/main/java/androidx/benchmark/BenchmarkState.kt b/benchmark/common/src/main/java/androidx/benchmark/BenchmarkState.kt
index 6b66d0a..de873fb 100644
--- a/benchmark/common/src/main/java/androidx/benchmark/BenchmarkState.kt
+++ b/benchmark/common/src/main/java/androidx/benchmark/BenchmarkState.kt
@@ -471,7 +471,7 @@
             stats.forEach { it.putInBundle(status, PREFIX) }
         }
         InstrumentationResultScope(status).ideSummaryRecord(
-            ideSummaryLineWrapped(
+            summaryV1 = ideSummaryLineWrapped(
                 key,
                 getMinTimeNanos(),
                 stats.firstOrNull { it.name == "allocationCount" }?.median
@@ -611,7 +611,7 @@
 
             instrumentationReport {
                 ideSummaryRecord(
-                    ideSummaryLineWrapped(
+                    summaryV1 = ideSummaryLineWrapped(
                         key = fullTestName,
                         nanos = report.getStats("timeNs").min,
                         allocations = null
diff --git a/benchmark/common/src/main/java/androidx/benchmark/InstrumentationResults.kt b/benchmark/common/src/main/java/androidx/benchmark/InstrumentationResults.kt
index 43c8c58..ad96275 100644
--- a/benchmark/common/src/main/java/androidx/benchmark/InstrumentationResults.kt
+++ b/benchmark/common/src/main/java/androidx/benchmark/InstrumentationResults.kt
@@ -26,8 +26,23 @@
  */
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public class InstrumentationResultScope(public val bundle: Bundle = Bundle()) {
-    public fun ideSummaryRecord(value: String) {
-        bundle.putString(IDE_SUMMARY_KEY, value)
+    @Suppress("MissingJvmstatic")
+    public fun ideSummaryRecord(
+        /**
+         * Simple text-only result summary string to output to IDE.
+         */
+        summaryV1: String,
+        /**
+         * V2 output string, supports linking to files in the output dir via links of the format
+         * `[link](file://<relative-path-to-trace>`).
+         */
+        summaryV2: String = summaryV1
+    ) {
+        bundle.putString(IDE_V1_SUMMARY_KEY, summaryV1)
+        // Outputs.outputDirectory is safe to use in the context of Studio currently.
+        // This is because AGP does not populate the `additionalTestOutputDir` argument.
+        bundle.putString(IDE_V2_OUTPUT_DIR_PATH_KEY, Outputs.outputDirectory.absolutePath)
+        bundle.putString(IDE_V2_SUMMARY_KEY, summaryV2)
     }
 
     public fun fileRecord(key: String, path: String) {
@@ -35,7 +50,11 @@
     }
 
     internal companion object {
-        private const val IDE_SUMMARY_KEY = "android.studio.display.benchmark"
+        private const val IDE_V1_SUMMARY_KEY = "android.studio.display.benchmark"
+
+        private const val IDE_V2_OUTPUT_DIR_PATH_KEY =
+            "android.studio.v2display.benchmark.outputDirPath"
+        private const val IDE_V2_SUMMARY_KEY = "android.studio.v2display.benchmark"
     }
 }
 
diff --git a/benchmark/common/src/main/java/androidx/benchmark/Outputs.kt b/benchmark/common/src/main/java/androidx/benchmark/Outputs.kt
new file mode 100644
index 0000000..ae2b62c
--- /dev/null
+++ b/benchmark/common/src/main/java/androidx/benchmark/Outputs.kt
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2021 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.benchmark
+
+import android.annotation.SuppressLint
+import android.os.Build
+import android.os.Environment
+import android.util.Log
+import androidx.annotation.RestrictTo
+import androidx.test.platform.app.InstrumentationRegistry
+import java.io.File
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public object Outputs {
+
+    /**
+     * The output directory that the developer wants us to use.
+     */
+    public val outputDirectory: File
+
+    /**
+     * The usable output directory, given permission issues with `adb shell` on Android R.
+     * Both the app and the shell have access to this output folder.
+     */
+    public val dirUsableByAppAndShell: File
+
+    init {
+        @SuppressLint("UnsafeNewApiCall", "NewApi")
+        @Suppress("DEPRECATION")
+        dirUsableByAppAndShell = when (Build.VERSION.SDK_INT) {
+            Build.VERSION_CODES.R -> {
+                // On Android R, we are using the media directory because that is the directory
+                // that the shell has access to. Context: b/181601156
+                InstrumentationRegistry.getInstrumentation().context.externalMediaDirs
+                    .firstOrNull {
+                        Environment.getExternalStorageState(it) == Environment.MEDIA_MOUNTED
+                    }
+            }
+            else -> InstrumentationRegistry.getInstrumentation().context.externalCacheDir
+        } ?: throw IllegalStateException(
+            "Unable to read externalCacheDir for writing files, " +
+                "additionalTestOutputDir argument required to declare output dir."
+        )
+
+        Log.d(BenchmarkState.TAG, "Usable output directory: $dirUsableByAppAndShell")
+
+        outputDirectory = Arguments.additionalTestOutputDir?.let { File(it) }
+            ?: dirUsableByAppAndShell
+
+        Log.d(BenchmarkState.TAG, "Output Directory: $outputDirectory")
+    }
+
+    /**
+     * Create a benchmark output [File] to write to.
+     *
+     * This method handles reporting files to `InstrumentationStatus` to request copy,
+     * writing them in the desired output directory, and handling shell access issues on Android R.
+     *
+     * @return The absolute path of the output [File].
+     */
+    public fun writeFile(
+        fileName: String,
+        reportKey: String,
+        reportOnRunEndOnly: Boolean = false,
+        block: (file: File) -> Unit,
+    ): String {
+        val override = Build.VERSION.SDK_INT == Build.VERSION_CODES.R
+        // We override the `additionalTestOutputDir` argument on R.
+        // Context: b/181601156
+        val file = File(dirUsableByAppAndShell, fileName)
+        try {
+            block.invoke(file)
+        } finally {
+            var destination = file
+            if (override) {
+                // This respects the `additionalTestOutputDir` argument.
+                val actualOutputDirectory = outputDirectory
+                destination = File(actualOutputDirectory, fileName)
+                if (file != destination) {
+                    try {
+                        destination.mkdirs()
+                        file.copyTo(destination, overwrite = true)
+                    } catch (exception: Throwable) {
+                        // This can happen when `additionalTestOutputDir` being passed in cannot
+                        // be written to. The shell does not have permissions to do the necessary
+                        // setup, and this can cause `adb pull` to fail.
+                        val message = """
+                            Unable to copy files to ${destination.absolutePath}.
+                            Please pull the Macrobenchmark results manually by using:
+                            adb pull ${file.absolutePath}
+                        """.trimIndent()
+                        Log.e(BenchmarkState.TAG, message, exception)
+                        destination = file
+                    }
+                }
+            }
+            InstrumentationResults.reportAdditionalFileToCopy(
+                key = reportKey,
+                absoluteFilePath = destination.absolutePath,
+                reportOnRunEndOnly = reportOnRunEndOnly
+            )
+            return destination.absolutePath
+        }
+    }
+
+    public fun testOutputFile(filename: String): File {
+        return File(outputDirectory, filename)
+    }
+
+    public fun relativePathFor(path: String): String {
+        var basePath = outputDirectory.absolutePath
+        val relativePath = if (path.indexOf(basePath) > 0) {
+            path.removePrefix("$basePath/")
+        } else {
+            basePath = dirUsableByAppAndShell.absolutePath
+            path.removePrefix("$basePath/")
+        }
+        check(relativePath != path) {
+            "$relativePath == $path"
+        }
+        return relativePath
+    }
+}
diff --git a/benchmark/common/src/main/java/androidx/benchmark/Profiler.kt b/benchmark/common/src/main/java/androidx/benchmark/Profiler.kt
index 3075cc8..36207f9 100644
--- a/benchmark/common/src/main/java/androidx/benchmark/Profiler.kt
+++ b/benchmark/common/src/main/java/androidx/benchmark/Profiler.kt
@@ -16,6 +16,7 @@
 
 package androidx.benchmark
 
+import android.annotation.SuppressLint
 import android.os.Build
 import android.os.Debug
 import android.util.Log
@@ -85,8 +86,9 @@
     }
 }
 
+@SuppressLint("UnsafeNewApiCall")
 internal fun startRuntimeMethodTracing(traceFileName: String, sampled: Boolean) {
-    val path = Arguments.testOutputFile(traceFileName).absolutePath
+    val path = Outputs.testOutputFile(traceFileName).absolutePath
 
     Log.d(BenchmarkState.TAG, "Profiling output file: $path")
     InstrumentationResults.reportAdditionalFileToCopy("profiling_trace", path)
diff --git a/benchmark/common/src/main/java/androidx/benchmark/ResultWriter.kt b/benchmark/common/src/main/java/androidx/benchmark/ResultWriter.kt
index d4d9a78..c539573 100644
--- a/benchmark/common/src/main/java/androidx/benchmark/ResultWriter.kt
+++ b/benchmark/common/src/main/java/androidx/benchmark/ResultWriter.kt
@@ -37,22 +37,21 @@
         if (Arguments.outputEnable) {
             // Currently, we just overwrite the whole file
             // Ideally, append for efficiency
-            val packageName =
-                InstrumentationRegistry.getInstrumentation().targetContext!!.packageName
+            val packageName = InstrumentationRegistry.getInstrumentation()
+                .targetContext!!
+                .packageName
 
-            val file = Arguments.testOutputFile("$packageName-benchmarkData.json")
-            Log.d(
-                BenchmarkState.TAG,
-                "writing results to ${file.absolutePath}"
-            )
-            writeReport(file, reports)
-            InstrumentationResults.reportAdditionalFileToCopy(
-                "results_json",
-                file.absolutePath,
-                // since we keep appending the same file, defer reporting path until end of suite
-                // note: this requires using InstrumentationResultsRunListener
+            Outputs.writeFile(
+                fileName = "$packageName-benchmarkData.json",
+                reportKey = "results_json",
                 reportOnRunEndOnly = true
-            )
+            ) {
+                Log.d(
+                    BenchmarkState.TAG,
+                    "writing results to ${it.absolutePath}"
+                )
+                writeReport(it, reports)
+            }
         } else {
             Log.d(
                 BenchmarkState.TAG,
diff --git a/benchmark/common/src/main/java/androidx/benchmark/Stats.kt b/benchmark/common/src/main/java/androidx/benchmark/Stats.kt
index 6d2e354..cee9d23 100644
--- a/benchmark/common/src/main/java/androidx/benchmark/Stats.kt
+++ b/benchmark/common/src/main/java/androidx/benchmark/Stats.kt
@@ -18,9 +18,9 @@
 
 import android.os.Bundle
 import androidx.annotation.RestrictTo
-import kotlin.Double.Companion.NaN
 import kotlin.math.pow
 import kotlin.math.roundToLong
+import kotlin.math.sqrt
 
 /**
  * Provides statistics such as mean, median, min, max, and percentiles, given a list of input
@@ -29,31 +29,37 @@
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public class Stats(data: LongArray, public val name: String) {
     public val median: Long
+    public val medianIndex: Int
     public val min: Long
+    public val minIndex: Int
     public val max: Long
-    public val mean: Double = data.average()
+    public val maxIndex: Int
     public val standardDeviation: Double
 
     init {
         val values = data.sorted()
         val size = values.size
-        if (size < 1) {
-            throw IllegalArgumentException("At least one result is necessary.")
-        }
+        require(size >= 1) { "At least one result is necessary." }
 
+        val mean: Double = data.average()
         min = values.first()
         max = values.last()
         median = getPercentile(values, 50)
-        standardDeviation = if (size == 1) {
-            NaN
+
+        minIndex = data.indexOf(min)
+        maxIndex = data.indexOf(max)
+        medianIndex = data.size / 2
+
+        standardDeviation = if (data.size == 1) {
+            0.0
         } else {
             val sum = values.map { (it - mean).pow(2) }.sum()
-            Math.sqrt(sum / (size - 1).toDouble())
+            sqrt(sum / (size - 1).toDouble())
         }
     }
 
     internal fun getSummary(): String {
-        return "Stats for $name: median $median, min $min, max $max, mean $mean, " +
+        return "Stats for $name: median $median, min $min, max $max, " +
             "standardDeviation: $standardDeviation"
     }
 
@@ -66,7 +72,7 @@
             status.putLong("${prefix}standardDeviation", standardDeviation.toLong())
         }
 
-        // format string for
+        // format string to be in instrumentation results format
         val bundleName = name.toOutputMetricName()
 
         status.putLong("${prefix}${bundleName}_min", min)
@@ -74,13 +80,35 @@
         status.putLong("${prefix}${bundleName}_stddev", standardDeviation.toLong())
     }
 
+    // NOTE: Studio-generated, re-generate if members change
     override fun equals(other: Any?): Boolean {
-        return (other is Stats && other.hashCode() == this.hashCode())
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as Stats
+
+        if (name != other.name) return false
+        if (median != other.median) return false
+        if (medianIndex != other.medianIndex) return false
+        if (min != other.min) return false
+        if (minIndex != other.minIndex) return false
+        if (max != other.max) return false
+        if (maxIndex != other.maxIndex) return false
+        if (standardDeviation != other.standardDeviation) return false
+
+        return true
     }
 
     override fun hashCode(): Int {
-        return min.hashCode() + max.hashCode() + median.hashCode() + standardDeviation.hashCode() +
-            mean.hashCode()
+        var result = name.hashCode()
+        result = 31 * result + median.hashCode()
+        result = 31 * result + medianIndex
+        result = 31 * result + min.hashCode()
+        result = 31 * result + minIndex
+        result = 31 * result + max.hashCode()
+        result = 31 * result + maxIndex
+        result = 31 * result + standardDeviation.hashCode()
+        return result
     }
 
     internal companion object {
diff --git a/benchmark/docs/macrobenchmark.md b/benchmark/docs/macrobenchmark.md
index 488c47e..3330d59a 100644
--- a/benchmark/docs/macrobenchmark.md
+++ b/benchmark/docs/macrobenchmark.md
@@ -4,6 +4,8 @@
 [developer.android.com](https://developer.android.com) when the library is ready
 for public release.
 
+NOTE: See [Known Issues](#known-issues) for workarounds for library issues.
+
 [TOC]
 
 ## Jetpack Macrobenchmark
@@ -49,8 +51,6 @@
 you're testing (e.g. you can specify cold, first-time install startup
 performance).
 
-
-
 <!-- Below table doesn't work on android.googlesource.com, using image as workaround
 <table>
     <tr>
@@ -137,10 +137,34 @@
 
 To macrobenchmark an app (called the *target* of the macrobenchmark), that app
 should be configured as close to user experience as possible - non-debuggable,
-preferabbly with minification on (which is beneficial for performance). This is
+preferably with minification on (which is beneficial for performance). This is
 typically done by installing the `release` variant of the target apk.
 
-It will also need to be profileable, to enable reading detailed trace
+As it is necessary to sign your app's `release` variant before building, you can
+sign it locally with `debug` keys:
+
+```groovy
+    buildTypes {
+        release {
+            // You'll be unable to release with this config, but it can
+            // be useful for local performance testing
+            signingConfig signingConfigs.debug
+        }
+    }
+```
+
+Every Activity to be launched by a Macrobenchmark must
+[exported](https://developer.android.com/guide/topics/manifest/activity-element#exported).
+As of Android 11, this must be enabled explicitly in the app's
+AndroidManifest.xml:
+
+```xml
+    <activity
+        android:name=".MyActivity"
+        android:exported="true">
+```
+
+Your app will also need to be profileable, to enable reading detailed trace
 information. This is enabled in the `<application>` tag of the app's
 AndroidManifest.xml:
 
@@ -164,13 +188,6 @@
 
 ## Run the Macrobenchmark
 
-```
-Some users are experiencing issues running macro benchmarks on certain devices and OS versions, especially non-Pixel devices.
-If you run into an issue please [report feedback](#feedback), with the exception and a logcat snippet from the test run.
-
-If you hit a problem, try a different test device as a temporary workaround.
-```
-
 Run the test from within Studio to measure the performance of your app on your
 device. Note that you **must run the test on a physical device**, and not an
 emulator, as emulators do not produce performance numbers representative of
@@ -283,10 +300,19 @@
 
 ```shell
 # the following command will pull all files ending in .trace
-adb shell 'ls /storage/emulated/0/Download/*.trace' \
+# if you have not overriden the output directory
+adb shell ls '/storage/emulated/0/Android/data/*/*/*.trace' \
     | tr -d '\r' | xargs -n1 adb pull
 ```
 
+Note that your output file path may be different if you customize it with the
+`additionalTestOutputDir` argument. You can look for trace path logs in logcat
+to see where there are written, for example:
+
+```
+I PerfettoCapture: Writing to /storage/emulated/0/Android/data/androidx.benchmark.integration.macrobenchmark.test/cache/TrivialStartupBenchmark_startup[mode=COLD]_iter002.trace.
+```
+
 If you invoke the tests instead via gradle command line (e.g. `./gradlew
 macrobenchmark:connectedCheck`), these files are pulled automatically to a test
 output directory:
@@ -362,6 +388,12 @@
 </manifest>
 ```
 
+Or pass an instrumentation arg to bypass scoped storage for the test:
+
+```shell
+-e no-isolated-storage 1
+```
+
 NOTE: The file extension of these trace files is currently `.trace`, but will
 likely change in the future to clarify that these are perfetto traces.
 
@@ -423,6 +455,17 @@
 For guidance in how to detect performance regressions, see the blogpost
 [Fighting Regressions with Benchmarks in CI](https://medium.com/androiddevelopers/fighting-regressions-with-benchmarks-in-ci-6ea9a14b5c71).
 
+
+## Known Issues
+
+### Missing Metrics
+
+If you see exceptions with the text: `Unable to read any metrics during
+benchmark` or `Error, different metrics observed in different iterations.` in a
+startup benchmark, these can be caused by the library failing to wait for
+Activity launch. As a temporary workaround, you can add a
+`Thread.sleep(5000/*ms*/)` at the end of your `measureRepeated {}` block.
+
 ## Feedback
 
 To report issues or submit feature requests for Jetpack Macrobenchmark, see the
diff --git a/benchmark/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml b/benchmark/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
index 854c056..45da2fe 100644
--- a/benchmark/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
+++ b/benchmark/integration-tests/macrobenchmark-target/src/main/AndroidManifest.xml
@@ -54,5 +54,19 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
+
+
+        <!--
+        Activities need to be exported so the macrobenchmark can discover them
+        under the new package visibility changes for Android 11.
+         -->
+        <activity
+            android:name=".NotExportedActivity"
+            android:exported="false">
+            <intent-filter>
+                <action android:name="androidx.benchmark.integration.macrobenchmark.target.NOT_EXPORTED_ACTIVITY" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt b/benchmark/integration-tests/macrobenchmark-target/src/main/java/androidx/benchmark/integration/macrobenchmark/target/NotExportedActivity.kt
similarity index 79%
rename from compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
rename to benchmark/integration-tests/macrobenchmark-target/src/main/java/androidx/benchmark/integration/macrobenchmark/target/NotExportedActivity.kt
index 7e01354..8b6d2f6 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
+++ b/benchmark/integration-tests/macrobenchmark-target/src/main/java/androidx/benchmark/integration/macrobenchmark/target/NotExportedActivity.kt
@@ -1,5 +1,3 @@
-// ktlint-disable filename
-
 /*
  * Copyright 2021 The Android Open Source Project
  *
@@ -16,6 +14,8 @@
  * limitations under the License.
  */
 
-package androidx.compose.foundation
+package androidx.benchmark.integration.macrobenchmark.target
 
-internal actual typealias AtomicReference<V> = java.util.concurrent.atomic.AtomicReference<V>
\ No newline at end of file
+import androidx.appcompat.app.AppCompatActivity
+
+class NotExportedActivity : AppCompatActivity()
diff --git a/benchmark/macro-junit4/src/main/java/androidx/benchmark/macro/junit4/PerfettoRule.kt b/benchmark/macro-junit4/src/main/java/androidx/benchmark/macro/junit4/PerfettoRule.kt
index 2891995..3ba31d4 100644
--- a/benchmark/macro-junit4/src/main/java/androidx/benchmark/macro/junit4/PerfettoRule.kt
+++ b/benchmark/macro-junit4/src/main/java/androidx/benchmark/macro/junit4/PerfettoRule.kt
@@ -19,8 +19,7 @@
 import android.os.Build
 import android.util.Log
 import androidx.annotation.RequiresApi
-import androidx.benchmark.Arguments
-import androidx.benchmark.InstrumentationResults
+import androidx.benchmark.Outputs
 import androidx.benchmark.macro.perfetto.PerfettoCapture
 import org.junit.rules.TestRule
 import org.junit.runner.Description
@@ -74,10 +73,11 @@
         Log.d(PerfettoRule.TAG, "Recording perfetto trace $traceName")
         start()
         block()
-        val destinationPath = Arguments.testOutputFile(traceName).absolutePath
-        stop(destinationPath)
-        Log.d(PerfettoRule.TAG, "Finished recording to $destinationPath")
-        InstrumentationResults.reportAdditionalFileToCopy("perfetto_trace", destinationPath)
+        Outputs.writeFile(fileName = traceName, reportKey = "perfetto_trace") {
+            val destinationPath = it.absolutePath
+            stop(destinationPath)
+            Log.d(PerfettoRule.TAG, "Finished recording to $destinationPath")
+        }
     } finally {
         cancel()
     }
diff --git a/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/IdeSummaryStringTest.kt b/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/IdeSummaryStringTest.kt
index 8bed818..b74eca1 100644
--- a/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/IdeSummaryStringTest.kt
+++ b/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/IdeSummaryStringTest.kt
@@ -16,34 +16,69 @@
 
 package androidx.benchmark.macro
 
+import androidx.benchmark.Outputs
 import androidx.benchmark.Stats
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import org.junit.Assert.assertEquals
 import org.junit.Test
 import org.junit.runner.RunWith
+import java.io.File
 import kotlin.test.assertFailsWith
 
 @RunWith(AndroidJUnit4::class)
 @SmallTest
 class IdeSummaryStringTest {
+    private fun createAbsoluteTracePaths(
+        @Suppress("SameParameterValue") count: Int
+    ) = List(count) {
+        File(Outputs.dirUsableByAppAndShell, "iter$it.trace").absolutePath
+    }
+
     @Test
     fun minimalSample() {
         val stats = Stats(longArrayOf(0, 1, 2), "Metric")
+
+        assertEquals(0, stats.minIndex)
+        assertEquals(1, stats.medianIndex)
+        assertEquals(2, stats.maxIndex)
+        val absoluteTracePaths = createAbsoluteTracePaths(3)
+        val (summaryV1, summaryV2) = ideSummaryStrings(
+            warningLines = "",
+            benchmarkName = "foo",
+            statsList = listOf(stats),
+            absoluteTracePaths = absoluteTracePaths
+        )
         assertEquals(
             """
                 |foo
                 |  Metric   min 0,   median 1,   max 2
                 |
             """.trimMargin(),
-            ideSummaryString("", "foo", listOf(stats))
+            summaryV1
+        )
+        assertEquals(
+            """
+                |foo
+                |  Metric   [min 0](file://iter0.trace),   [median 1](file://iter1.trace),   [max 2](file://iter2.trace)
+                |    Traces: Iteration [0](file://iter0.trace) [1](file://iter1.trace) [2](file://iter2.trace)
+                |
+            """.trimMargin(),
+            summaryV2
         )
     }
 
     @Test
     fun complexSample() {
         val metric1 = Stats(longArrayOf(0, 1, 2), "Metric1")
-        val metric2 = Stats(longArrayOf(0, 111, 222), "Metric2")
+        val metric2 = Stats(longArrayOf(222, 111, 0), "Metric2")
+        val absoluteTracePaths = createAbsoluteTracePaths(3)
+        val (summaryV1, summaryV2) = ideSummaryStrings(
+            warningLines = "",
+            benchmarkName = "foo",
+            statsList = listOf(metric1, metric2),
+            absoluteTracePaths = absoluteTracePaths
+        )
         assertEquals(
             """
                 |foo
@@ -51,13 +86,30 @@
                 |  Metric2   min   0,   median 111,   max 222
                 |
             """.trimMargin(),
-            ideSummaryString("", "foo", listOf(metric1, metric2))
+            summaryV1
+        )
+        assertEquals(
+            """
+                |foo
+                |  Metric1   [min   0](file://iter0.trace),   [median   1](file://iter1.trace),   [max   2](file://iter2.trace)
+                |  Metric2   [min   0](file://iter2.trace),   [median 111](file://iter1.trace),   [max 222](file://iter0.trace)
+                |    Traces: Iteration [0](file://iter0.trace) [1](file://iter1.trace) [2](file://iter2.trace)
+                |
+            """.trimMargin(),
+            summaryV2
         )
     }
 
     @Test
     fun warningSample() {
         val stats = Stats(longArrayOf(0, 1, 2), "Metric")
+        val absoluteTracePaths = createAbsoluteTracePaths(3)
+        val (summaryV1, summaryV2) = ideSummaryStrings(
+            warningLines = "warning\nstring\n",
+            benchmarkName = "foo",
+            statsList = listOf(stats),
+            absoluteTracePaths = absoluteTracePaths
+        )
         assertEquals(
             """
                 |warning
@@ -66,14 +118,30 @@
                 |  Metric   min 0,   median 1,   max 2
                 |
             """.trimMargin(),
-            ideSummaryString("warning\nstring\n", "foo", listOf(stats))
+            summaryV1
+        )
+        assertEquals(
+            """
+                |warning
+                |string
+                |foo
+                |  Metric   [min 0](file://iter0.trace),   [median 1](file://iter1.trace),   [max 2](file://iter2.trace)
+                |    Traces: Iteration [0](file://iter0.trace) [1](file://iter1.trace) [2](file://iter2.trace)
+                |
+            """.trimMargin(),
+            summaryV2
         )
     }
 
     @Test
     fun requireNotEmpty() {
         assertFailsWith<IllegalArgumentException> {
-            ideSummaryString(warningLines = "", benchmarkName = "foo", statsList = emptyList())
+            ideSummaryStrings(
+                warningLines = "",
+                benchmarkName = "foo",
+                statsList = emptyList(),
+                absoluteTracePaths = emptyList()
+            ).first
         }
     }
-}
\ No newline at end of file
+}
diff --git a/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/ActionsTest.kt b/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkScopeTest.kt
similarity index 70%
rename from benchmark/macro/src/androidTest/java/androidx/benchmark/macro/ActionsTest.kt
rename to benchmark/macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkScopeTest.kt
index f191f0d..f74f5a4 100644
--- a/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/ActionsTest.kt
+++ b/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/MacrobenchmarkScopeTest.kt
@@ -16,22 +16,25 @@
 
 package androidx.benchmark.macro
 
+import android.content.Intent
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.platform.app.InstrumentationRegistry
-import junit.framework.TestCase.assertTrue
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
 import org.junit.Assert.fail
 import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
+import kotlin.test.assertFailsWith
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
 
 @RunWith(AndroidJUnit4::class)
 @LargeTest
-class ActionsTest {
+class MacrobenchmarkScopeTest {
     @Test
-    @Ignore("Figure out why we can't launch the default activity.")
+    @Ignore("Apk dependencies not working in presubmit, b/181810492")
     fun killTest() {
         val scope = MacrobenchmarkScope(PACKAGE_NAME, launchWithClearTask = true)
         scope.pressHome()
@@ -42,7 +45,7 @@
     }
 
     @Test
-    @Ignore("Compilation modes are a bit flaky")
+    @Ignore("Apk dependencies not working in presubmit, b/181810492")
     fun compile_speedProfile() {
         val scope = MacrobenchmarkScope(PACKAGE_NAME, launchWithClearTask = true)
         val iterations = 1
@@ -57,7 +60,7 @@
     }
 
     @Test
-    @Ignore("Compilation modes are a bit flaky")
+    @Ignore("Apk dependencies not working in presubmit, b/181810492")
     fun compile_speed() {
         val compilation = CompilationMode.Speed
         compilation.compile(PACKAGE_NAME) {
@@ -65,6 +68,24 @@
         }
     }
 
+    @Test
+    @Ignore("Apk dependencies not working in presubmit, b/181810492")
+    fun startActivityAndWait_activityNotExported() {
+        val scope = MacrobenchmarkScope(PACKAGE_NAME, launchWithClearTask = true)
+        scope.pressHome()
+
+        val intent = Intent()
+        intent.setPackage(PACKAGE_NAME)
+        intent.action = "$PACKAGE_NAME.NOT_EXPORTED_ACTIVITY"
+
+        // should throw, warning to set exported = true
+        val exceptionMessage = assertFailsWith<SecurityException> {
+            scope.startActivityAndWait(intent)
+        }.message
+        assertNotNull(exceptionMessage)
+        assertTrue(exceptionMessage.contains("android:exported=true"))
+    }
+
     private fun processes(): List<String> {
         val instrumentation = InstrumentationRegistry.getInstrumentation()
         val output = instrumentation.device().executeShellCommand("ps -A")
diff --git a/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/MetricResultExtensionsTest.kt b/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/MetricResultExtensionsTest.kt
index 5f7faa7..fcaeb5b 100644
--- a/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/MetricResultExtensionsTest.kt
+++ b/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/MetricResultExtensionsTest.kt
@@ -47,6 +47,7 @@
     fun mergeToMetricResults_standard() {
         assertEquals(
             expected = listOf(
+                // note, bar sorted first
                 MetricResult("bar", longArrayOf(101, 301, 201)),
                 MetricResult("foo", longArrayOf(100, 300, 200))
             ),
diff --git a/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureTest.kt b/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureTest.kt
index 8e6513c..ffa8939 100644
--- a/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureTest.kt
+++ b/benchmark/macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureTest.kt
@@ -16,10 +16,10 @@
 
 package androidx.benchmark.macro.perfetto
 
+import androidx.benchmark.Outputs
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
-import androidx.test.platform.app.InstrumentationRegistry
 import androidx.testutils.verifyWithPolling
 import androidx.tracing.Trace
 import androidx.tracing.trace
@@ -33,8 +33,7 @@
 @SdkSuppress(minSdkVersion = 29)
 @RunWith(AndroidJUnit4::class)
 class PerfettoCaptureTest {
-    private val context = InstrumentationRegistry.getInstrumentation().context
-    private val traceFile = File(context.getExternalFilesDir(null), "PerfettoCaptureTest.trace")
+    private val traceFile = File(Outputs.dirUsableByAppAndShell, "PerfettoCaptureTest.trace")
     private val traceFilePath = traceFile.absolutePath
 
     @Before
diff --git a/benchmark/macro/src/main/java/androidx/benchmark/macro/IdeSummaryString.kt b/benchmark/macro/src/main/java/androidx/benchmark/macro/IdeSummaryString.kt
index 303e758..2b79b2e 100644
--- a/benchmark/macro/src/main/java/androidx/benchmark/macro/IdeSummaryString.kt
+++ b/benchmark/macro/src/main/java/androidx/benchmark/macro/IdeSummaryString.kt
@@ -16,15 +16,27 @@
 
 package androidx.benchmark.macro
 
+import androidx.benchmark.Outputs
 import androidx.benchmark.Stats
 import java.util.Collections
 import kotlin.math.max
 
-internal fun ideSummaryString(
+/**
+ * Returns a pair of ideSummaryStrings - v1 (pre Arctic-fox) and v2 (Arctic-fox+)
+ *
+ * These strings are to be displayed in Studio, depending on the version.
+ *
+ * The V2 string embeds links to trace files relative to the output path sent to the IDE via
+ * `[link](file://<relative/path/to/trace>)`
+ *
+ * @see androidx.benchmark.InstrumentationResultScope#ideSummaryRecord
+ */
+internal fun ideSummaryStrings(
     warningLines: String,
     benchmarkName: String,
-    statsList: List<Stats>
-): String {
+    statsList: List<Stats>,
+    absoluteTracePaths: List<String>
+): Pair<String, String> {
     require(statsList.isNotEmpty()) { "Require non-empty list of stats." }
 
     val maxLabelLength = Collections.max(statsList.map { it.name.length })
@@ -35,11 +47,33 @@
         .reduce { acc, maxValue -> max(acc, maxValue) }
         .toString().length
 
-    return warningLines + "$benchmarkName\n" + statsList.joinToString("\n") {
-        val displayName = it.name.padStart(maxLabelLength)
-        val displayMin = it.min.toString().padStart(maxValueLength)
-        val displayMedian = it.median.toString().padStart(maxValueLength)
-        val displayMax = it.max.toString().padStart(maxValueLength)
-        "  $displayName   min $displayMin,   median $displayMedian,   max $displayMax"
-    } + "\n"
+    fun ideSummaryString(
+        transform: (name: String, min: String, median: String, max: String, stats: Stats) -> String
+    ): String {
+        return warningLines + benchmarkName + "\n" + statsList.joinToString("\n") {
+            transform(
+                it.name.padStart(maxLabelLength),
+                it.min.toString().padStart(maxValueLength),
+                it.median.toString().padStart(maxValueLength),
+                it.max.toString().padStart(maxValueLength),
+                it
+            )
+        } + "\n"
+    }
+    val relativeTracePaths = absoluteTracePaths.map { absolutePath ->
+        Outputs.relativePathFor(absolutePath)
+    }
+    return Pair(
+        first = ideSummaryString { name, min, median, max, _ ->
+            "  $name   min $min,   median $median,   max $max"
+        },
+        second = ideSummaryString { name, min, median, max, stats ->
+            "  $name" +
+                "   [min $min](file://${relativeTracePaths[stats.minIndex]})," +
+                "   [median $median](file://${relativeTracePaths[stats.medianIndex]})," +
+                "   [max $max](file://${relativeTracePaths[stats.maxIndex]})"
+        } + "    Traces: Iteration " + relativeTracePaths.mapIndexed { index, path ->
+            "[$index](file://$path)"
+        }.joinToString(separator = " ") + "\n"
+    )
 }
\ No newline at end of file
diff --git a/benchmark/macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt b/benchmark/macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
index c439b79..021bcee 100644
--- a/benchmark/macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
+++ b/benchmark/macro/src/main/java/androidx/benchmark/macro/Macrobenchmark.kt
@@ -169,7 +169,13 @@
         }
         InstrumentationResults.instrumentationReport {
             val statsList = metricResults.map { it.stats }
-            ideSummaryRecord(ideSummaryString(warningMessage, uniqueName, statsList))
+            val (summaryV1, summaryV2) = ideSummaryStrings(
+                warningMessage,
+                uniqueName,
+                statsList,
+                tracePaths
+            )
+            ideSummaryRecord(summaryV1 = summaryV1, summaryV2 = summaryV2)
             warningMessage = "" // warning only printed once
             statsList.forEach { it.putInBundle(bundle, suppressionState?.prefix ?: "") }
         }
diff --git a/benchmark/macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt b/benchmark/macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt
index 102f124..9ab579f 100644
--- a/benchmark/macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt
+++ b/benchmark/macro/src/main/java/androidx/benchmark/macro/MacrobenchmarkScope.kt
@@ -69,7 +69,18 @@
         if (launchWithClearTask) {
             intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
         }
-        context.startActivity(intent)
+        try {
+            context.startActivity(intent)
+        } catch (securityException: SecurityException) {
+            // Android 11 sets exported=false by default, which means we can't launch, but this
+            // can also happen if "android:exported=false" is used directly.
+            throw SecurityException(
+                "Unable to launch Activity due to Security Exception. To launch an " +
+                    "activity from a benchmark, you may need to set android:exported=true " +
+                    "for the Activity in your application's manifest",
+                securityException
+            )
+        }
         device.wait(
             Until.hasObject(By.pkg(packageName).depth(0)),
             5000 /* ms */
diff --git a/benchmark/macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoCapture.kt b/benchmark/macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoCapture.kt
index 267d8c0..6bba7c4 100644
--- a/benchmark/macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoCapture.kt
+++ b/benchmark/macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoCapture.kt
@@ -18,6 +18,7 @@
 
 import androidx.annotation.RequiresApi
 import androidx.annotation.RestrictTo
+import androidx.benchmark.Outputs
 import androidx.benchmark.macro.R
 import androidx.test.platform.app.InstrumentationRegistry
 import java.io.File
@@ -55,7 +56,7 @@
         // Write textproto asset to external files dir, so it can be read by shell
         // TODO: use binary proto (which will also give us rooted 28 support)
         val configBytes = context.resources.openRawResource(R.raw.trace_config).readBytes()
-        val textProtoFile = File(context.getExternalFilesDir(null), "trace_config.textproto")
+        val textProtoFile = File(Outputs.dirUsableByAppAndShell, "trace_config.textproto")
         try {
             textProtoFile.writeBytes(configBytes)
             helper.startCollecting(textProtoFile.absolutePath, true)
diff --git a/benchmark/macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoCaptureWrapper.kt b/benchmark/macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoCaptureWrapper.kt
index 89b50db..d1f8f89 100644
--- a/benchmark/macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoCaptureWrapper.kt
+++ b/benchmark/macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoCaptureWrapper.kt
@@ -19,8 +19,7 @@
 import android.os.Build
 import android.util.Log
 import androidx.annotation.RequiresApi
-import androidx.benchmark.Arguments
-import androidx.benchmark.InstrumentationResults
+import androidx.benchmark.Outputs
 import androidx.benchmark.macro.device
 import androidx.test.platform.app.InstrumentationRegistry
 
@@ -49,19 +48,15 @@
     @RequiresApi(Build.VERSION_CODES.Q)
     private fun stop(benchmarkName: String, iteration: Int): String {
         val iterString = iteration.toString().padStart(3, '0')
-        // NOTE: macrobench still using legacy .trace name until
+        // NOTE: Macrobenchmarks still use legacy .trace name until
         // Studio supports .perfetto-trace extension (b/171251272)
         val traceName = "${benchmarkName}_iter$iterString.trace".replace(
             oldValue = " ",
             newValue = ""
         )
-        val destination = Arguments.testOutputFile(traceName).absolutePath
-        capture!!.stop(destination)
-        InstrumentationResults.reportAdditionalFileToCopy(
-            key = "perfetto_trace_$iterString",
-            absoluteFilePath = destination
-        )
-        return destination
+        return Outputs.writeFile(fileName = traceName, reportKey = "perfetto_trace_$iterString") {
+            capture!!.stop(it.absolutePath)
+        }
     }
 
     fun record(
diff --git a/benchmark/macro/src/main/java/androidx/benchmark/macro/perfetto/ShellUtils.kt b/benchmark/macro/src/main/java/androidx/benchmark/macro/perfetto/ShellUtils.kt
index bba9b68..11d1f00c 100644
--- a/benchmark/macro/src/main/java/androidx/benchmark/macro/perfetto/ShellUtils.kt
+++ b/benchmark/macro/src/main/java/androidx/benchmark/macro/perfetto/ShellUtils.kt
@@ -16,7 +16,7 @@
 
 package androidx.benchmark.macro.perfetto
 
-import androidx.test.platform.app.InstrumentationRegistry
+import androidx.benchmark.Outputs
 import androidx.test.uiautomator.UiDevice
 import java.io.File
 import java.io.InputStream
@@ -36,11 +36,9 @@
  * @param stdin String to pass in as stdin to first command in script
  */
 fun UiDevice.executeShellScript(script: String, stdin: String? = null): String {
-    // externalFilesDir is writable, but we can't execute there (as of Q),
+    // dirUsableByAppAndShell is writable, but we can't execute there (as of Q),
     // so we copy to /data/local/tmp
-    val context = InstrumentationRegistry.getInstrumentation().context
-    val externalDir = context.getExternalFilesDir(null)!!
-
+    val externalDir = Outputs.dirUsableByAppAndShell
     val stdinFile = File.createTempFile("temporaryStdin", null, externalDir)
     val writableScriptFile = File.createTempFile("temporaryScript", "sh", externalDir)
     val runnableScriptPath = "/data/local/tmp/" + writableScriptFile.name
@@ -70,11 +68,9 @@
  * Writes the inputStream to an executable file with the given name in `/data/local/tmp`
  */
 fun UiDevice.createRunnableExecutable(name: String, inputStream: InputStream): String {
-    // externalFilesDir is writable, but we can't execute there (as of Q),
+    // dirUsableByAppAndShell is writable, but we can't execute there (as of Q),
     // so we copy to /data/local/tmp
-    val context = InstrumentationRegistry.getInstrumentation().context
-    val externalDir = context.getExternalFilesDir(null)!!
-
+    val externalDir = Outputs.dirUsableByAppAndShell
     val writableExecutableFile = File.createTempFile(
         /* prefix */ "temporary_$name",
         /* suffix */ null,
diff --git a/buildSrc-tests/src/test/kotlin/androidx/build/testConfiguration/AndroidTestXmlBuilderTest.kt b/buildSrc-tests/src/test/kotlin/androidx/build/testConfiguration/AndroidTestXmlBuilderTest.kt
index 5b8f59b..4798cfc 100644
--- a/buildSrc-tests/src/test/kotlin/androidx/build/testConfiguration/AndroidTestXmlBuilderTest.kt
+++ b/buildSrc-tests/src/test/kotlin/androidx/build/testConfiguration/AndroidTestXmlBuilderTest.kt
@@ -162,7 +162,7 @@
     See the License for the specific language governing permissions
     and limitations under the License.-->
     <configuration description="Runs tests for the module">
-    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController">
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MinApiLevelModuleController">
     <option name="min-api-level" value="15" />
     </object>
     <option name="test-suite-tag" value="placeholder_tag" />
@@ -193,7 +193,7 @@
     See the License for the specific language governing permissions
     and limitations under the License.-->
     <configuration description="Runs tests for the module">
-    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController">
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MinApiLevelModuleController">
     <option name="min-api-level" value="15" />
     </object>
     <option name="test-suite-tag" value="placeholder_tag" />
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXPlaygroundRootPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/AndroidXPlaygroundRootPlugin.kt
index b97e4d7..aa96978 100644
--- a/buildSrc/src/main/kotlin/androidx/build/AndroidXPlaygroundRootPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/AndroidXPlaygroundRootPlugin.kt
@@ -16,6 +16,8 @@
 
 package androidx.build
 
+import androidx.build.AndroidXRootPlugin.Companion.PREBUILT_OR_SNAPSHOT_EXT_NAME
+import androidx.build.AndroidXRootPlugin.Companion.PROJECT_OR_ARTIFACT_EXT_NAME
 import androidx.build.gradle.isRoot
 import groovy.util.XmlParser
 import groovy.xml.QName
@@ -52,6 +54,12 @@
         }
     )
 
+    private val prebuiltOrSnapshotClosure = KotlinClosure1<String, String>(
+        function = {
+            prebuiltOrSnapshot(this)
+        }
+    )
+
     override fun apply(target: Project) {
         if (!target.isRoot) {
             throw GradleException("This plugin should only be applied to root project")
@@ -72,7 +80,8 @@
 
     private fun configureSubProject(project: Project) {
         project.repositories.addPlaygroundRepositories()
-        project.extra.set(AndroidXRootPlugin.PROJECT_OR_ARTIFACT_EXT_NAME, projectOrArtifactClosure)
+        project.extra.set(PROJECT_OR_ARTIFACT_EXT_NAME, projectOrArtifactClosure)
+        project.extra.set(PREBUILT_OR_SNAPSHOT_EXT_NAME, prebuiltOrSnapshotClosure)
         project.configurations.all { configuration ->
             configuration.resolutionStrategy.dependencySubstitution.all { substitution ->
                 substitution.allowAndroidxSnapshotReplacement()
@@ -118,6 +127,21 @@
         }
     }
 
+    private fun prebuiltOrSnapshot(path: String): String {
+        val sections = path.split(":")
+
+        if (sections.size != 3) {
+            throw GradleException(
+                "Expected prebuiltOrSnapshot path to be of the form " +
+                    "<group>:<artifact>:<version>, but was $path"
+            )
+        }
+
+        val group = sections[0]
+        val artifact = sections[1]
+        return "$group:$artifact:$SNAPSHOT_MARKER"
+    }
+
     private fun DependencySubstitution.allowAndroidxSnapshotReplacement() {
         val requested = this.requested
         if (requested is ModuleComponentSelector && requested.group.startsWith("androidx") &&
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXRootPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/AndroidXRootPlugin.kt
index 6420a50..1d82fb3 100644
--- a/buildSrc/src/main/kotlin/androidx/build/AndroidXRootPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/AndroidXRootPlugin.kt
@@ -101,6 +101,15 @@
                     }
                 )
             )
+            project.extra.set(
+                PREBUILT_OR_SNAPSHOT_EXT_NAME,
+                KotlinClosure1<String, String>(
+                    function = {
+                        // this refers to the first parameter of the closure.
+                        this
+                    }
+                )
+            )
             project.plugins.withType(AndroidBasePlugin::class.java) {
                 buildOnServerTask.dependsOn("${project.path}:assembleDebug")
                 buildOnServerTask.dependsOn("${project.path}:assembleAndroidTest")
@@ -226,5 +235,6 @@
 
     companion object {
         const val PROJECT_OR_ARTIFACT_EXT_NAME = "projectOrArtifact"
+        const val PREBUILT_OR_SNAPSHOT_EXT_NAME = "prebuiltOrSnapshot"
     }
 }
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
index 18056af7..ca5eda1 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
@@ -22,7 +22,7 @@
 object LibraryVersions {
     val ACTIVITY = Version("1.3.0-alpha04")
     val ADS_IDENTIFIER = Version("1.0.0-alpha04")
-    val ANNOTATION = Version("1.2.0-rc01")
+    val ANNOTATION = Version("1.3.0-alpha01")
     val ANNOTATION_EXPERIMENTAL = Version("1.1.0-rc01")
     val APPCOMPAT = Version("1.3.0-beta02")
     val APPSEARCH = Version("1.0.0-alpha01")
@@ -48,7 +48,7 @@
     val CONTENTPAGER = Version("1.1.0-alpha01")
     val COMPOSE = Version(System.getenv("COMPOSE_CUSTOM_VERSION") ?: "1.0.0-beta02")
     val COORDINATORLAYOUT = Version("1.2.0-alpha01")
-    val CORE = Version("1.5.0-beta02")
+    val CORE = Version("1.5.0-beta03")
     val CORE_ANIMATION = Version("1.0.0-alpha03")
     val CORE_ANIMATION_TESTING = Version("1.0.0-alpha03")
     val CORE_APPDIGEST = Version("1.0.0-alpha01")
@@ -144,7 +144,7 @@
     val WEAR_WATCHFACE_EDITOR = Version("1.0.0-alpha09")
     val WEAR_WATCHFACE_STYLE = Version("1.0.0-alpha09")
     val WEBKIT = Version("1.5.0-alpha01")
-    val WINDOW = Version("1.0.0-alpha04")
+    val WINDOW = Version("1.0.0-alpha05")
     val WINDOW_EXTENSIONS = Version("1.0.0-alpha01")
     val WINDOW_SIDECAR = Version("0.1.0-alpha01")
     val WORK = Version("2.6.0-alpha01")
diff --git a/buildSrc/src/main/kotlin/androidx/build/LintConfiguration.kt b/buildSrc/src/main/kotlin/androidx/build/LintConfiguration.kt
index 4ce1461..6c4446d 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LintConfiguration.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LintConfiguration.kt
@@ -159,6 +159,11 @@
                 disable("BanUncheckedReflection")
             }
 
+            // Only run certain checks where API tracking is important.
+            if (extension.type.checkApi is RunApiTasks.No) {
+                disable("IllegalExperimentalApiUsage")
+            }
+
             // If the project has not overridden the lint config, set the default one.
             if (lintConfig == null) {
                 // suppress warnings more specifically than issue-wide severity (regexes)
diff --git a/buildSrc/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt b/buildSrc/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt
index 2f70c19..5bcc7646 100644
--- a/buildSrc/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt
@@ -24,6 +24,7 @@
 import org.gradle.api.attributes.DocsType
 import org.gradle.api.attributes.Usage
 import org.gradle.api.component.AdhocComponentWithVariants
+import org.gradle.api.file.DuplicatesStrategy
 import org.gradle.api.plugins.JavaPluginConvention
 import org.gradle.api.tasks.TaskProvider
 import org.gradle.api.tasks.bundling.Jar
@@ -40,6 +41,8 @@
         val sourceJar = tasks.register("sourceJar${variant.name.capitalize()}", Jar::class.java) {
             it.archiveClassifier.set("sources")
             it.from(extension.sourceSets.getByName("main").java.srcDirs)
+            // Do not allow source files with duplicate names, information would be lost otherwise.
+            it.duplicatesStrategy = DuplicatesStrategy.FAIL
         }
         registerSourcesVariant(sourceJar)
     }
@@ -69,6 +72,8 @@
         it.archiveClassifier.set("sources")
         val convention = convention.getPlugin<JavaPluginConvention>()
         it.from(convention.sourceSets.getByName("main").allSource.srcDirs)
+        // Do not allow source files with duplicate names, information would be lost otherwise.
+        it.duplicatesStrategy = DuplicatesStrategy.FAIL
     }
     registerSourcesVariant(sourceJar)
 }
@@ -81,15 +86,15 @@
             Usage.USAGE_ATTRIBUTE,
             objects.named(Usage.JAVA_RUNTIME)
         )
-        gradleVariant.getAttributes().attribute(
+        gradleVariant.attributes.attribute(
             Category.CATEGORY_ATTRIBUTE,
             objects.named(Category.DOCUMENTATION)
         )
-        gradleVariant.getAttributes().attribute(
+        gradleVariant.attributes.attribute(
             Bundling.BUNDLING_ATTRIBUTE,
             objects.named(Bundling.EXTERNAL)
         )
-        gradleVariant.getAttributes().attribute(
+        gradleVariant.attributes.attribute(
             DocsType.DOCS_TYPE_ATTRIBUTE,
             objects.named(DocsType.SOURCES)
         )
diff --git a/buildSrc/src/main/kotlin/androidx/build/testConfiguration/AndroidTestXmlBuilder.kt b/buildSrc/src/main/kotlin/androidx/build/testConfiguration/AndroidTestXmlBuilder.kt
index d439f0c..fdee719 100644
--- a/buildSrc/src/main/kotlin/androidx/build/testConfiguration/AndroidTestXmlBuilder.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/testConfiguration/AndroidTestXmlBuilder.kt
@@ -244,7 +244,7 @@
 """.trimIndent()
 
 private val MIN_API_LEVEL_CONTROLLER_OBJECT = """
-    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController">
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MinApiLevelModuleController">
     <option name="min-api-level" value="MIN_SDK" />
     </object>
 
diff --git a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt
index 0bf359a..311be3f 100644
--- a/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt
+++ b/camera/camera-camera2-pipe-integration/src/main/java/androidx/camera/camera2/pipe/integration/adapter/CameraInfoAdapter.kt
@@ -28,6 +28,7 @@
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.ExposureState
 import androidx.camera.core.ZoomState
+import androidx.camera.core.impl.CamcorderProfileProvider
 import androidx.camera.core.impl.CameraCaptureCallback
 import androidx.camera.core.impl.CameraInfoInternal
 import androidx.camera.core.impl.Quirks
@@ -91,6 +92,12 @@
         cameraCallbackMap.removeCaptureCallback(callback)
 
     override fun getImplementationType(): String = "CameraPipe"
+
+    override fun getCamcorderProfileProvider(): CamcorderProfileProvider {
+        Log.warn { "TODO: CamcorderProfileProvider is not yet supported." }
+        return CamcorderProfileProvider.EMPTY
+    }
+
     override fun toString(): String = "CameraInfoAdapter<$cameraConfig.cameraId>"
 
     override fun getCameraQuirks(): Quirks {
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/VideoCaptureTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/VideoCaptureTest.kt
index 6d1c986..71554f9 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/VideoCaptureTest.kt
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/VideoCaptureTest.kt
@@ -32,6 +32,7 @@
 import androidx.camera.testing.CameraUtil
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
 import androidx.test.platform.app.InstrumentationRegistry
@@ -173,6 +174,7 @@
         parcelFileDescriptor.close()
     }
 
+    @FlakyTest // b/182165222
     @Test
     fun unbind_shouldStopRecording() {
         val file = File.createTempFile("CameraX", ".tmp").apply {
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProviderTest.kt b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProviderTest.kt
new file mode 100644
index 0000000..ad7a76e
--- /dev/null
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProviderTest.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2021 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.camera.camera2.internal
+
+import android.hardware.camera2.CameraCharacteristics
+import android.media.CamcorderProfile
+import android.util.Size
+import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.impl.ImageFormatConstants
+import androidx.camera.testing.CameraUtil
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+
+@RunWith(Parameterized::class)
+@SmallTest
+public class Camera2CamcorderProfileProviderTest(private val quality: Int) {
+    public companion object {
+        @JvmStatic
+        @Parameterized.Parameters
+        public fun data(): Array<Array<Int>> = arrayOf(
+            arrayOf(CamcorderProfile.QUALITY_LOW),
+            arrayOf(CamcorderProfile.QUALITY_HIGH),
+            arrayOf(CamcorderProfile.QUALITY_QCIF),
+            arrayOf(CamcorderProfile.QUALITY_CIF),
+            arrayOf(CamcorderProfile.QUALITY_480P),
+            arrayOf(CamcorderProfile.QUALITY_720P),
+            arrayOf(CamcorderProfile.QUALITY_1080P),
+            arrayOf(CamcorderProfile.QUALITY_QVGA),
+            arrayOf(CamcorderProfile.QUALITY_2160P),
+            arrayOf(CamcorderProfile.QUALITY_VGA),
+            arrayOf(CamcorderProfile.QUALITY_4KDCI),
+            arrayOf(CamcorderProfile.QUALITY_QHD),
+            arrayOf(CamcorderProfile.QUALITY_2K)
+        )
+    }
+
+    private lateinit var camcorderProfileProvider: Camera2CamcorderProfileProvider
+    private lateinit var cameraCharacteristics: CameraCharacteristicsCompat
+    private var isLegacyCamera = false
+    private var intCameraId = -1
+
+    @Before
+    public fun setup() {
+        assumeTrue(CameraUtil.hasCameraWithLensFacing(CameraSelector.LENS_FACING_BACK))
+
+        val cameraId = CameraUtil.getCameraIdWithLensFacing(CameraSelector.LENS_FACING_BACK)!!
+        intCameraId = cameraId.toInt()
+
+        cameraCharacteristics = CameraCharacteristicsCompat.toCameraCharacteristicsCompat(
+            CameraUtil.getCameraCharacteristics(CameraSelector.LENS_FACING_BACK)!!
+        )
+        val hardwareLevel =
+            cameraCharacteristics[CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL]
+
+        isLegacyCamera = hardwareLevel != null && hardwareLevel == CameraCharacteristics
+            .INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
+
+        camcorderProfileProvider = Camera2CamcorderProfileProvider(cameraId, cameraCharacteristics)
+    }
+
+    @Test
+    public fun nonLegacyCamera_hasProfile_returnSameResult() {
+        assumeTrue(!isLegacyCamera)
+
+        assertThat(camcorderProfileProvider.hasProfile(quality))
+            .isEqualTo(CamcorderProfile.hasProfile(intCameraId, quality))
+    }
+
+    @Test
+    public fun nonLegacyCamera_notHasProfile_getReturnNull() {
+        assumeTrue(!isLegacyCamera)
+        assumeTrue(!CamcorderProfile.hasProfile(intCameraId, quality))
+
+        assertThat(camcorderProfileProvider.get(quality)).isNull()
+    }
+
+    @Test
+    public fun nonLegacyCamera_hasProfile_getReturnSameQualityProfile() {
+        assumeTrue(!isLegacyCamera)
+        assumeTrue(CamcorderProfile.hasProfile(intCameraId, quality))
+
+        val profileProxy = camcorderProfileProvider.get(quality)!!
+        val profile = CamcorderProfile.get(intCameraId, quality)
+        assertThat(profileProxy.quality).isEqualTo(profile.quality)
+    }
+
+    @Test
+    public fun legacyCamera_notHasProfile_returnFalse() {
+        assumeTrue(isLegacyCamera)
+        assumeTrue(!CamcorderProfile.hasProfile(intCameraId, quality))
+
+        assertThat(camcorderProfileProvider.hasProfile(quality)).isFalse()
+    }
+
+    @Test
+    public fun legacyCamera_hasProfile_shouldCheckSupportedResolution() {
+        assumeTrue(isLegacyCamera)
+        assumeTrue(CamcorderProfile.hasProfile(intCameraId, quality))
+
+        val videoSupportedResolutions = getVideoSupportedResolutions()
+        val isResolutionSupported =
+            videoSupportedResolutions.contains(CamcorderProfile.get(intCameraId, quality).size())
+
+        assertThat(camcorderProfileProvider.hasProfile(quality)).isEqualTo(isResolutionSupported)
+    }
+
+    @Test
+    public fun legacyCamera_notHasProfile_getReturnNull() {
+        assumeTrue(isLegacyCamera)
+        assumeTrue(!CamcorderProfile.hasProfile(intCameraId, quality))
+
+        assertThat(camcorderProfileProvider.get(quality)).isNull()
+    }
+
+    @Test
+    public fun legacyCamera_hasProfile_getShouldCheckSupportedResolution() {
+        assumeTrue(isLegacyCamera)
+        assumeTrue(CamcorderProfile.hasProfile(intCameraId, quality))
+
+        val profile = CamcorderProfile.get(intCameraId, quality)
+        val videoSupportedResolutions = getVideoSupportedResolutions()
+        val isResolutionSupported = videoSupportedResolutions.contains(profile.size())
+
+        val profileProxy = camcorderProfileProvider.get(quality)
+        if (isResolutionSupported) {
+            assertThat(profileProxy!!.quality).isEqualTo(profile.quality)
+        } else {
+            assertThat(profileProxy).isNull()
+        }
+    }
+
+    private fun getVideoSupportedResolutions(): Array<Size> {
+        val map = cameraCharacteristics[CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP]!!
+        return map.getOutputSizes(ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE)
+            ?: emptyArray()
+    }
+
+    private fun CamcorderProfile.size() = Size(videoFrameWidth, videoFrameHeight)
+}
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProvider.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProvider.java
new file mode 100644
index 0000000..a1040d8
--- /dev/null
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CamcorderProfileProvider.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2021 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.camera.camera2.internal;
+
+import android.media.CamcorderProfile;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat;
+import androidx.camera.camera2.internal.compat.quirk.CamcorderProfileResolutionQuirk;
+import androidx.camera.camera2.internal.compat.quirk.CameraQuirks;
+import androidx.camera.camera2.internal.compat.workaround.CamcorderProfileResolutionValidator;
+import androidx.camera.core.Logger;
+import androidx.camera.core.impl.CamcorderProfileProvider;
+import androidx.camera.core.impl.CamcorderProfileProxy;
+
+/** An implementation that provides the {@link CamcorderProfileProxy}. */
+public class Camera2CamcorderProfileProvider implements CamcorderProfileProvider {
+    private static final String TAG = "Camera2CamcorderProfileProvider";
+
+    private final boolean mHasValidCameraId;
+    private final int mCameraId;
+    private final CamcorderProfileResolutionValidator mCamcorderProfileResolutionValidator;
+
+    public Camera2CamcorderProfileProvider(@NonNull String cameraId,
+            @NonNull CameraCharacteristicsCompat cameraCharacteristics) {
+        boolean hasValidCameraId = false;
+        int intCameraId = -1;
+        try {
+            intCameraId = Integer.parseInt(cameraId);
+            hasValidCameraId = true;
+        } catch (NumberFormatException e) {
+            Logger.w(TAG, "Camera id is not an integer: " + cameraId
+                    + ", unable to create CamcorderProfileProvider");
+        }
+        mHasValidCameraId = hasValidCameraId;
+        mCameraId = intCameraId;
+        CamcorderProfileResolutionQuirk quirk = CameraQuirks.get(cameraId, cameraCharacteristics)
+                .get(CamcorderProfileResolutionQuirk.class);
+        mCamcorderProfileResolutionValidator = new CamcorderProfileResolutionValidator(quirk);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean hasProfile(int quality) {
+        if (!mHasValidCameraId) {
+            return false;
+        }
+
+        if (!CamcorderProfile.hasProfile(mCameraId, quality)) {
+            return false;
+        }
+
+        if (mCamcorderProfileResolutionValidator.hasQuirk()) {
+            // Only get profile when quirk exist for performance concern.
+            CamcorderProfileProxy profile = getProfileInternal(quality);
+            return mCamcorderProfileResolutionValidator.hasValidVideoResolution(profile);
+        }
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nullable
+    public CamcorderProfileProxy get(int quality) {
+        if (!mHasValidCameraId) {
+            return null;
+        }
+
+        if (!CamcorderProfile.hasProfile(mCameraId, quality)) {
+            return null;
+        }
+
+        CamcorderProfileProxy profile = getProfileInternal(quality);
+        if (!mCamcorderProfileResolutionValidator.hasValidVideoResolution(profile)) {
+            return null;
+        }
+        return profile;
+    }
+
+    @Nullable
+    private CamcorderProfileProxy getProfileInternal(int quality) {
+        CamcorderProfile profile = null;
+        try {
+            profile = CamcorderProfile.get(mCameraId, quality);
+        } catch (RuntimeException e) {
+            // CamcorderProfile.get() will throw
+            // - RuntimeException if not able to retrieve camcorder profile params.
+            // - IllegalArgumentException if quality is not valid.
+            Logger.w(TAG, "Unable to get CamcorderProfile by quality: " + quality, e);
+        }
+        return profile != null ? CamcorderProfileProxy.fromCamcorderProfile(profile) : null;
+    }
+}
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java
index b31c41c..69c20f1 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/Camera2CameraInfoImpl.java
@@ -34,6 +34,7 @@
 import androidx.camera.core.ExposureState;
 import androidx.camera.core.Logger;
 import androidx.camera.core.ZoomState;
+import androidx.camera.core.impl.CamcorderProfileProvider;
 import androidx.camera.core.impl.CameraCaptureCallback;
 import androidx.camera.core.impl.CameraInfoInternal;
 import androidx.camera.core.impl.ImageOutputConfig.RotationValue;
@@ -84,6 +85,8 @@
 
     @NonNull
     private final Quirks mCameraQuirks;
+    @NonNull
+    private final CamcorderProfileProvider mCamera2CamcorderProfileProvider;
 
     /**
      * Constructs an instance. Before {@link #linkWithCameraControl(Camera2CameraControlImpl)} is
@@ -95,6 +98,8 @@
         mCameraCharacteristicsCompat = cameraCharacteristicsCompat;
         mCamera2CameraInfo = new Camera2CameraInfo(this);
         mCameraQuirks = CameraQuirks.get(cameraId, cameraCharacteristicsCompat);
+        mCamera2CamcorderProfileProvider = new Camera2CamcorderProfileProvider(cameraId,
+                cameraCharacteristicsCompat);
     }
 
     /**
@@ -305,6 +310,13 @@
                 ? IMPLEMENTATION_TYPE_CAMERA2_LEGACY : IMPLEMENTATION_TYPE_CAMERA2;
     }
 
+    /** {@inheritDoc} */
+    @NonNull
+    @Override
+    public CamcorderProfileProvider getCamcorderProfileProvider() {
+        return mCamera2CamcorderProfileProvider;
+    }
+
     @Override
     public void addSessionCaptureCallback(@NonNull Executor executor,
             @NonNull CameraCaptureCallback callback) {
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/CamcorderProfileResolutionQuirk.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/CamcorderProfileResolutionQuirk.java
new file mode 100644
index 0000000..f2ee3d2
--- /dev/null
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/CamcorderProfileResolutionQuirk.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2021 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.camera.camera2.internal.compat.quirk;
+
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.CamcorderProfile;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat;
+import androidx.camera.core.Logger;
+import androidx.camera.core.impl.ImageFormatConstants;
+import androidx.camera.core.impl.Quirk;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Quirk that should validate the video resolution of {@link CamcorderProfile} on legacy camera.
+ *
+ * <p>
+ * When using the Camera 2 API in {@code LEGACY} mode (i.e. when
+ * {@link android.hardware.camera2.CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} is set
+ * to
+ * {@link android.hardware.camera2.CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY}),
+ * {@link CamcorderProfile#hasProfile} may return {@code true} for unsupported resolutions. To
+ * ensure a given resolution is supported in LEGACY mode, the configuration given in
+ * {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP}
+ * must contain the resolution in the supported output sizes. The recommended way to check this
+ * is with {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes(Class)}
+ * with the class of the desired recording endpoint, and check that the desired resolution is
+ * contained in the list returned.
+ * </p>
+ *
+ * @see CamcorderProfile#hasProfile
+ */
+public class CamcorderProfileResolutionQuirk implements Quirk {
+    private static final String TAG = "CamcorderProfileResolutionQuirk";
+
+    static boolean load(@NonNull CameraCharacteristicsCompat characteristicsCompat) {
+        final Integer level = characteristicsCompat.get(
+                CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
+        return level != null && level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
+    }
+
+    private final List<Size> mSupportedResolutions;
+
+    public CamcorderProfileResolutionQuirk(
+            @NonNull CameraCharacteristicsCompat characteristicsCompat) {
+        StreamConfigurationMap map =
+                characteristicsCompat.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+        if (map == null) {
+            Logger.e(TAG, "StreamConfigurationMap is null");
+        }
+        Size[] sizes = map != null ? map.getOutputSizes(
+                ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE) : null;
+        mSupportedResolutions = sizes != null ? Arrays.asList(sizes.clone())
+                : Collections.emptyList();
+
+        Logger.d(TAG, "mSupportedResolutions = " + mSupportedResolutions);
+    }
+
+    /** Returns the supported video resolutions. */
+    @NonNull
+    public List<Size> getSupportedResolutions() {
+        return new ArrayList<>(mSupportedResolutions);
+    }
+}
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/CameraQuirks.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/CameraQuirks.java
index 473ea83..c76c712 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/CameraQuirks.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/quirk/CameraQuirks.java
@@ -56,6 +56,9 @@
         if (JpegHalCorruptImageQuirk.load(cameraCharacteristicsCompat)) {
             quirks.add(new JpegHalCorruptImageQuirk());
         }
+        if (CamcorderProfileResolutionQuirk.load(cameraCharacteristicsCompat)) {
+            quirks.add(new CamcorderProfileResolutionQuirk(cameraCharacteristicsCompat));
+        }
         return new Quirks(quirks);
     }
 }
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/workaround/CamcorderProfileResolutionValidator.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/workaround/CamcorderProfileResolutionValidator.java
new file mode 100644
index 0000000..3d46881
--- /dev/null
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/internal/compat/workaround/CamcorderProfileResolutionValidator.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2021 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.camera.camera2.internal.compat.workaround;
+
+import android.media.CamcorderProfile;
+import android.util.Size;
+
+import androidx.annotation.Nullable;
+import androidx.camera.camera2.internal.compat.quirk.CamcorderProfileResolutionQuirk;
+import androidx.camera.core.impl.CamcorderProfileProxy;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Validates the video resolution of {@link CamcorderProfile}.
+ *
+ * @see CamcorderProfileResolutionQuirk
+ */
+public class CamcorderProfileResolutionValidator {
+
+    private final CamcorderProfileResolutionQuirk mQuirk;
+    private final Set<Size> mSupportedResolutions;
+
+    public CamcorderProfileResolutionValidator(@Nullable CamcorderProfileResolutionQuirk quirk) {
+        mQuirk = quirk;
+        mSupportedResolutions = quirk != null ? new HashSet<>(quirk.getSupportedResolutions()) :
+                Collections.emptySet();
+    }
+
+    /** Checks if this validator contains quirk. */
+    public boolean hasQuirk() {
+        return mQuirk != null;
+    }
+
+    /** Checks if the video resolution of CamcorderProfile is valid. */
+    public boolean hasValidVideoResolution(@Nullable CamcorderProfileProxy profile) {
+        if (profile == null) {
+            return false;
+        }
+
+        if (mQuirk == null) {
+            // Quirk doesn't exist, always valid.
+            return true;
+        }
+
+        Size videoSize = new Size(profile.getVideoFrameWidth(), profile.getVideoFrameHeight());
+        return mSupportedResolutions.contains(videoSize);
+    }
+}
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/quirk/CamcorderProfileResolutionQuirkTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/quirk/CamcorderProfileResolutionQuirkTest.kt
new file mode 100644
index 0000000..9f62a037
--- /dev/null
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/quirk/CamcorderProfileResolutionQuirkTest.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2021 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.camera.camera2.internal.compat.quirk
+
+import android.hardware.camera2.CameraCharacteristics
+import android.hardware.camera2.CameraMetadata
+import android.hardware.camera2.params.StreamConfigurationMap
+import android.os.Build
+import android.util.Size
+import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat
+import androidx.camera.testing.CamcorderProfileUtil.RESOLUTION_1080P
+import androidx.camera.testing.CamcorderProfileUtil.RESOLUTION_2160P
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.mock
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+import org.robolectric.shadow.api.Shadow
+import org.robolectric.shadows.ShadowCameraCharacteristics
+
+@RunWith(RobolectricTestRunner::class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+public class CamcorderProfileResolutionQuirkTest {
+
+    @Test
+    public fun loadByHardwareLevel() {
+        var cameraCharacteristicsCompat =
+            createCameraCharacteristicsCompat(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL)
+        assertThat(CamcorderProfileResolutionQuirk.load(cameraCharacteristicsCompat)).isFalse()
+
+        cameraCharacteristicsCompat =
+            createCameraCharacteristicsCompat(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_3)
+        assertThat(CamcorderProfileResolutionQuirk.load(cameraCharacteristicsCompat)).isFalse()
+
+        cameraCharacteristicsCompat =
+            createCameraCharacteristicsCompat(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED)
+        assertThat(CamcorderProfileResolutionQuirk.load(cameraCharacteristicsCompat)).isFalse()
+
+        cameraCharacteristicsCompat =
+            createCameraCharacteristicsCompat(CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY)
+        assertThat(CamcorderProfileResolutionQuirk.load(cameraCharacteristicsCompat)).isTrue()
+    }
+
+    @Test
+    public fun canGetCorrectSupportedSizes() {
+        val cameraCharacteristicsCompat =
+            createCameraCharacteristicsCompat(
+                supportedSizes = arrayOf(
+                    RESOLUTION_2160P,
+                    RESOLUTION_1080P
+                )
+            )
+        val quirk = CamcorderProfileResolutionQuirk(cameraCharacteristicsCompat)
+
+        assertThat(quirk.supportedResolutions[0]).isEqualTo(RESOLUTION_2160P)
+        assertThat(quirk.supportedResolutions[1]).isEqualTo(RESOLUTION_1080P)
+    }
+
+    private fun createCameraCharacteristicsCompat(
+        hardwareLevel: Int = CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
+        supportedSizes: Array<Size> = emptyArray()
+    ): CameraCharacteristicsCompat {
+        val characteristics = ShadowCameraCharacteristics.newCameraCharacteristics()
+        val shadowCharacteristics = Shadow.extract<ShadowCameraCharacteristics>(characteristics)
+
+        shadowCharacteristics.set(
+            CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL,
+            hardwareLevel
+        )
+
+        val mockMap = mock(StreamConfigurationMap::class.java)
+        `when`(mockMap.getOutputSizes(ArgumentMatchers.anyInt())).thenReturn(supportedSizes)
+
+        shadowCharacteristics.set(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP, mockMap)
+
+        return CameraCharacteristicsCompat.toCameraCharacteristicsCompat(characteristics)
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/CamcorderProfileResolutionValidatorTest.kt b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/CamcorderProfileResolutionValidatorTest.kt
new file mode 100644
index 0000000..515aaff
--- /dev/null
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/internal/compat/workaround/CamcorderProfileResolutionValidatorTest.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2021 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.camera.camera2.internal.compat.workaround
+
+import android.hardware.camera2.CameraCharacteristics
+import android.hardware.camera2.params.StreamConfigurationMap
+import android.os.Build
+import android.util.Size
+import androidx.camera.camera2.internal.compat.CameraCharacteristicsCompat
+import androidx.camera.camera2.internal.compat.quirk.CamcorderProfileResolutionQuirk
+import androidx.camera.testing.CamcorderProfileUtil.PROFILE_2160P
+import androidx.camera.testing.CamcorderProfileUtil.PROFILE_720P
+import androidx.camera.testing.CamcorderProfileUtil.RESOLUTION_2160P
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+import org.robolectric.shadow.api.Shadow
+import org.robolectric.shadows.ShadowCameraCharacteristics
+
+@RunWith(RobolectricTestRunner::class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+public class CamcorderProfileResolutionValidatorTest {
+
+    @Test
+    public fun noQuirk_alwaysValid() {
+        val validator = CamcorderProfileResolutionValidator(null)
+
+        assertThat(validator.hasValidVideoResolution(PROFILE_2160P)).isTrue()
+        assertThat(validator.hasValidVideoResolution(PROFILE_720P)).isTrue()
+    }
+
+    @Test
+    public fun hasQuirk_shouldCheckSupportedResolutions() {
+        val cameraCharacteristicsCompat = createCameraCharacteristicsCompat(
+            supportedResolution = arrayOf(RESOLUTION_2160P)
+        )
+        val quirk = CamcorderProfileResolutionQuirk(cameraCharacteristicsCompat)
+        val validator = CamcorderProfileResolutionValidator(quirk)
+
+        assertThat(validator.hasValidVideoResolution(PROFILE_2160P)).isTrue()
+        assertThat(validator.hasValidVideoResolution(PROFILE_720P)).isFalse()
+    }
+
+    @Test
+    public fun nullProfile_notValid() {
+        val cameraCharacteristicsCompat = createCameraCharacteristicsCompat(
+            supportedResolution = arrayOf(RESOLUTION_2160P)
+        )
+        val quirk = CamcorderProfileResolutionQuirk(cameraCharacteristicsCompat)
+        val validator = CamcorderProfileResolutionValidator(quirk)
+
+        assertThat(validator.hasValidVideoResolution(null)).isFalse()
+    }
+
+    private fun createCameraCharacteristicsCompat(
+        supportedResolution: Array<Size> = emptyArray()
+    ): CameraCharacteristicsCompat {
+        val characteristics = ShadowCameraCharacteristics.newCameraCharacteristics()
+        val shadowCharacteristics = Shadow.extract<ShadowCameraCharacteristics>(characteristics)
+
+        val mockMap = Mockito.mock(StreamConfigurationMap::class.java)
+        `when`(mockMap.getOutputSizes(ArgumentMatchers.anyInt())).thenReturn(supportedResolution)
+
+        shadowCharacteristics.set(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP, mockMap)
+
+        return CameraCharacteristicsCompat.toCameraCharacteristicsCompat(characteristics)
+    }
+}
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/CamcorderProfileProxyTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/CamcorderProfileProxyTest.kt
new file mode 100644
index 0000000..1f560eb
--- /dev/null
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/CamcorderProfileProxyTest.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2021 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.camera.core.impl
+
+import android.media.CamcorderProfile
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assume.assumeTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+public class CamcorderProfileProxyTest {
+
+    @Test
+    public fun createInstance() {
+        // QUALITY_HIGH is guaranteed to be supported.
+        assumeTrue(CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_HIGH))
+
+        val profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)
+        val profileProxy = CamcorderProfileProxy.fromCamcorderProfile(profile)
+
+        assertThat(profileProxy.duration).isEqualTo(profile.duration)
+        assertThat(profileProxy.quality).isEqualTo(profile.quality)
+        assertThat(profileProxy.fileFormat).isEqualTo(profile.fileFormat)
+        assertThat(profileProxy.videoCodec).isEqualTo(profile.videoCodec)
+        assertThat(profileProxy.videoBitRate).isEqualTo(profile.videoBitRate)
+        assertThat(profileProxy.videoFrameRate).isEqualTo(profile.videoFrameRate)
+        assertThat(profileProxy.videoFrameWidth).isEqualTo(profile.videoFrameWidth)
+        assertThat(profileProxy.videoFrameHeight).isEqualTo(profile.videoFrameHeight)
+        assertThat(profileProxy.audioCodec).isEqualTo(profile.audioCodec)
+        assertThat(profileProxy.audioBitRate).isEqualTo(profile.audioBitRate)
+        assertThat(profileProxy.audioSampleRate).isEqualTo(profile.audioSampleRate)
+        assertThat(profileProxy.audioChannels).isEqualTo(profile.audioChannels)
+    }
+}
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/ConstantObservableTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/ConstantObservableTest.kt
index 8e6a633..a76dc4d 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/ConstantObservableTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/ConstantObservableTest.kt
@@ -16,17 +16,20 @@
 
 package androidx.camera.core.impl
 
+import androidx.camera.core.impl.utils.executor.CameraXExecutors
 import androidx.camera.testing.asFlow
 import androidx.concurrent.futures.await
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.runBlocking
 import org.junit.Test
 import org.junit.runner.RunWith
 
 private const val MAGIC_VALUE = 42
+private const val MAGIC_STRING = "Magic"
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
@@ -52,4 +55,27 @@
         val value = constantObservable.asFlow().first()
         assertThat(value).isEqualTo(MAGIC_VALUE)
     }
+
+    @Test
+    public fun observerOfSuperClass_receivesValue(): Unit = runBlocking {
+        val constantObservable: Observable<String> = ConstantObservable.withValue(MAGIC_STRING)
+
+        // Create on observer of CharSequence, a superclass of String
+        val deferredValue = CompletableDeferred<CharSequence?>()
+        val observer: Observable.Observer<CharSequence> = object :
+            Observable.Observer<CharSequence> {
+            override fun onNewData(value: CharSequence?) {
+                deferredValue.complete(value)
+            }
+
+            override fun onError(t: Throwable) {
+                deferredValue.completeExceptionally(t)
+            }
+        }
+
+        // Add the observer to receive the value
+        constantObservable.addObserver(CameraXExecutors.directExecutor(), observer)
+
+        assertThat(deferredValue.await()).isEqualTo(MAGIC_STRING)
+    }
 }
\ No newline at end of file
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/LiveDataObservableTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/LiveDataObservableTest.kt
index a4f3b38..805fb7b 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/LiveDataObservableTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/LiveDataObservableTest.kt
@@ -115,4 +115,4 @@
     }
 }
 
-private class TestError(message: String) : Exception(message)
\ No newline at end of file
+internal class TestError(message: String) : Exception(message)
\ No newline at end of file
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/StateObservableTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/StateObservableTest.kt
new file mode 100644
index 0000000..0d901b2
--- /dev/null
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/impl/StateObservableTest.kt
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2021 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.camera.core.impl
+
+import androidx.camera.testing.asFlow
+import androidx.concurrent.futures.await
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SmallTest
+import androidx.testutils.assertThrows
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.asExecutor
+import kotlinx.coroutines.async
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.dropWhile
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val INITIAL_STATE = 0
+private const val MAGIC_STATE = 42
+private val TEST_ERROR = TestError("TEST")
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+public class StateObservableTest {
+
+    @Test
+    public fun canFetchInitialState(): Unit = runBlocking {
+        val observable = MutableStateObservable.withInitialState(INITIAL_STATE)
+
+        val fetched = observable.fetchData().await()
+        assertThat(fetched).isEqualTo(INITIAL_STATE)
+    }
+
+    @Test
+    public fun canFetchInitialError(): Unit = runBlocking {
+        val observable = MutableStateObservable.withInitialError<Any?>(TEST_ERROR)
+
+        assertThrows<TestError> { observable.fetchData().await() }
+    }
+
+    @Test
+    public fun fetchIsImmediate() {
+        val observable = MutableStateObservable.withInitialState(INITIAL_STATE)
+
+        assertThat(observable.fetchData().isDone).isTrue()
+    }
+
+    @Test
+    public fun canObserveToFetchInitialState(): Unit = runBlocking {
+        val observable = MutableStateObservable.withInitialState(INITIAL_STATE)
+
+        val fetched = observable.asFlow().first()
+        assertThat(fetched).isEqualTo(INITIAL_STATE)
+    }
+
+    @Test
+    public fun canObserveToFetchInitialError(): Unit = runBlocking {
+        val observable = MutableStateObservable.withInitialError<Any?>(TEST_ERROR)
+
+        assertThrows<TestError> { observable.asFlow().first() }
+    }
+
+    @Test
+    public fun canObserveToFetchPostedState(): Unit = runBlocking {
+        val observable = MutableStateObservable.withInitialState(INITIAL_STATE)
+        observable.setState(MAGIC_STATE)
+
+        val fetched = observable.asFlow().dropWhile {
+            it != MAGIC_STATE
+        }.first()
+        assertThat(fetched).isEqualTo(MAGIC_STATE)
+    }
+
+    @Test
+    public fun canObserveToReceivePostedError(): Unit = runBlocking {
+        val observable = MutableStateObservable.withInitialState(INITIAL_STATE)
+        observable.setError(TEST_ERROR)
+
+        assertThrows<TestError> { observable.asFlow().collect() }
+    }
+
+    @Test
+    public fun canSetAndFetchState_fromSeparateThreads(): Unit = runBlocking {
+        val observable = MutableStateObservable.withInitialState(INITIAL_STATE)
+        launch(Dispatchers.Main) {
+            delay(100) // Not strictly necessary, but wait before setting state
+            observable.setState(MAGIC_STATE)
+        }
+
+        val fetched = async(Dispatchers.IO) {
+            observable.asFlow().dropWhile { it != MAGIC_STATE }.first()
+        }
+
+        assertThat(fetched.await()).isEqualTo(MAGIC_STATE)
+    }
+
+    @Test
+    public fun canObserveToRetrieveState_whenSetAfterObserve(): Unit = runBlocking {
+        val observable = MutableStateObservable.withInitialState(INITIAL_STATE)
+
+        // Add the observer
+        val deferred = CompletableDeferred<Int>()
+        observable.addObserver(
+            Dispatchers.IO.asExecutor(),
+            object : Observable.Observer<Int> {
+                override fun onNewData(state: Int?) {
+                    if (state == MAGIC_STATE) {
+                        deferred.complete(state)
+                    }
+                }
+
+                override fun onError(t: Throwable) {
+                    deferred.completeExceptionally(t)
+                }
+            }
+        )
+
+        // Post the state
+        observable.setState(MAGIC_STATE)
+
+        assertThat(deferred.await()).isEqualTo(MAGIC_STATE)
+    }
+
+    @Test
+    public fun canObserveToRetrieveError_whenSetAfterObserve(): Unit = runBlocking {
+        val observable = MutableStateObservable.withInitialState(INITIAL_STATE)
+
+        // Add the observer
+        val deferred = CompletableDeferred<Int>()
+        observable.addObserver(
+            Dispatchers.IO.asExecutor(),
+            object : Observable.Observer<Int> {
+                override fun onNewData(state: Int?) {
+                    // Ignore states
+                }
+
+                override fun onError(t: Throwable) {
+                    deferred.completeExceptionally(t)
+                }
+            }
+        )
+
+        // Post the error
+        observable.setError(TEST_ERROR)
+
+        assertThrows<TestError> { deferred.await() }
+    }
+
+    @MediumTest
+    @Test
+    public fun allObservers_receiveFinalState(): Unit = runBlocking {
+        val observable = MutableStateObservable.withInitialState(INITIAL_STATE)
+
+        // Create 20 observers to ensure they all complete
+        val receiveJob = launch(Dispatchers.IO) {
+            repeat(20) {
+                launch { observable.asFlow().dropWhile { it != MAGIC_STATE }.first() }
+            }
+        }
+
+        // Create another coroutine to set states
+        launch(Dispatchers.IO) {
+            (25 downTo 0).forEach { i ->
+                observable.setState(MAGIC_STATE - i)
+                delay(5)
+            }
+        }
+
+        // Ensure receiveJob completes
+        receiveJob.join()
+    }
+}
\ No newline at end of file
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
index a5f6579..9e9ee15 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
@@ -822,6 +822,7 @@
         // Audio encoding loop. Exits on end of stream.
         boolean audioEos = false;
         int outIndex;
+        long lastAudioTimestamp = 0;
         while (!audioEos && mIsRecording) {
             // Check for end of stream from main thread
             if (mEndOfAudioStreamSignal.get()) {
@@ -862,7 +863,20 @@
                         case MediaCodec.INFO_TRY_AGAIN_LATER:
                             break;
                         default:
-                            audioEos = writeAudioEncodedBuffer(outIndex);
+                            // Drops out of order audio frame if the frame's earlier than last
+                            // frame.
+                            if (mAudioBufferInfo.presentationTimeUs > lastAudioTimestamp) {
+                                audioEos = writeAudioEncodedBuffer(outIndex);
+                                lastAudioTimestamp = mAudioBufferInfo.presentationTimeUs;
+                            } else {
+                                Logger.w(TAG,
+                                        "Drops frame, current frame's timestamp "
+                                                + mAudioBufferInfo.presentationTimeUs
+                                                + " is earlier that last frame "
+                                                + lastAudioTimestamp);
+                                // Releases this frame from output buffer
+                                mAudioEncoder.releaseOutputBuffer(outIndex, false);
+                            }
                     }
                 } while (outIndex >= 0 && !audioEos); // end of dequeue output buffer
             }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/CamcorderProfileProvider.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/CamcorderProfileProvider.java
new file mode 100644
index 0000000..865e2d1
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/CamcorderProfileProvider.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2021 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.camera.core.impl;
+
+import android.media.CamcorderProfile;
+
+import androidx.annotation.Nullable;
+
+/**
+ * CamcorderProfileProvider is used to obtain the {@link CamcorderProfileProxy}.
+ */
+public interface CamcorderProfileProvider {
+
+    /**
+     * Check if the quality is supported on this device.
+     *
+     * <p>The quality should be one of quality constants defined in {@link CamcorderProfile}.
+     */
+    boolean hasProfile(int quality);
+
+    /**
+     * Gets the {@link CamcorderProfileProxy} if the quality is supported on the device.
+     *
+     * <p>The quality should be one of quality constants defined in {@link CamcorderProfile}.
+     *
+     * @see #hasProfile(int)
+     */
+    @Nullable
+    CamcorderProfileProxy get(int quality);
+
+    /** An implementation that contains no data. */
+    CamcorderProfileProvider EMPTY = new CamcorderProfileProvider() {
+        @Override
+        public boolean hasProfile(int quality) {
+            return false;
+        }
+
+        @Nullable
+        @Override
+        public CamcorderProfileProxy get(int quality) {
+            return null;
+        }
+    };
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/CamcorderProfileProxy.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/CamcorderProfileProxy.java
new file mode 100644
index 0000000..5f0e82e
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/CamcorderProfileProxy.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2021 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.camera.core.impl;
+
+import android.media.CamcorderProfile;
+
+import androidx.annotation.NonNull;
+
+import com.google.auto.value.AutoValue;
+
+/**
+ * CamcorderProfileProxy defines the get methods that is mapping to the fields of
+ * {@link CamcorderProfile}.
+ */
+@AutoValue
+public abstract class CamcorderProfileProxy {
+
+    /** Creates a CamcorderProfileProxy instance. */
+    @NonNull
+    public static CamcorderProfileProxy create(int duration,
+            int quality,
+            int fileFormat,
+            int videoCodec,
+            int videoBitRate,
+            int videoFrameRate,
+            int videoFrameWidth,
+            int videoFrameHeight,
+            int audioCodec,
+            int audioBitRate,
+            int audioSampleRate,
+            int audioChannels) {
+        return new AutoValue_CamcorderProfileProxy(
+                duration,
+                quality,
+                fileFormat,
+                videoCodec,
+                videoBitRate,
+                videoFrameRate,
+                videoFrameWidth,
+                videoFrameHeight,
+                audioCodec,
+                audioBitRate,
+                audioSampleRate,
+                audioChannels
+        );
+    }
+
+    /** Creates a CamcorderProfileProxy instance from {@link CamcorderProfile}. */
+    @NonNull
+    public static CamcorderProfileProxy fromCamcorderProfile(
+            @NonNull CamcorderProfile camcorderProfile) {
+        return new AutoValue_CamcorderProfileProxy(
+                camcorderProfile.duration,
+                camcorderProfile.quality,
+                camcorderProfile.fileFormat,
+                camcorderProfile.videoCodec,
+                camcorderProfile.videoBitRate,
+                camcorderProfile.videoFrameRate,
+                camcorderProfile.videoFrameWidth,
+                camcorderProfile.videoFrameHeight,
+                camcorderProfile.audioCodec,
+                camcorderProfile.audioBitRate,
+                camcorderProfile.audioSampleRate,
+                camcorderProfile.audioChannels
+        );
+    }
+
+    /** @see CamcorderProfile#duration */
+    public abstract int getDuration();
+
+    /** @see CamcorderProfile#quality */
+    public abstract int getQuality();
+
+    /** @see CamcorderProfile#fileFormat */
+    public abstract int getFileFormat();
+
+    /** @see CamcorderProfile#videoCodec */
+    public abstract int getVideoCodec();
+
+    /** @see CamcorderProfile#videoBitRate */
+    public abstract int getVideoBitRate();
+
+    /** @see CamcorderProfile#videoFrameRate */
+    public abstract int getVideoFrameRate();
+
+    /** @see CamcorderProfile#videoFrameWidth */
+    public abstract int getVideoFrameWidth();
+
+    /** @see CamcorderProfile#videoFrameHeight */
+    public abstract int getVideoFrameHeight();
+
+    /** @see CamcorderProfile#audioCodec */
+    public abstract int getAudioCodec();
+
+    /** @see CamcorderProfile#audioBitRate */
+    public abstract int getAudioBitRate();
+
+    /** @see CamcorderProfile#audioSampleRate */
+    public abstract int getAudioSampleRate();
+
+    /** @see CamcorderProfile#audioChannels */
+    public abstract int getAudioChannels();
+}
+
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraInfoInternal.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraInfoInternal.java
index 7dc5669..aba76ae 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraInfoInternal.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/CameraInfoInternal.java
@@ -66,4 +66,8 @@
     /** Returns a list of quirks related to the camera. */
     @NonNull
     Quirks getCameraQuirks();
+
+    /** Returns the {@link CamcorderProfileProvider} associated with this camera. */
+    @NonNull
+    CamcorderProfileProvider getCamcorderProfileProvider();
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/ConstantObservable.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/ConstantObservable.java
index 17fddbb..f090d00c 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/ConstantObservable.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/ConstantObservable.java
@@ -62,7 +62,7 @@
     }
 
     @Override
-    public void addObserver(@NonNull Executor executor, @NonNull Observable.Observer<T> observer) {
+    public void addObserver(@NonNull Executor executor, @NonNull Observer<? super T> observer) {
         // Since the Observable has a constant value, we only will have a one-shot call to the
         // observer, so we don't need to store the observer.
         // ImmediateFuture does not actually store listeners since it is already complete, so it
@@ -79,7 +79,7 @@
     }
 
     @Override
-    public void removeObserver(@NonNull Observable.Observer<T> observer) {
+    public void removeObserver(@NonNull Observer<? super T> observer) {
         // no-op. addObserver() does not need to store observers.
     }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/LiveDataObservable.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/LiveDataObservable.java
index fba389e..e8520da 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/LiveDataObservable.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/LiveDataObservable.java
@@ -53,7 +53,7 @@
     @SuppressWarnings("WeakerAccess") /* synthetic accessor */
     final MutableLiveData<Result<T>> mLiveData = new MutableLiveData<>();
     @GuardedBy("mObservers")
-    private final Map<Observer<T>, LiveDataObserverAdapter<T>> mObservers = new HashMap<>();
+    private final Map<Observer<? super T>, LiveDataObserverAdapter<T>> mObservers = new HashMap<>();
 
     /**
      * Posts a new value to be used as the current value of this Observable.
@@ -81,34 +81,26 @@
     @Override
     @SuppressWarnings("ObjectToString")
     public ListenableFuture<T> fetchData() {
-        return CallbackToFutureAdapter.getFuture(new CallbackToFutureAdapter.Resolver<T>() {
-            @Nullable
-            @Override
-            public Object attachCompleter(
-                    @NonNull final CallbackToFutureAdapter.Completer<T> completer) {
-                CameraXExecutors.mainThreadExecutor().execute(new Runnable() {
-                    @Override
-                    public void run() {
-                        Result<T> result = mLiveData.getValue();
-                        if (result == null) {
-                            completer.setException(new IllegalStateException(
-                                    "Observable has not yet been initialized with a value."));
-                        } else if (result.completedSuccessfully()) {
-                            completer.set(result.getValue());
-                        } else {
-                            Preconditions.checkNotNull(result.getError());
-                            completer.setException(result.getError());
-                        }
-                    }
-                });
+        return CallbackToFutureAdapter.getFuture(completer -> {
+            CameraXExecutors.mainThreadExecutor().execute(() -> {
+                Result<T> result = mLiveData.getValue();
+                if (result == null) {
+                    completer.setException(new IllegalStateException(
+                            "Observable has not yet been initialized with a value."));
+                } else if (result.completedSuccessfully()) {
+                    completer.set(result.getValue());
+                } else {
+                    Preconditions.checkNotNull(result.getError());
+                    completer.setException(result.getError());
+                }
+            });
 
-                return LiveDataObservable.this + " [fetch@" + SystemClock.uptimeMillis() + "]";
-            }
+            return LiveDataObservable.this + " [fetch@" + SystemClock.uptimeMillis() + "]";
         });
     }
 
     @Override
-    public void addObserver(@NonNull Executor executor, @NonNull Observer<T> observer) {
+    public void addObserver(@NonNull Executor executor, @NonNull Observer<? super T> observer) {
         synchronized (mObservers) {
             final LiveDataObserverAdapter<T> oldAdapter = mObservers.get(observer);
             if (oldAdapter != null) {
@@ -119,29 +111,24 @@
                     observer);
             mObservers.put(observer, newAdapter);
 
-            CameraXExecutors.mainThreadExecutor().execute(new Runnable() {
-                @Override
-                public void run() {
+            CameraXExecutors.mainThreadExecutor().execute(() -> {
+                if (oldAdapter != null) {
                     mLiveData.removeObserver(oldAdapter);
-                    mLiveData.observeForever(newAdapter);
                 }
+                mLiveData.observeForever(newAdapter);
             });
         }
     }
 
     @Override
-    public void removeObserver(@NonNull Observer<T> observer) {
+    public void removeObserver(@NonNull Observer<? super T> observer) {
         synchronized (mObservers) {
             LiveDataObserverAdapter<T> adapter = mObservers.remove(observer);
 
             if (adapter != null) {
                 adapter.disable();
-                CameraXExecutors.mainThreadExecutor().execute(new Runnable() {
-                    @Override
-                    public void run() {
-                        mLiveData.removeObserver(adapter);
-                    }
-                });
+                CameraXExecutors.mainThreadExecutor().execute(
+                        () -> mLiveData.removeObserver(adapter));
             }
         }
     }
@@ -156,9 +143,9 @@
      */
     public static final class Result<T> {
         @Nullable
-        private T mValue;
+        private final T mValue;
         @Nullable
-        private Throwable mError;
+        private final Throwable mError;
 
         private Result(@Nullable T value, @Nullable Throwable error) {
             mValue = value;
@@ -224,10 +211,10 @@
             androidx.lifecycle.Observer<Result<T>> {
 
         final AtomicBoolean mActive = new AtomicBoolean(true);
-        final Observer<T> mObserver;
+        final Observer<? super T> mObserver;
         final Executor mExecutor;
 
-        LiveDataObserverAdapter(@NonNull Executor executor, @NonNull Observer<T> observer) {
+        LiveDataObserverAdapter(@NonNull Executor executor, @NonNull Observer<? super T> observer) {
             mExecutor = executor;
             mObserver = observer;
         }
@@ -238,20 +225,17 @@
 
         @Override
         public void onChanged(@NonNull final Result<T> result) {
-            mExecutor.execute(new Runnable() {
-                @Override
-                public void run() {
-                    if (!mActive.get()) {
-                        // Observer has been disabled.
-                        return;
-                    }
+            mExecutor.execute(() -> {
+                if (!mActive.get()) {
+                    // Observer has been disabled.
+                    return;
+                }
 
-                    if (result.completedSuccessfully()) {
-                        mObserver.onNewData(result.getValue());
-                    } else {
-                        Preconditions.checkNotNull(result.getError());
-                        mObserver.onError(result.getError());
-                    }
+                if (result.completedSuccessfully()) {
+                    mObserver.onNewData(result.getValue());
+                } else {
+                    Preconditions.checkNotNull(result.getError());
+                    mObserver.onError(result.getError());
                 }
             });
         }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/MutableStateObservable.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/MutableStateObservable.java
new file mode 100644
index 0000000..90fa540
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/MutableStateObservable.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2021 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.camera.core.impl;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+/**
+ * A {@link StateObservable} whose state can be set.
+ *
+ * @param <T> The state type.
+ */
+public class MutableStateObservable<T> extends StateObservable<T> {
+
+    private MutableStateObservable(@Nullable Object initialState, boolean isError) {
+        super(initialState, isError);
+    }
+
+    /**
+     * Creates a mutable state observer with the provided initial state.
+     *
+     * @param initialState The initial state
+     * @param <T>          The state type
+     * @return A mutable state observable initialized with the given initial state.
+     */
+    @NonNull
+    public static <T> MutableStateObservable<T> withInitialState(@Nullable T initialState) {
+        return new MutableStateObservable<>(initialState, false);
+    }
+
+    /**
+     * Creates a mutable state observer in an initial error state containing the provided
+     * {@link Throwable}.
+     *
+     * @param initialError The {@link Throwable} contained by the error state.
+     * @param <T>          The state type
+     * @return A mutable state observable initialized in an error state containing the provided
+     * {@link Throwable}.
+     */
+    @NonNull
+    public static <T> MutableStateObservable<T> withInitialError(@NonNull Throwable initialError) {
+        return new MutableStateObservable<>(initialError, true);
+    }
+
+    /**
+     * Posts a new state to be used as the current state of this Observable.
+     */
+    public void setState(@Nullable T state) {
+        updateState(state);
+    }
+
+    /**
+     * Posts a new {@link Throwable} to be used in the new error state of this Observable.
+     */
+    public void setError(@NonNull Throwable error) {
+        updateStateAsError(error);
+    }
+
+}
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/Observable.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/Observable.java
index 272e1cc..4491d48 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/impl/Observable.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/Observable.java
@@ -55,11 +55,10 @@
      *
      * <p>If the same observer is added twice, it will only be called on the last executor it was
      * registered with.
-     *
      * @param executor The executor which will be used to notify the observer of new data.
      * @param observer The observer which will receive new data.
      */
-    void addObserver(@NonNull Executor executor, @NonNull Observer<T> observer);
+    void addObserver(@NonNull Executor executor, @NonNull Observer<? super T> observer);
 
     /**
      * Removes a previously added observer.
@@ -70,7 +69,7 @@
      *
      * @param observer The observer to remove.
      */
-    void removeObserver(@NonNull Observer<T> observer);
+    void removeObserver(@NonNull Observer<? super T> observer);
 
     /**
      * A callback that can receive new values and errors from an {@link Observable}.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/impl/StateObservable.java b/camera/camera-core/src/main/java/androidx/camera/core/impl/StateObservable.java
new file mode 100644
index 0000000..ed3ab43
--- /dev/null
+++ b/camera/camera-core/src/main/java/androidx/camera/core/impl/StateObservable.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2021 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.camera.core.impl;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.core.impl.utils.futures.Futures;
+import androidx.core.util.Preconditions;
+
+import com.google.auto.value.AutoValue;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * An observable which reports a dynamic state.
+ *
+ * <p>The state of a state observable is conflated. That is, the value received by an
+ * {@link androidx.camera.core.impl.Observable.Observer} will only be the latest state; some
+ * state updates may never be observed if the state changes quickly enough.
+ *
+ * <p>State observables require an initial state, and thus always have a state available for
+ * retrieval via {@link #fetchData()}, which will return an already-complete
+ * {@link ListenableFuture}.
+ *
+ * <p>Errors are also possible as states, and when an error is present, any previous state
+ * information is lost. State observables may transition in and out of error states at any time,
+ * including the initial state.
+ *
+ * <p>All states, including errors, are conflated via {@link Object#equals(Object)}. That is, if
+ * two states evaluate to {@code true}, it will be as if the state didn't change and no update
+ * will be sent to observers.
+ *
+ * @param <T> The state type.
+ */
+public abstract class StateObservable<T> implements Observable<T> {
+    private static final int INITIAL_VERSION = 0;
+
+    private final Object mLock = new Object();
+    private final AtomicReference<Object> mState;
+    @GuardedBy("mLock")
+    private int mVersion = INITIAL_VERSION;
+    @GuardedBy("mLock")
+    private boolean mUpdating = false;
+
+    // Must be updated together under lock
+    @GuardedBy("mLock")
+    private final Map<Observer<? super T>, ObserverWrapper<T>> mWrapperMap = new HashMap<>();
+    @GuardedBy("mLock")
+    private final CopyOnWriteArraySet<ObserverWrapper<T>> mNotifySet = new CopyOnWriteArraySet<>();
+
+    StateObservable(@Nullable Object initialState, boolean isError) {
+        if (isError) {
+            Preconditions.checkArgument(initialState instanceof Throwable, "Initial errors must "
+                    + "be Throwable");
+            mState = new AtomicReference<>(ErrorWrapper.wrap((Throwable) initialState));
+        } else {
+            mState = new AtomicReference<>(initialState);
+        }
+
+    }
+
+    void updateState(@Nullable T state) {
+        updateStateInternal(state);
+    }
+
+    void updateStateAsError(@NonNull Throwable error) {
+        updateStateInternal(ErrorWrapper.wrap(error));
+    }
+
+    private void updateStateInternal(@Nullable Object newState) {
+        Iterator<ObserverWrapper<T>> notifyIter;
+        int currentVersion;
+        synchronized (mLock) {
+            Object oldState = mState.getAndSet(newState);
+            // If new state is equal to old state, no need to do anything.
+            if (Objects.equals(oldState, newState)) return;
+            currentVersion = ++mVersion; // State was updated. Next version.
+            if (mUpdating) return; // Already updating. New state will get used due to version bump.
+            mUpdating = true;
+            notifyIter = mNotifySet.iterator();
+        }
+
+        while (true) {
+            // Update observers unlocked in case of direct executor.
+            while (notifyIter.hasNext()) {
+                notifyIter.next().update(currentVersion);
+            }
+
+            // Check if a new version was added while updating
+            synchronized (mLock) {
+                if (mVersion == currentVersion) {
+                    // Updating complete. Break out.
+                    mUpdating = false;
+                    break;
+                }
+
+                // A new version was added. Update again on next loop.
+                // Get a new iterator in case the observers changed during update.
+                notifyIter = mNotifySet.iterator();
+                currentVersion = mVersion;
+            }
+        }
+    }
+
+    /**
+     * Fetch the latest state.
+     *
+     * <p>For state observables, the future returned by {@code fetchData()} is guaranteed to be
+     * complete and will contain either the current state or an error state which will be thrown
+     * as an exception from {@link ListenableFuture#get()}.
+     *
+     * @return A future which will contain the latest value or an error.
+     */
+    @SuppressWarnings("unchecked")
+    @NonNull
+    @Override
+    public ListenableFuture<T> fetchData() {
+        Object state = mState.get();
+        if (state instanceof ErrorWrapper) {
+            return Futures.immediateFailedFuture(((ErrorWrapper) state).getError());
+        } else {
+            return Futures.immediateFuture((T) state);
+        }
+    }
+
+    @Override
+    public void addObserver(@NonNull Executor executor, @NonNull Observer<? super T> observer) {
+        ObserverWrapper<T> wrapper;
+        synchronized (mLock) {
+            // If observer is already registered, remove it. It will get notified again immediately.
+            removeObserverLocked(observer);
+
+            wrapper = new ObserverWrapper<>(mState, executor, observer);
+            mWrapperMap.put(observer, wrapper);
+            mNotifySet.add(wrapper);
+        }
+
+        // INITIAL_VERSION won't necessarily match the current tracked version constant, but it
+        // will be the initial version this wrapper receives. Any future version updates will
+        // always be higher than INITIAL_VERSION.
+        wrapper.update(INITIAL_VERSION);
+    }
+
+    @Override
+    public void removeObserver(@NonNull Observer<? super T> observer) {
+        synchronized (mLock) {
+            removeObserverLocked(observer);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void removeObserverLocked(@NonNull Observable.Observer<? super T> observer) {
+        ObserverWrapper<T> wrapper = mWrapperMap.remove(observer);
+        if (wrapper != null) {
+            wrapper.close();
+            mNotifySet.remove(wrapper);
+        }
+    }
+
+    private static final class ObserverWrapper<T> implements Runnable {
+        private static final Object NOT_SET = new Object();
+        private static final int NO_VERSION = -1;
+
+        private final Executor mExecutor;
+        private final Observer<? super T> mObserver;
+        private final AtomicBoolean mActive = new AtomicBoolean(true);
+        private final AtomicReference<Object> mStateRef;
+
+        // Since run() will always run sequentially, no need to lock for this variable.
+        private Object mLastState = NOT_SET;
+        @GuardedBy("this")
+        private int mLatestSignalledVersion = NO_VERSION;
+        @GuardedBy("this")
+        private boolean mWrapperUpdating = false;
+
+        ObserverWrapper(@NonNull AtomicReference<Object> stateRef, @NonNull Executor executor,
+                @NonNull Observer<? super T> observer) {
+            mStateRef = stateRef;
+            mExecutor = executor;
+            mObserver = observer;
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public void run() {
+            Object newState;
+            int currentVersion;
+            synchronized (this) {
+                // Only update if we're still active.
+                if (!mActive.get()) {
+                    mWrapperUpdating = false;
+                    return;
+                }
+                // Get latest state.
+                newState = mStateRef.get();
+                currentVersion = mLatestSignalledVersion;
+            }
+
+            // Continue to check if we're active before updating
+            while (true) {
+                // Conflate notification using equality
+                if (!Objects.equals(mLastState, newState)) {
+                    mLastState = newState;
+                    if (newState instanceof ErrorWrapper) {
+                        mObserver.onError(((ErrorWrapper) newState).getError());
+                    } else {
+                        mObserver.onNewData((T) newState);
+                    }
+                }
+
+                synchronized (this) {
+                    if (currentVersion == mLatestSignalledVersion || !mActive.get()) {
+                        // Updating complete or no longer active. Break out of update loop.
+                        mWrapperUpdating = false;
+                        break;
+                    }
+
+                    // Get state and version for next update.
+                    newState = mStateRef.get();
+                    currentVersion = mLatestSignalledVersion;
+                }
+            }
+        }
+
+        void update(int version) {
+            synchronized (this) {
+                // If no longer active, then don't attempt update.
+                if (!mActive.get()) return;
+                // No need to update (but this probably shouldn't happen anyways)
+                if (version <= mLatestSignalledVersion) return;
+                mLatestSignalledVersion = version;
+                // No need to update if already updating. Version bump will cause update.
+                if (mWrapperUpdating) return;
+                mWrapperUpdating = true;
+            }
+
+            try {
+                mExecutor.execute(this);
+            } catch (Throwable t) {
+                // Unable to notify due to state of Executor. The update is lost, but there's
+                // not much we can do here since the executor rejected the update. Note this
+                // may also mean that any updates which occurred while mWrapperUpdating ==
+                // true will have also been lost.
+                synchronized (this) {
+                    // Update mWrapperUpdating so the next update can try again
+                    mWrapperUpdating = false;
+                }
+            }
+        }
+
+        void close() {
+            // Best effort cancellation. In progress updates will not be cancelled.
+            mActive.set(false);
+        }
+    }
+
+    @AutoValue
+    abstract static class ErrorWrapper {
+        @NonNull
+        static ErrorWrapper wrap(@NonNull Throwable error) {
+            return new AutoValue_StateObservable_ErrorWrapper(error);
+        }
+
+        @NonNull
+        public abstract Throwable getError();
+    }
+}
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/CamcorderProfileUtil.java b/camera/camera-testing/src/main/java/androidx/camera/testing/CamcorderProfileUtil.java
new file mode 100644
index 0000000..e17eb0c
--- /dev/null
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/CamcorderProfileUtil.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2021 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.camera.testing;
+
+import android.media.CamcorderProfile;
+import android.media.MediaRecorder;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.camera.core.impl.CamcorderProfileProxy;
+
+/**
+ * Utility methods for testing {@link CamcorderProfile} related classes, including predefined
+ * resolutions, attributes and {@link CamcorderProfileProxy}, which can be used directly on the
+ * unit tests.
+ */
+public final class CamcorderProfileUtil {
+
+    private CamcorderProfileUtil() {
+    }
+
+    /** Resolution for QCIF. */
+    public static final Size RESOLUTION_QCIF = new Size(176, 144);
+    /** Resolution for QVGA. */
+    public static final Size RESOLUTION_QVGA = new Size(320, 240);
+    /** Resolution for CIF. */
+    public static final Size RESOLUTION_CIF = new Size(352, 288);
+    /** Resolution for VGA. */
+    public static final Size RESOLUTION_VGA = new Size(640, 480);
+    /** Resolution for 480P. */
+    public static final Size RESOLUTION_480P = new Size(720, 480); /* 640, 704 or 720 x 480 */
+    /** Resolution for 720P. */
+    public static final Size RESOLUTION_720P = new Size(1280, 720);
+    /** Resolution for 1080P. */
+    public static final Size RESOLUTION_1080P = new Size(1920, 1080); /* 1920 x 1080 or 1088 */
+    /** Resolution for 2K. */
+    public static final Size RESOLUTION_2K = new Size(2048, 1080);
+    /** Resolution for QHD. */
+    public static final Size RESOLUTION_QHD = new Size(2560, 1440);
+    /** Resolution for 2160P. */
+    public static final Size RESOLUTION_2160P = new Size(3840, 2160);
+    /** Resolution for 4KDCI. */
+    public static final Size RESOLUTION_4KDCI = new Size(4096, 2160);
+
+    /** Default duration. */
+    public static final int DEFAULT_DURATION = 30;
+    /** Default output format. */
+    public static final int DEFAULT_OUTPUT_FORMAT = MediaRecorder.OutputFormat.MPEG_4;
+    /** Default video codec. */
+    public static final int DEFAULT_VIDEO_CODEC = MediaRecorder.VideoEncoder.H264;
+    /** Default video bitrate. */
+    public static final int DEFAULT_VIDEO_BITRATE = 8 * 1024 * 1024;
+    /** Default video frame rate. */
+    public static final int DEFAULT_VIDEO_FRAME_RATE = 30;
+    /** Default audio codec. */
+    public static final int DEFAULT_AUDIO_CODEC = MediaRecorder.AudioEncoder.AAC;
+    /** Default audio bitrate. */
+    public static final int DEFAULT_AUDIO_BITRATE = 192_000;
+    /** Default audio sample rate. */
+    public static final int DEFAULT_AUDIO_SAMPLE_RATE = 48_000;
+    /** Default channel count. */
+    public static final int DEFAULT_AUDIO_CHANNELS = 1;
+
+    public static final CamcorderProfileProxy PROFILE_QCIF = createCamcorderProfileProxy(
+            CamcorderProfile.QUALITY_QCIF,
+            RESOLUTION_QCIF.getWidth(),
+            RESOLUTION_QCIF.getHeight()
+    );
+
+    public static final CamcorderProfileProxy PROFILE_QVGA = createCamcorderProfileProxy(
+            CamcorderProfile.QUALITY_QVGA,
+            RESOLUTION_QVGA.getWidth(),
+            RESOLUTION_QVGA.getHeight()
+    );
+
+    public static final CamcorderProfileProxy PROFILE_CIF = createCamcorderProfileProxy(
+            CamcorderProfile.QUALITY_CIF,
+            RESOLUTION_CIF.getWidth(),
+            RESOLUTION_CIF.getHeight()
+    );
+
+    public static final CamcorderProfileProxy PROFILE_VGA = createCamcorderProfileProxy(
+            CamcorderProfile.QUALITY_VGA,
+            RESOLUTION_VGA.getWidth(),
+            RESOLUTION_VGA.getHeight()
+    );
+
+    public static final CamcorderProfileProxy PROFILE_480P = createCamcorderProfileProxy(
+            CamcorderProfile.QUALITY_480P,
+            RESOLUTION_480P.getWidth(),
+            RESOLUTION_480P.getHeight()
+    );
+
+    public static final CamcorderProfileProxy PROFILE_720P = createCamcorderProfileProxy(
+            CamcorderProfile.QUALITY_720P,
+            RESOLUTION_720P.getWidth(),
+            RESOLUTION_720P.getHeight()
+    );
+
+    public static final CamcorderProfileProxy PROFILE_1080P = createCamcorderProfileProxy(
+            CamcorderProfile.QUALITY_1080P,
+            RESOLUTION_1080P.getWidth(),
+            RESOLUTION_1080P.getHeight()
+    );
+
+    public static final CamcorderProfileProxy PROFILE_2K = createCamcorderProfileProxy(
+            CamcorderProfile.QUALITY_2K,
+            RESOLUTION_2K.getWidth(),
+            RESOLUTION_2K.getHeight()
+    );
+
+    public static final CamcorderProfileProxy PROFILE_QHD = createCamcorderProfileProxy(
+            CamcorderProfile.QUALITY_QHD,
+            RESOLUTION_QHD.getWidth(),
+            RESOLUTION_QHD.getHeight()
+    );
+
+    public static final CamcorderProfileProxy PROFILE_2160P = createCamcorderProfileProxy(
+            CamcorderProfile.QUALITY_2160P,
+            RESOLUTION_2160P.getWidth(),
+            RESOLUTION_2160P.getHeight()
+    );
+
+    public static final CamcorderProfileProxy PROFILE_4KDCI = createCamcorderProfileProxy(
+            CamcorderProfile.QUALITY_4KDCI,
+            RESOLUTION_4KDCI.getWidth(),
+            RESOLUTION_4KDCI.getHeight()
+    );
+
+    /** A utility method to create a CamcorderProfileProxy with some default values. */
+    @NonNull
+    public static CamcorderProfileProxy createCamcorderProfileProxy(
+            int quality,
+            int videoFrameWidth,
+            int videoFrameHeight
+    ) {
+        return CamcorderProfileProxy.create(
+                DEFAULT_DURATION,
+                quality,
+                DEFAULT_OUTPUT_FORMAT,
+                DEFAULT_VIDEO_CODEC,
+                DEFAULT_VIDEO_BITRATE,
+                DEFAULT_VIDEO_FRAME_RATE,
+                videoFrameWidth,
+                videoFrameHeight,
+                DEFAULT_AUDIO_CODEC,
+                DEFAULT_AUDIO_BITRATE,
+                DEFAULT_AUDIO_SAMPLE_RATE,
+                DEFAULT_AUDIO_CHANNELS
+        );
+    }
+
+    /**
+     * Copies a CamcorderProfileProxy and sets the quality to
+     * {@link CamcorderProfile#QUALITY_HIGH}.
+     */
+    @NonNull
+    public static CamcorderProfileProxy asHighQuality(@NonNull CamcorderProfileProxy profile) {
+        return asQuality(profile, CamcorderProfile.QUALITY_HIGH);
+    }
+
+    /**
+     * Copies a CamcorderProfileProxy and sets the quality to
+     * {@link CamcorderProfile#QUALITY_LOW}.
+     */
+    @NonNull
+    public static CamcorderProfileProxy asLowQuality(@NonNull CamcorderProfileProxy profile) {
+        return asQuality(profile, CamcorderProfile.QUALITY_LOW);
+    }
+
+    private static CamcorderProfileProxy asQuality(@NonNull CamcorderProfileProxy profile,
+            int quality) {
+        return CamcorderProfileProxy.create(
+                profile.getDuration(),
+                quality,
+                profile.getFileFormat(),
+                profile.getVideoCodec(),
+                profile.getVideoBitRate(),
+                profile.getVideoFrameRate(),
+                profile.getVideoFrameWidth(),
+                profile.getVideoFrameHeight(),
+                profile.getAudioCodec(),
+                profile.getAudioBitRate(),
+                profile.getAudioSampleRate(),
+                profile.getAudioChannels()
+        );
+    }
+}
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCamcorderProfileProvider.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCamcorderProfileProvider.java
new file mode 100644
index 0000000..a1142ba
--- /dev/null
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCamcorderProfileProvider.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2021 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.camera.testing.fakes;
+
+import android.media.CameraProfile;
+import android.util.SparseArray;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.core.impl.CamcorderProfileProvider;
+import androidx.camera.core.impl.CamcorderProfileProxy;
+
+/**
+ * A fake implementation of the {@link CamcorderProfileProvider} and used for test.
+ */
+public class FakeCamcorderProfileProvider implements CamcorderProfileProvider {
+
+    private final SparseArray<CamcorderProfileProxy> mQualityToProfileMap;
+
+    FakeCamcorderProfileProvider(@NonNull SparseArray<CamcorderProfileProxy> qualityToProfileMap) {
+        mQualityToProfileMap = qualityToProfileMap;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nullable
+    public CamcorderProfileProxy get(int quality) {
+        return mQualityToProfileMap.get(quality);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean hasProfile(int quality) {
+        return mQualityToProfileMap.get(quality) != null;
+    }
+
+    /**
+     * The builder to create a FakeCamcorderProfileProvider instance.
+     */
+    public static class Builder {
+        private final SparseArray<CamcorderProfileProxy> mQualityToProfileMap = new SparseArray<>();
+
+        /**
+         * Sets the camera id and corresponding profiles.
+         *
+         * <p>In normal case, the {@link CameraProfile#QUALITY_HIGH} and
+         * {@link CameraProfile#QUALITY_LOW} should be added in order to follow the contract of
+         * CamcorderProfile.
+         */
+        @NonNull
+        public Builder addProfile(@NonNull CamcorderProfileProxy camcorderProfile) {
+            mQualityToProfileMap.put(camcorderProfile.getQuality(), camcorderProfile);
+            return this;
+        }
+
+        /** Builds the FakeCamcorderProfileProvider instance. */
+        @NonNull
+        public FakeCamcorderProfileProvider build() {
+            return new FakeCamcorderProfileProvider(mQualityToProfileMap.clone());
+        }
+    }
+}
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java
index 78aab0c..7be0d3a 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeCameraInfoInternal.java
@@ -27,6 +27,7 @@
 import androidx.camera.core.ExposureState;
 import androidx.camera.core.TorchState;
 import androidx.camera.core.ZoomState;
+import androidx.camera.core.impl.CamcorderProfileProvider;
 import androidx.camera.core.impl.CameraCaptureCallback;
 import androidx.camera.core.impl.CameraInfoInternal;
 import androidx.camera.core.impl.ImageOutputConfig.RotationValue;
@@ -34,6 +35,7 @@
 import androidx.camera.core.impl.Quirks;
 import androidx.camera.core.impl.utils.CameraOrientationUtil;
 import androidx.camera.core.internal.ImmutableZoomState;
+import androidx.core.util.Preconditions;
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
 
@@ -57,6 +59,11 @@
     private final MutableLiveData<ZoomState> mZoomLiveData;
     private String mImplementationType = IMPLEMENTATION_TYPE_FAKE;
 
+    // Leave uninitialized to support camera-core:1.0.0 dependencies.
+    // Can be initialized during class init once there are no more pinned dependencies on
+    // camera-core:1.0.0
+    private CamcorderProfileProvider mCamcorderProfileProvider;
+
     @NonNull
     private final List<Quirk> mCameraQuirks = new ArrayList<>();
 
@@ -163,6 +170,13 @@
         return mImplementationType;
     }
 
+    @NonNull
+    @Override
+    public CamcorderProfileProvider getCamcorderProfileProvider() {
+        return mCamcorderProfileProvider == null ? CamcorderProfileProvider.EMPTY :
+                mCamcorderProfileProvider;
+    }
+
     @Override
     public void addSessionCaptureCallback(@NonNull Executor executor,
             @NonNull CameraCaptureCallback callback) {
@@ -191,4 +205,10 @@
     public void setImplementationType(@NonNull @ImplementationType String implementationType) {
         mImplementationType = implementationType;
     }
+
+    /** Set the CamcorderProfileProvider for testing */
+    public void setCamcorderProfileProvider(
+            @NonNull CamcorderProfileProvider camcorderProfileProvider) {
+        mCamcorderProfileProvider = Preconditions.checkNotNull(camcorderProfileProvider);
+    }
 }
diff --git a/camera/camera-video/build.gradle b/camera/camera-video/build.gradle
index 6f3a86a..d2d4178 100644
--- a/camera/camera-video/build.gradle
+++ b/camera/camera-video/build.gradle
@@ -33,7 +33,9 @@
 
     annotationProcessor(AUTO_VALUE)
 
-    testImplementation("junit:junit:4.12")
+    // TODO(leohuang): We need this for assertThrows. Point back to the AndroidX shared version if
+    //  it is ever upgraded.
+    testImplementation("junit:junit:4.13")
     testImplementation(KOTLIN_STDLIB)
     testImplementation(ANDROIDX_TEST_CORE)
     testImplementation(ANDROIDX_TEST_RUNNER)
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoSpecTest.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoSpecTest.kt
index 334e181..7ba71a0 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoSpecTest.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/VideoSpecTest.kt
@@ -30,7 +30,7 @@
     fun newBuilder_containsCorrectDefaults() {
         val videoSpec = VideoSpec.builder().build()
 
-        assertThat(videoSpec.videoQuality).isEqualTo(VideoSpec.VIDEO_QUALITY_AUTO)
+        assertThat(videoSpec.qualitySelector).isEqualTo(VideoSpec.QUALITY_SELECTOR_AUTO)
         assertThat(videoSpec.bitrate).isEqualTo(VideoSpec.BITRATE_RANGE_AUTO)
         assertThat(videoSpec.frameRate).isEqualTo(VideoSpec.FRAME_RATE_RANGE_AUTO)
     }
diff --git a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/FakeBufferProvider.kt b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/FakeBufferProvider.kt
index db8e4be..f2d0dd6 100644
--- a/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/FakeBufferProvider.kt
+++ b/camera/camera-video/src/androidTest/java/androidx/camera/video/internal/FakeBufferProvider.kt
@@ -29,7 +29,7 @@
 
     private val lock = Object()
     @GuardedBy("lock")
-    private val observers = mutableMapOf<Observable.Observer<BufferProvider.State>, Executor>()
+    private val observers = mutableMapOf<Observable.Observer<in BufferProvider.State>, Executor>()
     @GuardedBy("lock")
     private var state = BufferProvider.State.ACTIVE
 
@@ -51,7 +51,7 @@
 
     override fun addObserver(
         executor: Executor,
-        observer: Observable.Observer<BufferProvider.State>
+        observer: Observable.Observer<in BufferProvider.State>
     ) {
         synchronized(observers) {
             observers[observer] = executor
@@ -59,7 +59,7 @@
         executor.execute { observer.onNewData(state) }
     }
 
-    override fun removeObserver(observer: Observable.Observer<BufferProvider.State>) {
+    override fun removeObserver(observer: Observable.Observer<in BufferProvider.State>) {
         synchronized(lock) {
             observers.remove(observer)
         }
@@ -67,7 +67,7 @@
 
     fun setActive(active: Boolean) {
         val newState = if (active) BufferProvider.State.ACTIVE else BufferProvider.State.INACTIVE
-        val localObservers: Map<Observable.Observer<BufferProvider.State>, Executor>
+        val localObservers: Map<Observable.Observer<in BufferProvider.State>, Executor>
         synchronized(lock) {
             if (state == newState) {
                 return
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/QualitySelector.java b/camera/camera-video/src/main/java/androidx/camera/video/QualitySelector.java
new file mode 100644
index 0000000..c570ce8
--- /dev/null
+++ b/camera/camera-video/src/main/java/androidx/camera/video/QualitySelector.java
@@ -0,0 +1,551 @@
+/*
+ * Copyright 2021 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.camera.video;
+
+import android.media.CamcorderProfile;
+import android.util.Size;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+import androidx.camera.core.CameraInfo;
+import androidx.camera.core.Logger;
+import androidx.camera.core.impl.CamcorderProfileProxy;
+import androidx.core.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * QualitySelector defines the desired quality setting.
+ *
+ * <p>There are several defined quality constants such as {@link #QUALITY_SD},
+ * {@link #QUALITY_HD}, {@link #QUALITY_FHD} and {@link #QUALITY_FHD}, but not all of them
+ * are supported on every device since each device has its own capabilities.
+ * {@link #isQualitySupported(CameraInfo, int)} can be used to check whether a quality is
+ * supported on the device or not and {@link #getResolution(CameraInfo, int)} can be used to get
+ * the actual resolution defined in the device. However, checking qualities one by one is not
+ * so inconvenient for the quality setting. QualitySelector is designed to facilitate the quality
+ * setting. The typical usage is
+ * <pre>
+ *     <code>
+ * QualitySelector qualitySelector = QualitySelector.of(QualitySelector.QUALITY_FHD)
+ *     </code>
+ * </pre>
+ * if there is only one desired quality, or a series of quality constants can be set by desired
+ * order
+ * <pre>
+ *     <code>
+ * QualitySelector qualitySelector = QualitySelector
+ *         .firstTry(QualitySelector.QUALITY_FHD)
+ *         .thenTry(QualitySelector.QUALITY_HD)
+ *         .finallyTry(QualitySelector.QUALITY_SHD)
+ *     </code>
+ * </pre>
+ * A recommended way to set the {@link Procedure#finallyTry(int)} is giving guaranteed supported
+ * qualities such as {@link #QUALITY_LOWEST} and {@link #QUALITY_HIGHEST}, which ensures the
+ * QualitySelector can always choose a supported quality. Another way to ensure a quality is
+ * selected when none of the desired qualities are supported is to use
+ * {@link Procedure#finallyTry(int, int)} with an open-ended fallback strategy such as
+ * {@link #FALLBACK_STRATEGY_LOWER}.
+ * <pre>
+ *     <code>
+ * QualitySelector qualitySelector = QualitySelector
+ *         .firstTry(QualitySelector.QUALITY_UHD)
+ *         .finallyTry(QualitySelector.QUALITY_FHD, FALLBACK_STRATEGY_LOWER)
+ *     </code>
+ * </pre>
+ * If QUALITY_UHD and QUALITY_FHD are not supported on the device, the next lower supported
+ * quality than QUALITY_FHD will be attempted. If no lower quality is supported, the next higher
+ * supported quality will be selected. {@link #select(CameraInfo)} can obtain the final result
+ * quality based on the desired qualities and fallback strategy, {@link #QUALITY_NONE} will be
+ * returned if all desired qualities are not supported and fallback strategy also cannot find a
+ * supported one.
+ */
+public class QualitySelector {
+    private static final String TAG = "QualitySelector";
+
+    /**
+     * Indicates no quality.
+     *
+     * <p>Check QUALITY_NONE via {@link #isQualitySupported(CameraInfo, int)} will return
+     * {@code false}. {@link #select(CameraInfo)} will return QUALITY_NONE if all desired
+     * qualities are not supported and fallback strategy is not able to find a supported one.
+     */
+    public static final int QUALITY_NONE = -1;
+    /**
+     * Choose the lowest video quality supported by the video frame producer.
+     */
+    public static final int QUALITY_LOWEST = CamcorderProfile.QUALITY_LOW;
+    /**
+     * Choose the highest video quality supported by the video frame producer.
+     */
+    public static final int QUALITY_HIGHEST = CamcorderProfile.QUALITY_HIGH;
+    /**
+     * Standard Definition (SD) 480p video quality.
+     *
+     * <p>This video quality usually corresponds to a resolution of 720 x 480 (480p) pixels.
+     */
+    public static final int QUALITY_SD = CamcorderProfile.QUALITY_480P;
+    /**
+     * High Definition (HD) video quality.
+     *
+     * <p>This video quality usually corresponds to a resolution of 1280 x 720 (720p) pixels.
+     */
+    public static final int QUALITY_HD = CamcorderProfile.QUALITY_720P;
+    /**
+     * Full High Definition (FHD) 1080p video quality.
+     *
+     * <p>This video quality usually corresponds to a resolution of 1920 x 1080 (1080p) pixels.
+     */
+    public static final int QUALITY_FHD = CamcorderProfile.QUALITY_1080P;
+    /**
+     * Ultra High Definition (UHD) 2160p video quality.
+     *
+     * <p>This video quality usually corresponds to a resolution of 3840 x 2160 (2160p) pixels.
+     */
+    public static final int QUALITY_UHD = CamcorderProfile.QUALITY_2160P;
+
+    /** @hide */
+    @IntDef({QUALITY_NONE, QUALITY_LOWEST, QUALITY_HIGHEST, QUALITY_SD, QUALITY_HD, QUALITY_FHD,
+            QUALITY_UHD})
+    @Retention(RetentionPolicy.SOURCE)
+    @RestrictTo(Scope.LIBRARY)
+    public @interface VideoQuality {
+    }
+
+    /** All quality constants. */
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    static final List<Integer> QUALITIES = Arrays.asList(QUALITY_NONE, QUALITY_LOWEST,
+            QUALITY_HIGHEST, QUALITY_SD, QUALITY_HD, QUALITY_FHD, QUALITY_UHD);
+
+    /** Quality constants with size from large to small. */
+    private static final List<Integer> QUALITIES_ORDER_BY_SIZE = Arrays.asList(QUALITY_UHD,
+            QUALITY_FHD, QUALITY_HD, QUALITY_SD);
+
+    /**
+     * No fallback strategy.
+     *
+     * <p>When using this fallback strategy, if {@link #select(CameraInfo)} fails to find a
+     * supported quality, it will return {@link #QUALITY_NONE}.
+     */
+    public static final int FALLBACK_STRATEGY_NONE = 0;
+
+    /**
+     * Choose a higher quality if the desired quality isn't supported. Choose a lower quality if
+     * no higher quality is supported.
+     */
+    public static final int FALLBACK_STRATEGY_HIGHER = 1;
+
+    /**
+     * Choose a higher quality if the desired quality isn't supported.
+     *
+     * <p>When a higher quality can't be found, {@link #select(CameraInfo)} will return
+     * {@link #QUALITY_NONE}.
+     */
+    public static final int FALLBACK_STRATEGY_STRICTLY_HIGHER = 2;
+
+    /**
+     * Choose a lower quality if the desired quality isn't supported. Choose a higher quality if
+     * no lower quality is supported.
+     */
+    public static final int FALLBACK_STRATEGY_LOWER = 3;
+
+    /**
+     * Choose a lower quality if the desired quality isn't supported.
+     *
+     * <p>When a lower quality can't be found, {@link #select(CameraInfo)} will return
+     * {@link #QUALITY_NONE}.
+     */
+    public static final int FALLBACK_STRATEGY_STRICTLY_LOWER = 4;
+
+    private static final int FALLBACK_STRATEGY_START = FALLBACK_STRATEGY_NONE;
+    private static final int FALLBACK_STRATEGY_END = FALLBACK_STRATEGY_STRICTLY_LOWER;
+
+    /**
+     * The fallback strategies when desired quality is not supported.
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({FALLBACK_STRATEGY_NONE,
+            FALLBACK_STRATEGY_HIGHER,
+            FALLBACK_STRATEGY_STRICTLY_HIGHER,
+            FALLBACK_STRATEGY_LOWER,
+            FALLBACK_STRATEGY_STRICTLY_LOWER
+    })
+    public @interface FallbackStrategy {
+    }
+
+    /**
+     * Check if the input quality is one of video quality constants.
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public static boolean containsQuality(int quality) {
+        return QUALITIES.contains(quality);
+    }
+
+    /**
+     * Get all video quality constants with clearly defined size sorted from large to small.
+     *
+     * <p>{@link #QUALITY_NONE}, {@link #QUALITY_HIGHEST} and {@link #QUALITY_LOWEST} are not
+     * included.
+     *
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    @NonNull
+    public static List<Integer> getSortedQualities() {
+        return new ArrayList<>(QUALITIES_ORDER_BY_SIZE);
+    }
+
+    /**
+     * Gets all supported qualities on the device.
+     *
+     * <p>The returned list is sorted by quality size from large to small. For the qualities in
+     * the returned list, with the same input cameraInfo,
+     * {@link #isQualitySupported(CameraInfo, int)} will return {@code true} and
+     * {@link #getResolution(CameraInfo, int)} will return the corresponding resolution.
+     *
+     * <p>Note: Constants {@link #QUALITY_HIGHEST} and {@link #QUALITY_LOWEST} are not included
+     * in the returned list, but their corresponding qualities are included.
+     *
+     * @param cameraInfo the cameraInfo
+     */
+    @NonNull
+    public static List<Integer> getSupportedQualities(@NonNull CameraInfo cameraInfo) {
+        return VideoCapabilities.from(cameraInfo).getSupportedQualities();
+    }
+
+    /**
+     * Checks if the quality is supported.
+     *
+     * <p>For the qualities in the list of {@link #getSupportedQualities}, calling this method with
+     * these qualities will return {@code true}.
+     *
+     * @param cameraInfo the cameraInfo
+     * @param quality one of the quality constants. Possible values include
+     * {@link #QUALITY_LOWEST}, {@link #QUALITY_HIGHEST}, {@link #QUALITY_SD}, {@link #QUALITY_HD},
+     * {@link #QUALITY_FHD}, or {@link #QUALITY_UHD}.
+     * @return {@code true} if the quality is supported; {@code false} otherwise.
+     * @see #getSupportedQualities(CameraInfo)
+     */
+    public static boolean isQualitySupported(@NonNull CameraInfo cameraInfo,
+            @VideoQuality int quality) {
+        return VideoCapabilities.from(cameraInfo).isQualitySupported(quality);
+    }
+
+    /**
+     * Gets the corresponding resolution from the input quality.
+     *
+     * @param cameraInfo the cameraInfo
+     * @param quality one of the quality constants. Possible values include
+     * {@link QualitySelector#QUALITY_LOWEST}, {@link QualitySelector#QUALITY_HIGHEST},
+     * {@link QualitySelector#QUALITY_SD}, {@link QualitySelector#QUALITY_HD},
+     * {@link QualitySelector#QUALITY_FHD}, or {@link QualitySelector#QUALITY_UHD}.
+     * @return the corresponding resolution from the input quality, or {@code null} if the
+     * quality is not supported on the device. {@link #isQualitySupported(CameraInfo, int)} can
+     * be used to check if the input quality is supported.
+     * @throws IllegalArgumentException if not a quality constant
+     * @see #isQualitySupported
+     */
+    @Nullable
+    public static Size getResolution(@NonNull CameraInfo cameraInfo, @VideoQuality int quality) {
+        checkQualityConstantsOrThrow(quality);
+        CamcorderProfileProxy profile = VideoCapabilities.from(cameraInfo).getProfile(quality);
+        return profile != null ? new Size(profile.getVideoFrameWidth(),
+                profile.getVideoFrameHeight()) : null;
+    }
+
+    private final List<Integer> mPreferredQualityList;
+    @VideoQuality
+    private final int mFallbackQuality;
+    @FallbackStrategy
+    private final int mFallbackStrategy;
+
+    QualitySelector(@NonNull List<Integer> preferredQualityList,
+            @VideoQuality int fallbackQuality,
+            @FallbackStrategy int fallbackStrategy) {
+        Preconditions.checkArgument(preferredQualityList.size() > 0, "No preferred quality.");
+        mPreferredQualityList = Collections.unmodifiableList(preferredQualityList);
+        mFallbackQuality = fallbackQuality;
+        mFallbackStrategy = fallbackStrategy;
+    }
+
+    /**
+     * Sets the first desired quality.
+     *
+     * @param quality the quality constant. Possible values include {@link #QUALITY_LOWEST},
+     * {@link #QUALITY_HIGHEST}, {@link #QUALITY_SD}, {@link #QUALITY_HD}, {@link #QUALITY_FHD},
+     * or {@link #QUALITY_UHD}.
+     * @return the procedure that can continue to be set
+     * @throws IllegalArgumentException if not a quality constant.
+     */
+    @NonNull
+    public static Procedure firstTry(@VideoQuality int quality) {
+        return new Procedure(quality);
+    }
+
+    /**
+     * Gets an instance of QualitySelector with only one desired quality.
+     *
+     * <p>The returned QualitySelector will adopt {@link #FALLBACK_STRATEGY_NONE}.
+     *
+     * @param quality the quality constant. Possible values include {@link #QUALITY_LOWEST},
+     * {@link #QUALITY_HIGHEST}, {@link #QUALITY_SD}, {@link #QUALITY_HD}, {@link #QUALITY_FHD},
+     * or {@link #QUALITY_UHD}.
+     * @return the QualitySelector instance.
+     * @throws IllegalArgumentException if not a quality constant.
+     */
+    @NonNull
+    public static QualitySelector of(@VideoQuality int quality) {
+        return of(quality, FALLBACK_STRATEGY_NONE);
+    }
+
+    /**
+     * Gets an instance of QualitySelector with only one desired quality.
+     *
+     * <p>If the desired quality is not supported, the fallback strategy will be applied on
+     * this quality.
+     *
+     * @param quality the quality constant. Possible values include {@link #QUALITY_LOWEST},
+     * {@link #QUALITY_HIGHEST}, {@link #QUALITY_SD}, {@link #QUALITY_HD}, {@link #QUALITY_FHD},
+     * or {@link #QUALITY_UHD}.
+     * @param fallbackStrategy the fallback strategy. Possible values include
+     * {@link #FALLBACK_STRATEGY_NONE}, {@link #FALLBACK_STRATEGY_HIGHER},
+     * {@link #FALLBACK_STRATEGY_STRICTLY_HIGHER}, {@link #FALLBACK_STRATEGY_LOWER} and
+     * {@link #FALLBACK_STRATEGY_STRICTLY_LOWER}.
+     * @return the QualitySelector instance.
+     * @throws IllegalArgumentException if {@code quality} is not a quality constant or
+     * {@code fallbackStrategy} is not a fallback strategy constant.
+     */
+    @NonNull
+    public static QualitySelector of(@VideoQuality int quality,
+            @FallbackStrategy int fallbackStrategy) {
+        return firstTry(quality).finallyTry(quality, fallbackStrategy);
+    }
+
+    /**
+     * Find a quality match to the desired quality settings.
+     *
+     * <p>The method bases on the desired qualities and the fallback strategy to find out a
+     * supported quality on this device. The desired qualities can be set by a series of try
+     * methods such as {@link #firstTry(int)}, {@link #of(int)},
+     * {@link Procedure#thenTry(int)} and {@link Procedure#finallyTry(int)}. The fallback strategy
+     * can be set via {@link #of(int, int)} and {@link Procedure#finallyTry(int, int)}. If no
+     * fallback strategy is specified, {@link #FALLBACK_STRATEGY_NONE} will be applied by default.
+     *
+     * <p>The search algorithm first checks which desired quality is supported according to the
+     * set sequence. If no desired quality is supported, the fallback strategy will be applied to
+     * the quality set with it. If there is still no quality can be found, {@link #QUALITY_NONE}
+     * will be returned.
+     *
+     * @param cameraInfo the cameraInfo
+     * @return the first supported quality of the desired qualities, or a supported quality
+     * searched by fallback strategy, or {@link #QUALITY_NONE} when no quality is found.
+     */
+    @VideoQuality
+    public int select(@NonNull CameraInfo cameraInfo) {
+        VideoCapabilities videoCapabilities = VideoCapabilities.from(cameraInfo);
+
+        List<Integer> supportedQualityList = videoCapabilities.getSupportedQualities();
+        if (supportedQualityList.isEmpty()) {
+            Logger.w(TAG, "No supported quality on the device.");
+            return QUALITY_NONE;
+        }
+
+        // Find exact quality.
+        for (Integer quality : mPreferredQualityList) {
+            if (videoCapabilities.isQualitySupported(quality)) {
+                Logger.d(TAG, "Quality is selected by exact quality = " + quality);
+                return quality;
+            }
+        }
+
+        // Find quality by fallback strategy based on fallback quality.
+        return selectByFallbackStrategy(videoCapabilities);
+    }
+
+    @VideoQuality
+    private int selectByFallbackStrategy(VideoCapabilities videoCapabilities) {
+        Logger.d(TAG, "Select quality by fallbackStrategy = " + mFallbackStrategy
+                + " on fallback quality = " + mFallbackQuality);
+        // If fallback quality is already supported, return directly.
+        if (videoCapabilities.isQualitySupported(mFallbackQuality)) {
+            return mFallbackQuality;
+        }
+
+        // No fallback strategy, return directly.
+        if (mFallbackStrategy == QualitySelector.FALLBACK_STRATEGY_NONE) {
+            return QUALITY_NONE;
+        }
+
+        // Size is from large to small
+        List<Integer> sizeSortedQualities = getSortedQualities();
+        int index = sizeSortedQualities.indexOf(mFallbackQuality);
+        Preconditions.checkState(index != -1); // Should not happen.
+
+        // search larger supported quality
+        int largerQuality = QUALITY_NONE;
+        for (int i = index - 1; i > 0; i--) {
+            int quality = sizeSortedQualities.get(i);
+            if (videoCapabilities.getProfile(quality) != null) {
+                largerQuality = quality;
+                break;
+            }
+        }
+
+        // search smaller supported quality
+        int smallerQuality = QUALITY_NONE;
+        for (int i = index + 1; index < sizeSortedQualities.size() - 1; i++) {
+            int quality = sizeSortedQualities.get(i);
+            if (videoCapabilities.getProfile(quality) != null) {
+                smallerQuality = quality;
+                break;
+            }
+        }
+
+        Logger.d(TAG, "sizeSortedQualities = " + sizeSortedQualities
+                + ", fallback quality = " + mFallbackQuality
+                + ", largerQuality = " + largerQuality
+                + ", smallerQuality = " + smallerQuality);
+
+        switch (mFallbackStrategy) {
+            case QualitySelector.FALLBACK_STRATEGY_HIGHER:
+                if (largerQuality != QUALITY_NONE) {
+                    return largerQuality;
+                } else if (smallerQuality != QUALITY_NONE) {
+                    return smallerQuality;
+                }
+                break;
+            case QualitySelector.FALLBACK_STRATEGY_STRICTLY_HIGHER:
+                if (largerQuality != QUALITY_NONE) {
+                    return largerQuality;
+                }
+                break;
+            case QualitySelector.FALLBACK_STRATEGY_LOWER:
+                if (smallerQuality != QUALITY_NONE) {
+                    return smallerQuality;
+                } else if (largerQuality != QUALITY_NONE) {
+                    return largerQuality;
+                }
+                break;
+            case QualitySelector.FALLBACK_STRATEGY_STRICTLY_LOWER:
+                if (smallerQuality != QUALITY_NONE) {
+                    return smallerQuality;
+                }
+                break;
+            case QualitySelector.FALLBACK_STRATEGY_NONE:
+                // No-Op
+                break;
+            default:
+                throw new AssertionError("Unhandled fallback strategy: " + mFallbackStrategy);
+        }
+        return QUALITY_NONE;
+    }
+
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    static void checkQualityConstantsOrThrow(@QualitySelector.VideoQuality int quality) {
+        Preconditions.checkArgument(QualitySelector.containsQuality(quality),
+                "Unknown quality: " + quality);
+    }
+
+    /**
+     * The procedure can continue to set the desired quality and fallback strategy.
+     */
+    public static class Procedure {
+        private final List<Integer> mPreferredQualityList = new ArrayList<>();
+
+        Procedure(int quality) {
+            addQuality(quality);
+        }
+
+        /**
+         * Sets the next desired quality.
+         *
+         * @param quality the quality constant. Possible values include {@link #QUALITY_LOWEST},
+         * {@link #QUALITY_HIGHEST}, {@link #QUALITY_SD}, {@link #QUALITY_HD},
+         * {@link #QUALITY_FHD} or {@link #QUALITY_UHD}.
+         * @return the procedure that can continue to be set
+         * @throws IllegalArgumentException if not a quality constant
+         */
+        @NonNull
+        public Procedure thenTry(@VideoQuality int quality) {
+            addQuality(quality);
+            return this;
+        }
+
+        /**
+         * Sets the final desired quality.
+         *
+         * <p>The returned QualitySelector will adopt {@link #FALLBACK_STRATEGY_NONE}.
+         *
+         * @param quality the quality constant. Possible values include {@link #QUALITY_LOWEST},
+         * {@link #QUALITY_HIGHEST}, {@link #QUALITY_SD}, {@link #QUALITY_HD},
+         * {@link #QUALITY_FHD} or {@link #QUALITY_UHD}.
+         * @return the QualitySelector.
+         * @throws IllegalArgumentException if not a quality constant
+         */
+        @NonNull
+        public QualitySelector finallyTry(@VideoQuality int quality) {
+            return finallyTry(quality, FALLBACK_STRATEGY_NONE);
+        }
+
+        /**
+         * Sets the final desired quality and fallback strategy.
+         *
+         * <p>The fallback strategy will be applied on this quality when all desired qualities are
+         * not supported.
+         *
+         * @param quality the quality constant. Possible values include {@link #QUALITY_LOWEST},
+         * {@link #QUALITY_HIGHEST}, {@link #QUALITY_SD}, {@link #QUALITY_HD},
+         * {@link #QUALITY_FHD} or {@link #QUALITY_UHD}.
+         * @param fallbackStrategy the fallback strategy. Possible values include
+         * {@link #FALLBACK_STRATEGY_NONE}, {@link #FALLBACK_STRATEGY_HIGHER},
+         * {@link #FALLBACK_STRATEGY_STRICTLY_HIGHER}, {@link #FALLBACK_STRATEGY_LOWER} and
+         * {@link #FALLBACK_STRATEGY_STRICTLY_LOWER}.
+         * @return the QualitySelector.
+         * @throws IllegalArgumentException if {@code quality} is not a quality constant or
+         * {@code fallbackStrategy} is not a fallback strategy constant.
+         */
+        @NonNull
+        public QualitySelector finallyTry(@VideoQuality int quality,
+                @FallbackStrategy int fallbackStrategy) {
+            Preconditions.checkArgument(fallbackStrategy >= FALLBACK_STRATEGY_START
+                            && fallbackStrategy <= FALLBACK_STRATEGY_END,
+                    "The value must be a fallback strategy constant.");
+            addQuality(quality);
+            return new QualitySelector(new ArrayList<>(mPreferredQualityList), quality,
+                    fallbackStrategy);
+        }
+
+        private void addQuality(@VideoQuality int quality) {
+            checkQualityConstantsOrThrow(quality);
+            Preconditions.checkArgument(quality != QUALITY_NONE, "Unsupported quality: " + quality);
+            mPreferredQualityList.add(quality);
+        }
+    }
+}
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoCapabilities.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapabilities.java
new file mode 100644
index 0000000..58d6819
--- /dev/null
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoCapabilities.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2021 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.camera.video;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.annotation.RestrictTo.Scope;
+import androidx.camera.core.CameraInfo;
+import androidx.camera.core.Logger;
+import androidx.camera.core.impl.CamcorderProfileProvider;
+import androidx.camera.core.impl.CamcorderProfileProxy;
+import androidx.camera.core.impl.CameraInfoInternal;
+import androidx.core.util.Preconditions;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * VideoCapabilities is used to query video recording capabilities on the device.
+ *
+ * <p>Calling {@link #from(CameraInfo)} to obtain the VideoCapabilities.
+ *
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+public final class VideoCapabilities {
+    private static final String TAG = "VideoCapabilities";
+
+    /**
+     * The supported @link CamcorderProfileProxy} map from quality to CamcorderProfileProxy. The
+     * order is from size large to small.
+     */
+    private final Map<Integer, CamcorderProfileProxy> mSupportedProfileMap = new LinkedHashMap<>();
+    private final CamcorderProfileProxy mHighestProfile;
+    private final CamcorderProfileProxy mLowestProfile;
+
+    /**
+     * Creates a VideoCapabilities.
+     *
+     * @param cameraInfoInternal the cameraInfo
+     * @throws IllegalArgumentException if unable to get the capability information from the
+     * CameraInfo.
+     */
+    VideoCapabilities(@NonNull CameraInfoInternal cameraInfoInternal) {
+        CamcorderProfileProvider camcorderProfileProvider =
+                cameraInfoInternal.getCamcorderProfileProvider();
+
+        // Construct supported profile map
+        for (@QualitySelector.VideoQuality int quality : QualitySelector.getSortedQualities()) {
+            // SortedQualities is from size large to small
+
+            // Get CamcorderProfile
+            if (!camcorderProfileProvider.hasProfile(quality)) {
+                continue;
+            }
+            CamcorderProfileProxy profile = camcorderProfileProvider.get(quality);
+            Logger.d(TAG, "profile = " + profile);
+            mSupportedProfileMap.put(quality, profile);
+        }
+        if (mSupportedProfileMap.isEmpty()) {
+            Logger.e(TAG, "No supported CamcorderProfile");
+            mLowestProfile = null;
+            mHighestProfile = null;
+        } else {
+            Deque<CamcorderProfileProxy> profileQueue = new ArrayDeque<>(
+                    mSupportedProfileMap.values());
+            mHighestProfile = profileQueue.peekFirst();
+            mLowestProfile = profileQueue.peekLast();
+        }
+    }
+
+    /** Gets VideoCapabilities by the {@link CameraInfo} */
+    @NonNull
+    public static VideoCapabilities from(@NonNull CameraInfo cameraInfo) {
+        return new VideoCapabilities((CameraInfoInternal) cameraInfo);
+    }
+
+    /**
+     * Gets all supported qualities on the device.
+     *
+     * <p>The returned list is sorted by quality size from large to small. For the qualities in
+     * the returned list, calling {@link #getProfile(int)} with these qualities will return a
+     * non-null result.
+     *
+     * <p>Note: Constants {@link QualitySelector#QUALITY_HIGHEST} and
+     * {@link QualitySelector#QUALITY_LOWEST} are not included.
+     */
+    @NonNull
+    public List<Integer> getSupportedQualities() {
+        return new ArrayList<>(mSupportedProfileMap.keySet());
+    }
+
+    /**
+     * Checks if the quality is supported.
+     *
+     * @param quality one of the quality constants. Possible values include
+     * {@link QualitySelector#QUALITY_LOWEST}, {@link QualitySelector#QUALITY_HIGHEST},
+     * {@link QualitySelector#QUALITY_SD}, {@link QualitySelector#QUALITY_HD},
+     * {@link QualitySelector#QUALITY_FHD}, or {@link QualitySelector#QUALITY_UHD}.
+     * @return {@code true} if the quality is supported; {@code false} otherwise.
+     * @throws IllegalArgumentException if not a quality constant.
+     */
+    public boolean isQualitySupported(@QualitySelector.VideoQuality int quality) {
+        checkQualityConstantsOrThrow(quality);
+        return getProfile(quality) != null;
+    }
+
+    /**
+     * Gets the corresponding {@link CamcorderProfileProxy} of the input quality.
+     *
+     * @param quality one of the quality constants. Possible values include
+     * {@link QualitySelector#QUALITY_LOWEST}, {@link QualitySelector#QUALITY_HIGHEST},
+     * {@link QualitySelector#QUALITY_SD}, {@link QualitySelector#QUALITY_HD},
+     * {@link QualitySelector#QUALITY_FHD}, or {@link QualitySelector#QUALITY_UHD}.
+     * @return the CamcorderProfileProxy
+     * @throws IllegalArgumentException if not a quality constant
+     */
+    @Nullable
+    public CamcorderProfileProxy getProfile(@QualitySelector.VideoQuality int quality) {
+        checkQualityConstantsOrThrow(quality);
+        if (quality == QualitySelector.QUALITY_HIGHEST) {
+            return mHighestProfile;
+        } else if (quality == QualitySelector.QUALITY_LOWEST) {
+            return mLowestProfile;
+        }
+        return mSupportedProfileMap.get(quality);
+    }
+
+    private static void checkQualityConstantsOrThrow(@QualitySelector.VideoQuality int quality) {
+        Preconditions.checkArgument(QualitySelector.containsQuality(quality),
+                "Unknown quality: " + quality);
+    }
+}
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoCaptureLegacy.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoCaptureLegacy.java
index 21d82f6..01096ab 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoCaptureLegacy.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoCaptureLegacy.java
@@ -827,6 +827,7 @@
         // Audio encoding loop. Exits on end of stream.
         boolean audioEos = false;
         int outIndex;
+        long lastAudioTimestamp = 0;
         while (!audioEos && mIsRecording) {
             // Check for end of stream from main thread
             if (mEndOfAudioStreamSignal.get()) {
@@ -867,7 +868,20 @@
                         case MediaCodec.INFO_TRY_AGAIN_LATER:
                             break;
                         default:
-                            audioEos = writeAudioEncodedBuffer(outIndex);
+                            // Drops out of order audio frame if the frame's earlier than last
+                            // frame.
+                            if (mAudioBufferInfo.presentationTimeUs >= lastAudioTimestamp) {
+                                audioEos = writeAudioEncodedBuffer(outIndex);
+                                lastAudioTimestamp = mAudioBufferInfo.presentationTimeUs;
+                            } else {
+                                Logger.w(TAG,
+                                        "Drops frame, current frame's timestamp "
+                                                + mAudioBufferInfo.presentationTimeUs
+                                                + " is earlier that last frame "
+                                                + lastAudioTimestamp);
+                                // Releases this frame from output buffer
+                                mAudioEncoder.releaseOutputBuffer(outIndex, false);
+                            }
                     }
                 } while (outIndex >= 0 && !audioEos); // end of dequeue output buffer
             }
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/VideoSpec.java b/camera/camera-video/src/main/java/androidx/camera/video/VideoSpec.java
index bf45940..46cc38c 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/VideoSpec.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/VideoSpec.java
@@ -16,18 +16,17 @@
 
 package androidx.camera.video;
 
-import android.media.CamcorderProfile;
+import static androidx.camera.video.QualitySelector.FALLBACK_STRATEGY_HIGHER;
+import static androidx.camera.video.QualitySelector.QUALITY_FHD;
+import static androidx.camera.video.QualitySelector.QUALITY_HD;
+import static androidx.camera.video.QualitySelector.QUALITY_SD;
+
 import android.util.Range;
 
-import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
 
 import com.google.auto.value.AutoValue;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
 /**
  * Video specification that is options to config video encoding.
  */
@@ -53,50 +52,16 @@
             Integer.MAX_VALUE);
 
     /**
-     * Allow the video frame producer to choose video quality based on its current state.
-     */
-    public static final int VIDEO_QUALITY_AUTO = -1;
-    /**
-     * Choose the lowest video quality supported by the video frame producer.
-     */
-    public static final int VIDEO_QUALITY_LOWEST = CamcorderProfile.QUALITY_LOW;
-    /**
-     * Choose the highest video quality supported by the video frame producer.
-     */
-    public static final int VIDEO_QUALITY_HIGHEST = CamcorderProfile.QUALITY_HIGH;
-    /**
-     * Standard Definition (SD) 480p video quality.
+     * Quality selector representing no preference for quality.
      *
-     * <p>This video quality usually corresponds to a resolution of 720 x 480 (480p) pixels.
+     * <p>Using this value with {@link Builder#setQualitySelector(QualitySelector)} allows the
+     * video frame producer to choose video quality based on its current state.
      */
-    public static final int VIDEO_QUALITY_SD = CamcorderProfile.QUALITY_480P;
-    /**
-     * High Definition (HD) video quality.
-     *
-     * <p>This video quality usually corresponds to a resolution of 1280 x 720 (720p) pixels.
-     */
-    public static final int VIDEO_QUALITY_HD = CamcorderProfile.QUALITY_720P;
-    /**
-     * Full High Definition (FHD) 1080p video quality.
-     *
-     * <p>This video quality usually corresponds to a resolution of 1920 x 1080 (1080p) pixels.
-     */
-    public static final int VIDEO_QUALITY_FHD = CamcorderProfile.QUALITY_1080P;
-    /**
-     * Ultra High Definition (UHD) 2160p video quality.
-     *
-     * <p>This video quality usually corresponds to a resolution of 3840 x 2160 (2160p) pixels.
-     */
-    public static final int VIDEO_QUALITY_UHD = CamcorderProfile.QUALITY_2160P;
-
-
-    /** @hide */
-    @IntDef({VIDEO_QUALITY_AUTO, VIDEO_QUALITY_LOWEST, VIDEO_QUALITY_HIGHEST, VIDEO_QUALITY_SD,
-            VIDEO_QUALITY_HD, VIDEO_QUALITY_FHD, VIDEO_QUALITY_UHD})
-    @Retention(RetentionPolicy.SOURCE)
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    public @interface VideoQuality {
-    }
+    public static final QualitySelector QUALITY_SELECTOR_AUTO =
+            QualitySelector.firstTry(QUALITY_FHD)
+                    .thenTry(QUALITY_HD)
+                    .thenTry(QUALITY_SD)
+                    .finallyTry(QUALITY_FHD, FALLBACK_STRATEGY_HIGHER);
 
     // Restrict constructor to same package
     VideoSpec() {
@@ -106,20 +71,14 @@
     @NonNull
     public static Builder builder() {
         return new AutoValue_VideoSpec.Builder()
-                .setVideoQuality(VIDEO_QUALITY_AUTO)
+                .setQualitySelector(QUALITY_SELECTOR_AUTO)
                 .setFrameRate(FRAME_RATE_RANGE_AUTO)
                 .setBitrate(BITRATE_RANGE_AUTO);
     }
 
-    /**
-     * Gets the video quality.
-     *
-     * @return the video quality. Possible values include {@link #VIDEO_QUALITY_AUTO},
-     * {@link #VIDEO_QUALITY_LOWEST}, {@link #VIDEO_QUALITY_HIGHEST}, {@link #VIDEO_QUALITY_SD},
-     * {@link #VIDEO_QUALITY_HD}, {@link #VIDEO_QUALITY_FHD}, or {@link #VIDEO_QUALITY_UHD}.
-     */
-    @VideoQuality
-    public abstract int getVideoQuality();
+    /** Gets the {@link QualitySelector}. */
+    @NonNull
+    public abstract QualitySelector getQualitySelector();
 
     /** Gets the frame rate. */
     @NonNull
@@ -143,22 +102,17 @@
         }
 
         /**
-         * Sets the video quality.
+         * Sets the {@link QualitySelector}.
          *
          * <p>Video encoding parameters such as frame rate and bitrate will often be automatically
          * determined according to quality. If video parameters are not set directly (such as
          * through {@link #setFrameRate(Range)}, the device will choose values calibrated for the
          * quality on that device.
          *
-         * <p>If not set, defaults to {@link #VIDEO_QUALITY_AUTO}.
-         *
-         * @param videoQuality the video quality. Possible values include
-         * {@link #VIDEO_QUALITY_AUTO}, {@link #VIDEO_QUALITY_LOWEST},
-         * {@link #VIDEO_QUALITY_HIGHEST}, {@link #VIDEO_QUALITY_SD}, {@link #VIDEO_QUALITY_HD},
-         * {@link #VIDEO_QUALITY_FHD}, or {@link #VIDEO_QUALITY_UHD}.
+         * <p>If not set, defaults to {@link #QUALITY_SELECTOR_AUTO}.
          */
         @NonNull
-        public abstract Builder setVideoQuality(@VideoQuality int videoQuality);
+        public abstract Builder setQualitySelector(@NonNull QualitySelector qualitySelector);
 
         /**
          * Sets the frame rate.
diff --git a/camera/camera-video/src/main/java/androidx/camera/video/internal/encoder/EncoderImpl.java b/camera/camera-video/src/main/java/androidx/camera/video/internal/encoder/EncoderImpl.java
index 132003d..3f6e043 100644
--- a/camera/camera-video/src/main/java/androidx/camera/video/internal/encoder/EncoderImpl.java
+++ b/camera/camera-video/src/main/java/androidx/camera/video/internal/encoder/EncoderImpl.java
@@ -786,12 +786,14 @@
     @SuppressWarnings("WeakerAccess") /* synthetic accessor */
     class InternalStateObservable implements Observable<InternalState> {
 
-        private final Map<Observer<InternalState>, Executor> mObservers = new LinkedHashMap<>();
+        private final Map<Observer<? super InternalState>, Executor> mObservers =
+                new LinkedHashMap<>();
 
         @ExecutedBy("mEncoderExecutor")
         void notifyState() {
             final InternalState state = mState;
-            for (Map.Entry<Observer<InternalState>, Executor> entry : mObservers.entrySet()) {
+            for (Map.Entry<Observer<? super InternalState>, Executor> entry :
+                    mObservers.entrySet()) {
                 entry.getValue().execute(() -> entry.getKey().onNewData(state));
             }
         }
@@ -806,7 +808,7 @@
         @ExecutedBy("mEncoderExecutor")
         @Override
         public void addObserver(@NonNull Executor executor,
-                @NonNull Observer<InternalState> observer) {
+                @NonNull Observer<? super InternalState> observer) {
             final InternalState state = mState;
             mObservers.put(observer, executor);
             executor.execute(() -> observer.onNewData(state));
@@ -814,7 +816,7 @@
 
         @ExecutedBy("mEncoderExecutor")
         @Override
-        public void removeObserver(@NonNull Observer<InternalState> observer) {
+        public void removeObserver(@NonNull Observer<? super InternalState> observer) {
             mObservers.remove(observer);
         }
     }
@@ -1114,7 +1116,8 @@
     @SuppressWarnings("WeakerAccess") /* synthetic accessor */
     class ByteBufferInput implements Encoder.ByteBufferInput {
 
-        private final Map<Observer<State>, Executor> mStateObservers = new LinkedHashMap<>();
+        private final Map<Observer<? super State>, Executor> mStateObservers =
+                new LinkedHashMap<>();
 
         private State mBufferProviderState = State.INACTIVE;
 
@@ -1163,7 +1166,8 @@
 
         /** {@inheritDoc} */
         @Override
-        public void addObserver(@NonNull Executor executor, @NonNull Observer<State> observer) {
+        public void addObserver(@NonNull Executor executor,
+                @NonNull Observer<? super State> observer) {
             mEncoderExecutor.execute(() -> {
                 mStateObservers.put(Preconditions.checkNotNull(observer),
                         Preconditions.checkNotNull(executor));
@@ -1174,7 +1178,7 @@
 
         /** {@inheritDoc} */
         @Override
-        public void removeObserver(@NonNull Observer<State> observer) {
+        public void removeObserver(@NonNull Observer<? super State> observer) {
             mEncoderExecutor.execute(
                     () -> mStateObservers.remove(Preconditions.checkNotNull(observer)));
         }
@@ -1194,7 +1198,7 @@
                 mAcquisitionList.clear();
             }
 
-            for (Map.Entry<Observer<State>, Executor> entry : mStateObservers.entrySet()) {
+            for (Map.Entry<Observer<? super State>, Executor> entry : mStateObservers.entrySet()) {
                 try {
                     entry.getValue().execute(() -> entry.getKey().onNewData(newState));
                 } catch (RejectedExecutionException e) {
diff --git a/camera/camera-video/src/test/java/androidx/camera/video/QualitySelectorTest.kt b/camera/camera-video/src/test/java/androidx/camera/video/QualitySelectorTest.kt
new file mode 100644
index 0000000..856b56b
--- /dev/null
+++ b/camera/camera-video/src/test/java/androidx/camera/video/QualitySelectorTest.kt
@@ -0,0 +1,420 @@
+/*
+ * Copyright 2021 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.camera.video
+
+import android.os.Build
+import androidx.camera.testing.CamcorderProfileUtil
+import androidx.camera.testing.CamcorderProfileUtil.PROFILE_1080P
+import androidx.camera.testing.CamcorderProfileUtil.PROFILE_2160P
+import androidx.camera.testing.CamcorderProfileUtil.PROFILE_480P
+import androidx.camera.testing.CamcorderProfileUtil.PROFILE_720P
+import androidx.camera.testing.CamcorderProfileUtil.RESOLUTION_2160P
+import androidx.camera.testing.CamcorderProfileUtil.RESOLUTION_720P
+import androidx.camera.testing.fakes.FakeCamcorderProfileProvider
+import androidx.camera.testing.fakes.FakeCameraInfoInternal
+import androidx.camera.video.QualitySelector.FALLBACK_STRATEGY_HIGHER
+import androidx.camera.video.QualitySelector.FALLBACK_STRATEGY_LOWER
+import androidx.camera.video.QualitySelector.FALLBACK_STRATEGY_NONE
+import androidx.camera.video.QualitySelector.FALLBACK_STRATEGY_STRICTLY_HIGHER
+import androidx.camera.video.QualitySelector.FALLBACK_STRATEGY_STRICTLY_LOWER
+import androidx.camera.video.QualitySelector.QUALITY_FHD
+import androidx.camera.video.QualitySelector.QUALITY_HD
+import androidx.camera.video.QualitySelector.QUALITY_HIGHEST
+import androidx.camera.video.QualitySelector.QUALITY_LOWEST
+import androidx.camera.video.QualitySelector.QUALITY_NONE
+import androidx.camera.video.QualitySelector.QUALITY_SD
+import androidx.camera.video.QualitySelector.QUALITY_UHD
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.assertThrows
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+
+private const val NOT_QUALITY_CONSTANT = -111
+private const val NOT_FALLBACK_STRATEGY_CONSTANT = -1
+private const val CAMERA_ID_0 = "0"
+private const val CAMERA_ID_1 = "1"
+private val CAMERA_0_PROFILE_HIGH = CamcorderProfileUtil.asHighQuality(PROFILE_2160P)
+private val CAMERA_0_PROFILE_LOW = CamcorderProfileUtil.asLowQuality(PROFILE_720P)
+private val CAMERA_1_PROFILE_HIGH = CamcorderProfileUtil.asHighQuality(PROFILE_1080P)
+private val CAMERA_1_PROFILE_LOW = CamcorderProfileUtil.asLowQuality(PROFILE_480P)
+
+@RunWith(RobolectricTestRunner::class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+class QualitySelectorTest {
+
+    private val cameraInfo0 = FakeCameraInfoInternal(CAMERA_ID_0).apply {
+        camcorderProfileProvider = FakeCamcorderProfileProvider.Builder()
+            .addProfile(CAMERA_0_PROFILE_HIGH)
+            .addProfile(PROFILE_2160P)
+            .addProfile(PROFILE_720P)
+            .addProfile(CAMERA_0_PROFILE_LOW)
+            .build()
+    }
+    private val cameraInfo1 = FakeCameraInfoInternal(CAMERA_ID_1).apply {
+        camcorderProfileProvider = FakeCamcorderProfileProvider.Builder()
+            .addProfile(CAMERA_1_PROFILE_HIGH)
+            .addProfile(PROFILE_1080P)
+            .addProfile(PROFILE_480P)
+            .addProfile(CAMERA_1_PROFILE_LOW)
+            .build()
+    }
+
+    @Test
+    fun getSortedQualities_fromLargeToSmall() {
+        val sortedQualities = QualitySelector.getSortedQualities()
+
+        assertThat(sortedQualities[0]).isEqualTo(QUALITY_UHD)
+        assertThat(sortedQualities[1]).isEqualTo(QUALITY_FHD)
+        assertThat(sortedQualities[2]).isEqualTo(QUALITY_HD)
+        assertThat(sortedQualities[3]).isEqualTo(QUALITY_SD)
+    }
+
+    @Test
+    fun getSupportedQualities_fromLargeToSmall() {
+        // camera0 supports 2160P(UHD) and 720P(HD)
+        val supportedQualities = QualitySelector.getSupportedQualities(cameraInfo0)
+
+        assertThat(supportedQualities[0]).isEqualTo(QUALITY_UHD)
+        assertThat(supportedQualities[1]).isEqualTo(QUALITY_HD)
+    }
+
+    @Test
+    fun isQualitySupported_returnCorrectResult() {
+        // camera0 supports 2160P(UHD) and 720P(HD)
+        assertThat(QualitySelector.isQualitySupported(cameraInfo0, QUALITY_NONE)).isFalse()
+        assertThat(QualitySelector.isQualitySupported(cameraInfo0, QUALITY_HIGHEST)).isTrue()
+        assertThat(QualitySelector.isQualitySupported(cameraInfo0, QUALITY_LOWEST)).isTrue()
+        assertThat(QualitySelector.isQualitySupported(cameraInfo0, QUALITY_UHD)).isTrue()
+        assertThat(QualitySelector.isQualitySupported(cameraInfo0, QUALITY_FHD)).isFalse()
+        assertThat(QualitySelector.isQualitySupported(cameraInfo0, QUALITY_HD)).isTrue()
+        assertThat(QualitySelector.isQualitySupported(cameraInfo0, QUALITY_SD)).isFalse()
+    }
+
+    @Test
+    fun getResolution_returnCorrectResolution() {
+        // camera0 supports 2160P(UHD) and 720P(HD)
+        assertThat(
+            QualitySelector.getResolution(cameraInfo0, QUALITY_NONE)
+        ).isNull()
+        assertThat(
+            QualitySelector.getResolution(cameraInfo0, QUALITY_HIGHEST)
+        ).isEqualTo(RESOLUTION_2160P)
+        assertThat(
+            QualitySelector.getResolution(cameraInfo0, QUALITY_LOWEST)
+        ).isEqualTo(RESOLUTION_720P)
+        assertThat(
+            QualitySelector.getResolution(cameraInfo0, QUALITY_UHD)
+        ).isEqualTo(RESOLUTION_2160P)
+        assertThat(
+            QualitySelector.getResolution(cameraInfo0, QUALITY_FHD)
+        ).isNull()
+        assertThat(
+            QualitySelector.getResolution(cameraInfo0, QUALITY_HD)
+        ).isEqualTo(RESOLUTION_720P)
+        assertThat(
+            QualitySelector.getResolution(cameraInfo0, QUALITY_SD)
+        ).isNull()
+    }
+
+    @Test
+    fun of_setNonQualityConstant_throwException() {
+        // Assert.
+        assertThrows(IllegalArgumentException::class.java) {
+            // Act.
+            QualitySelector.of(NOT_QUALITY_CONSTANT)
+        }
+    }
+
+    @Test
+    fun thenTry_setNonQualityConstant_throwException() {
+        // Assert.
+        assertThrows(IllegalArgumentException::class.java) {
+            // Act.
+            QualitySelector.firstTry(QUALITY_FHD)
+                .thenTry(NOT_QUALITY_CONSTANT)
+        }
+    }
+
+    @Test
+    fun finallyTry_setNonQualityConstant_throwException() {
+        // Assert.
+        assertThrows(IllegalArgumentException::class.java) {
+            // Act.
+            QualitySelector.firstTry(QUALITY_FHD)
+                .thenTry(QUALITY_HD)
+                .finallyTry(NOT_QUALITY_CONSTANT)
+        }
+    }
+
+    @Test
+    fun of_setNonFallbackStrategyConstant_throwException() {
+        // Assert.
+        assertThrows(IllegalArgumentException::class.java) {
+            // Act.
+            QualitySelector.of(QUALITY_FHD, NOT_FALLBACK_STRATEGY_CONSTANT)
+        }
+    }
+
+    @Test
+    fun finallyTry_setNonFallbackStrategyConstant_throwException() {
+        // Assert.
+        assertThrows(IllegalArgumentException::class.java) {
+            // Act.
+            QualitySelector.firstTry(QUALITY_FHD)
+                .finallyTry(QUALITY_HD, NOT_FALLBACK_STRATEGY_CONSTANT)
+        }
+    }
+
+    @Test
+    fun select_byFirstTry() {
+        // Arrange.
+        // camera0 supports 2160P(UHD) and 720P(HD)
+        val qualitySelector = QualitySelector.firstTry(QUALITY_UHD)
+            .finallyTry(QUALITY_HD)
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo0)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_UHD)
+    }
+
+    @Test
+    fun select_byOf() {
+        // Arrange.
+        // camera0 supports 2160P(UHD) and 720P(HD)
+        val qualitySelector = QualitySelector.of(QUALITY_UHD)
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo0)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_UHD)
+    }
+
+    @Test
+    fun select_byOf_noFallbackStrategy() {
+        // Arrange.
+        // camera0 supports 2160P(UHD) and 720P(HD)
+        val qualitySelector = QualitySelector.of(QUALITY_FHD)
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo0)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_NONE)
+    }
+
+    @Test
+    fun select_byOf_withFallbackStrategy() {
+        // Arrange.
+        // camera0 supports 2160P(UHD) and 720P(HD)
+        val qualitySelector = QualitySelector.of(
+            QUALITY_FHD,
+            FALLBACK_STRATEGY_LOWER
+        )
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo0)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_HD)
+    }
+
+    @Test
+    fun select_byThenTry() {
+        // Arrange.
+        // camera0 supports 2160P(UHD) and 720P(HD)
+        val qualitySelector = QualitySelector.firstTry(QUALITY_FHD)
+            .thenTry(QUALITY_UHD)
+            .finallyTry(FALLBACK_STRATEGY_NONE)
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo0)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_UHD)
+    }
+
+    @Test
+    fun select_byFinallyTry() {
+        // Arrange.
+        // camera0 supports 2160P(UHD) and 720P(HD)
+        val qualitySelector = QualitySelector.firstTry(QUALITY_FHD)
+            .thenTry(QUALITY_SD)
+            .finallyTry(QUALITY_UHD)
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo0)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_UHD)
+    }
+
+    @Test
+    fun select_byFinallyTry_noFallbackStrategy() {
+        // Arrange.
+        // camera0 supports 2160P(UHD) and 720P(HD)
+        val qualitySelector = QualitySelector.firstTry(QUALITY_FHD)
+            .finallyTry(QUALITY_SD)
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo0)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_NONE)
+    }
+
+    @Test
+    fun select_byFinallyTry_withFallbackStrategy() {
+        // Arrange.
+        // camera0 supports 2160P(UHD) and 720P(HD)
+        val qualitySelector = QualitySelector.firstTry(QUALITY_FHD)
+            .finallyTry(QUALITY_SD, FALLBACK_STRATEGY_HIGHER)
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo0)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_HD)
+    }
+
+    @Test
+    fun select_fallbackLower_getLower() {
+        // Arrange.
+        // camera0 supports 2160P(UHD) and 720P(HD)
+        val qualitySelector = QualitySelector.of(
+            QUALITY_FHD, FALLBACK_STRATEGY_LOWER
+        )
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo0)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_HD)
+    }
+
+    @Test
+    fun select_fallbackLower_getHigher() {
+        // Arrange.
+        // camera0 supports 2160P(UHD) and 720P(HD)
+        val qualitySelector = QualitySelector.of(
+            QUALITY_SD, FALLBACK_STRATEGY_LOWER
+        )
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo0)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_HD)
+    }
+
+    @Test
+    fun select_fallbackStrictLower_getLower() {
+        // Arrange.
+        // camera0 supports 2160P(UHD) and 720P(HD)
+        val qualitySelector = QualitySelector.of(
+            QUALITY_FHD, FALLBACK_STRATEGY_STRICTLY_LOWER
+        )
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo0)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_HD)
+    }
+
+    @Test
+    fun select_fallbackStrictLower_getNone() {
+        // Arrange.
+        // camera0 supports 2160P(UHD) and 720P(HD)
+        val qualitySelector = QualitySelector.of(
+            QUALITY_SD, FALLBACK_STRATEGY_STRICTLY_LOWER
+        )
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo0)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_NONE)
+    }
+
+    @Test
+    fun select_fallbackHigher_getHigher() {
+        // Arrange.
+        // camera1 supports 1080P(FHD) and 480P(SD)
+        val qualitySelector = QualitySelector.of(
+            QUALITY_HD,
+            FALLBACK_STRATEGY_HIGHER
+        )
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo1)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_FHD)
+    }
+
+    @Test
+    fun select_fallbackHigher_getLower() {
+        // Arrange.
+        // camera1 supports 1080P(FHD) and 480P(SD)
+        val qualitySelector = QualitySelector.of(
+            QUALITY_UHD, FALLBACK_STRATEGY_HIGHER
+        )
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo1)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_FHD)
+    }
+
+    @Test
+    fun select_fallbackStrictHigher_getHigher() {
+        // Arrange.
+        // camera1 supports 1080P(FHD) and 480P(SD)
+        val qualitySelector = QualitySelector.of(
+            QUALITY_HD, FALLBACK_STRATEGY_STRICTLY_HIGHER
+        )
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo1)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_FHD)
+    }
+
+    @Test
+    fun select_fallbackStrictHigher_getNone() {
+        // Arrange.
+        // camera1 supports 1080P(FHD) and 480P(SD)
+        val qualitySelector = QualitySelector.of(
+            QUALITY_UHD, FALLBACK_STRATEGY_STRICTLY_HIGHER
+        )
+
+        // Act.
+        val quality = qualitySelector.select(cameraInfo1)
+
+        // Assert.
+        assertThat(quality).isEqualTo(QUALITY_NONE)
+    }
+}
diff --git a/camera/camera-video/src/test/java/androidx/camera/video/VideoCapabilitiesTest.kt b/camera/camera-video/src/test/java/androidx/camera/video/VideoCapabilitiesTest.kt
new file mode 100644
index 0000000..d08276e
--- /dev/null
+++ b/camera/camera-video/src/test/java/androidx/camera/video/VideoCapabilitiesTest.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2021 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.camera.video
+
+import android.os.Build
+import androidx.camera.testing.CamcorderProfileUtil
+import androidx.camera.testing.CamcorderProfileUtil.PROFILE_2160P
+import androidx.camera.testing.CamcorderProfileUtil.PROFILE_720P
+import androidx.camera.testing.fakes.FakeCamcorderProfileProvider
+import androidx.camera.testing.fakes.FakeCameraInfoInternal
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.annotation.Config
+import org.robolectric.annotation.internal.DoNotInstrument
+
+private val PROFILE_HIGH = CamcorderProfileUtil.asHighQuality(PROFILE_2160P)
+private val PROFILE_LOW = CamcorderProfileUtil.asLowQuality(PROFILE_720P)
+
+@RunWith(RobolectricTestRunner::class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+class VideoCapabilitiesTest {
+
+    private val cameraInfo = FakeCameraInfoInternal().apply {
+        camcorderProfileProvider = FakeCamcorderProfileProvider.Builder()
+            .addProfile(PROFILE_HIGH)
+            .addProfile(PROFILE_2160P)
+            .addProfile(PROFILE_720P)
+            .addProfile(PROFILE_LOW)
+            .build()
+    }
+
+    @Test
+    fun isQualitySupported() {
+        val videoCapabilities = VideoCapabilities.from(cameraInfo)
+        assertThat(videoCapabilities.isQualitySupported(QualitySelector.QUALITY_NONE)).isFalse()
+        assertThat(videoCapabilities.isQualitySupported(QualitySelector.QUALITY_HIGHEST)).isTrue()
+        assertThat(videoCapabilities.isQualitySupported(QualitySelector.QUALITY_LOWEST)).isTrue()
+        assertThat(videoCapabilities.isQualitySupported(QualitySelector.QUALITY_UHD)).isTrue()
+        assertThat(videoCapabilities.isQualitySupported(QualitySelector.QUALITY_FHD)).isFalse()
+        assertThat(videoCapabilities.isQualitySupported(QualitySelector.QUALITY_HD)).isTrue()
+        assertThat(videoCapabilities.isQualitySupported(QualitySelector.QUALITY_SD)).isFalse()
+    }
+
+    @Test
+    fun getProfile() {
+        val videoCapabilities = VideoCapabilities.from(cameraInfo)
+        assertThat(videoCapabilities.getProfile(QualitySelector.QUALITY_NONE)).isNull()
+        assertThat(videoCapabilities.getProfile(QualitySelector.QUALITY_HIGHEST))
+            .isEqualTo(PROFILE_2160P)
+        assertThat(videoCapabilities.getProfile(QualitySelector.QUALITY_LOWEST))
+            .isEqualTo(PROFILE_720P)
+        assertThat(videoCapabilities.getProfile(QualitySelector.QUALITY_UHD))
+            .isEqualTo(PROFILE_2160P)
+        assertThat(videoCapabilities.getProfile(QualitySelector.QUALITY_FHD)).isNull()
+        assertThat(videoCapabilities.getProfile(QualitySelector.QUALITY_HD))
+            .isEqualTo(PROFILE_720P)
+        assertThat(videoCapabilities.getProfile(QualitySelector.QUALITY_SD)).isNull()
+    }
+}
diff --git a/camera/camera-view/build.gradle b/camera/camera-view/build.gradle
index edb66a5..1ad6270 100644
--- a/camera/camera-view/build.gradle
+++ b/camera/camera-view/build.gradle
@@ -25,11 +25,13 @@
     id("kotlin-android")
 }
 
+apply(from: "dependencies.gradle")
+
 dependencies {
     implementation("androidx.appcompat:appcompat:1.1.0")
     api("androidx.lifecycle:lifecycle-common:2.0.0")
-    api(project(":camera:camera-core"))
-    implementation(project(path: ":camera:camera-lifecycle"))
+    api("androidx.camera:camera-core:${VIEW_ATOMIC_GROUP_PINNED_VER}")
+    implementation("androidx.camera:camera-lifecycle:${VIEW_ATOMIC_GROUP_PINNED_VER}")
     api("androidx.annotation:annotation:1.0.0")
     implementation(GUAVA_LISTENABLE_FUTURE)
     implementation("androidx.core:core:1.1.0")
@@ -44,9 +46,17 @@
     testImplementation(TRUTH)
     testImplementation(ANDROIDX_TEST_RULES)
     testImplementation(ANDROIDX_TEST_CORE)
-    testImplementation(project(":camera:camera-testing"))
+    testImplementation(project(":camera:camera-testing")) {
+        // Ensure camera-testing does not pull in camera-core project dependency which will
+        // override pinned dependency.
+        exclude(group:"androidx.camera", module:"camera-core")
+    }
 
-    androidTestImplementation(project(":camera:camera-testing"))
+    androidTestImplementation(project(":camera:camera-testing"))  {
+        // Ensure camera-testing does not pull in camera-core project dependency which will
+        // override pinned dependency.
+        exclude(group:"androidx.camera", module:"camera-core")
+    }
     androidTestImplementation(MOCKITO_CORE)
     androidTestImplementation(ESPRESSO_CORE)
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
@@ -56,7 +66,7 @@
     androidTestImplementation(ANDROIDX_TEST_UIAUTOMATOR)
     androidTestImplementation(KOTLIN_STDLIB)
     androidTestImplementation(TRUTH)
-    androidTestImplementation(project(":camera:camera-camera2"))
+    androidTestImplementation("androidx.camera:camera-camera2:${VIEW_ATOMIC_GROUP_PINNED_VER}")
     androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it's own MockMaker
     androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it's own MockMaker
 }
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt b/camera/camera-view/dependencies.gradle
similarity index 78%
copy from compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
copy to camera/camera-view/dependencies.gradle
index 7e01354..5795377 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
+++ b/camera/camera-view/dependencies.gradle
@@ -1,5 +1,3 @@
-// ktlint-disable filename
-
 /*
  * Copyright 2021 The Android Open Source Project
  *
@@ -16,6 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.compose.foundation
-
-internal actual typealias AtomicReference<V> = java.util.concurrent.atomic.AtomicReference<V>
\ No newline at end of file
+ext {
+    // camera-view temporarily pins same-group depenencies to RC/stable until beta
+    VIEW_ATOMIC_GROUP_PINNED_VER = "1.0.0-rc03"
+}
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/transform/CoordinateTransformDeviceTest.kt b/camera/camera-view/src/androidTest/java/androidx/camera/view/transform/CoordinateTransformDeviceTest.kt
index 5c5186f..84e21f7 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/transform/CoordinateTransformDeviceTest.kt
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/transform/CoordinateTransformDeviceTest.kt
@@ -35,12 +35,13 @@
     @Test(expected = IllegalArgumentException::class)
     public fun mismatchViewPort_throwsException() {
         // Arrange: create 2 imageProxy with mismatched viewport aspect ratio.
-        val source = ImageProxyTransform.Builder(
-            createFakeImageProxy(300, 400, Rect(0, 0, 300, 400))
-        ).build()
-        val target = ImageProxyTransform.Builder(
-            createFakeImageProxy(300, 400, Rect(0, 0, 200, 400))
-        ).build()
+        val imageProxyTransformFactory = ImageProxyTransformFactory.Builder().build()
+        val source = imageProxyTransformFactory.getOutputTransform(
+            createFakeImageProxy(300, 400, 0, Rect(0, 0, 300, 400))
+        )
+        val target = imageProxyTransformFactory.getOutputTransform(
+            createFakeImageProxy(300, 400, 0, Rect(0, 0, 200, 400))
+        )
 
         // Act: creating CoordinateTransform throws exception.
         CoordinateTransform(source, target)
@@ -49,9 +50,10 @@
     @Test
     public fun sameSourceAndTarget_getsIdentityMatrix() {
         // Arrange.
-        val imageProxy = ImageProxyTransform.Builder(
-            createFakeImageProxy(3, 4, Rect(0, 0, 3, 4))
-        ).build()
+        val imageProxyTransformFactory = ImageProxyTransformFactory.Builder().build()
+        val imageProxy = imageProxyTransformFactory.getOutputTransform(
+            createFakeImageProxy(3, 4, 0, Rect(0, 0, 3, 4))
+        )
 
         // Act: create a transform with the same source and target.
         val transform = CoordinateTransform(imageProxy, imageProxy)
@@ -68,12 +70,13 @@
     @Test
     public fun scaleImageProxy() {
         // Arrange: create 2 ImageProxy with the only difference being 10x scale.
-        val source = ImageProxyTransform.Builder(
-            createFakeImageProxy(3, 4, Rect(0, 0, 3, 4))
-        ).build()
-        val target = ImageProxyTransform.Builder(
-            createFakeImageProxy(30, 40, Rect(0, 0, 30, 40))
-        ).build()
+        val imageProxyTransformFactory = ImageProxyTransformFactory.Builder().build()
+        val source = imageProxyTransformFactory.getOutputTransform(
+            createFakeImageProxy(3, 4, 0, Rect(0, 0, 3, 4))
+        )
+        val target = imageProxyTransformFactory.getOutputTransform(
+            createFakeImageProxy(30, 40, 0, Rect(0, 0, 30, 40))
+        )
 
         // Act.
         val coordinateTransform = CoordinateTransform(source, target)
@@ -87,12 +90,14 @@
     @Test
     public fun scaleAndRotateImageProxy() {
         // Arrange: create 2 ImageProxy with different scale and rotation.
-        val source = ImageProxyTransform.Builder(
-            createFakeImageProxy(3, 4, Rect(0, 0, 3, 4))
-        ).setRotationDegrees(270).build()
-        val target = ImageProxyTransform.Builder(
-            createFakeImageProxy(30, 40, Rect(0, 0, 30, 40))
-        ).setRotationDegrees(90).build()
+        val imageProxyTransformFactory = ImageProxyTransformFactory.Builder()
+            .setUseRotationDegrees(true).build()
+        val source = imageProxyTransformFactory.getOutputTransform(
+            createFakeImageProxy(3, 4, 270, Rect(0, 0, 3, 4))
+        )
+        val target = imageProxyTransformFactory.getOutputTransform(
+            createFakeImageProxy(30, 40, 90, Rect(0, 0, 30, 40))
+        )
 
         // Act.
         val coordinateTransform = CoordinateTransform(source, target)
@@ -107,12 +112,14 @@
     public fun withViewPortWithoutCropRect() {
         // Arrange: create 2 ImageProxy that have crop rect, but the coordinates do not respect the
         // crop rect. (MLKit scenario).
-        val source = ImageProxyTransform.Builder(
-            createFakeImageProxy(16, 12, Rect(2, 2, 10, 8))
-        ).build()
-        val target = ImageProxyTransform.Builder(
-            createFakeImageProxy(16, 12, Rect(8, 6, 16, 12))
-        ).build()
+        val imageProxyTransformFactory = ImageProxyTransformFactory.Builder()
+            .setUseRotationDegrees(true).build()
+        val source = imageProxyTransformFactory.getOutputTransform(
+            createFakeImageProxy(16, 12, 0, Rect(2, 2, 10, 8))
+        )
+        val target = imageProxyTransformFactory.getOutputTransform(
+            createFakeImageProxy(16, 12, 0, Rect(8, 6, 16, 12))
+        )
 
         // Act.
         val coordinateTransform = CoordinateTransform(source, target)
@@ -127,14 +134,18 @@
     public fun withViewPortAndCropRect() {
         // Arrange: create 2 ImageProxy that have crop rect, and the coordinates respect the crop
         // rect.
-        val sourceCropRect = Rect(2, 2, 10, 8)
-        val source = ImageProxyTransform.Builder(createFakeImageProxy(16, 12, sourceCropRect))
-            .setCropRect(sourceCropRect).build()
-        val targetCropRect = Rect(8, 6, 16, 12)
-        val target = ImageProxyTransform
-            .Builder(createFakeImageProxy(16, 12, targetCropRect))
-            .setCropRect(targetCropRect)
-            .build()
+        val imageProxyTransformFactory = ImageProxyTransformFactory.Builder()
+            .setUseCropRect(true).build()
+        val source = imageProxyTransformFactory.getOutputTransform(
+            createFakeImageProxy(
+                16, 12, 0, Rect(2, 2, 10, 8)
+            )
+        )
+        val target = imageProxyTransformFactory.getOutputTransform(
+            createFakeImageProxy(
+                16, 12, 90, Rect(8, 6, 16, 12)
+            )
+        )
 
         // Act.
         val coordinateTransform = CoordinateTransform(source, target)
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/transform/ImageProxyTransformDeviceTest.kt b/camera/camera-view/src/androidTest/java/androidx/camera/view/transform/ImageProxyTransformFactoryTest.kt
similarity index 64%
rename from camera/camera-view/src/androidTest/java/androidx/camera/view/transform/ImageProxyTransformDeviceTest.kt
rename to camera/camera-view/src/androidTest/java/androidx/camera/view/transform/ImageProxyTransformFactoryTest.kt
index 43a84ec..dec0cd4 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/transform/ImageProxyTransformDeviceTest.kt
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/transform/ImageProxyTransformFactoryTest.kt
@@ -25,11 +25,11 @@
 import org.junit.runner.RunWith
 
 /**
- * Instrument tests for [ImageProxyTransform]
+ * Instrument tests for [ImageProxyTransformFactory]
  */
 @LargeTest
 @RunWith(AndroidJUnit4::class)
-public class ImageProxyTransformDeviceTest {
+public class ImageProxyTransformFactoryTest {
 
     @Test
     public fun rotateVerticesAndAlignToOrigin() {
@@ -37,7 +37,7 @@
         val vertices = floatArrayOf(1f, 2f, 4f, 2f, 4f, 6f, 1f, 6f)
 
         // Act.
-        val rotatedVertices = ImageProxyTransform.Builder.getRotatedVertices(vertices, 90)
+        val rotatedVertices = ImageProxyTransformFactory.getRotatedVertices(vertices, 90)
 
         // Assert: the rotated rect becomes 4x3 and aligned to the origin: (0,0) - (4,3)
         assertThat(rotatedVertices).isEqualTo(floatArrayOf(4f, 0f, 4f, 3f, 0f, 3f, 0f, 0f))
@@ -46,8 +46,9 @@
     @Test
     public fun withoutRotationOrCropRect_scaled() {
         // Arrange: a 3x4 rect.
-        val imageProxy = createFakeImageProxy(3, 4, Rect(0, 0, 3, 4))
-        val transform = ImageProxyTransform.Builder(imageProxy).build()
+        val imageProxy = createFakeImageProxy(3, 4, 90, Rect(0, 0, 3, 4))
+        val imageProxyTransformFactory = ImageProxyTransformFactory.Builder().build()
+        val transform = imageProxyTransformFactory.getOutputTransform(imageProxy)
 
         // Assert: The bottom-right of the normalized space (1, 1) mapped to (3, 4)
         val point = floatArrayOf(1f, 1f)
@@ -58,8 +59,12 @@
     @Test
     public fun withRotation_scaledAndRotated() {
         // Arrange: a 3x4 rect with 90° rotation.
-        val imageProxy = createFakeImageProxy(3, 4, Rect(0, 0, 3, 4))
-        val transform = ImageProxyTransform.Builder(imageProxy).setRotationDegrees(90).build()
+        // (the MLKit scenario).
+        val imageProxyTransformFactory = ImageProxyTransformFactory.Builder()
+            .setUseRotationDegrees(true)
+            .build()
+        val imageProxy = createFakeImageProxy(3, 4, 90, Rect(0, 0, 3, 4))
+        val transform = imageProxyTransformFactory.getOutputTransform(imageProxy)
 
         // Assert: The bottom-right of the normalized space (1, 1) mapped to (0, 3)
         val point = floatArrayOf(1f, 1f)
@@ -70,9 +75,11 @@
     @Test
     public fun withCropRect_cropped() {
         // Arrange: a 16x12 rect with a 8x12 crop rect (8,0)-(16,12).
-        val cropRect = Rect(8, 0, 16, 12)
-        val imageProxy = createFakeImageProxy(16, 12, cropRect)
-        val transform = ImageProxyTransform.Builder(imageProxy).setCropRect(cropRect).build()
+        val imageProxyTransformFactory = ImageProxyTransformFactory.Builder()
+            .setUseCropRect(true)
+            .build()
+        val imageProxy = createFakeImageProxy(16, 12, 90, Rect(8, 0, 16, 12))
+        val transform = imageProxyTransformFactory.getOutputTransform(imageProxy)
 
         // Assert: the center of the normalized space (0.5, 0.5) mapped to the center of the crop
         // rect (4,6).
@@ -82,29 +89,14 @@
     }
 
     @Test
-    public fun withIgnoredCropRect() {
-        // The ImageProxy has crop rect which is the viewport, but the user chooses to ignore it
-        // (the MLKit scenario).
-        // Arrange: a 16x12 rect with a 8x12 crop rect (8,0)-(16,12).
-        val imageProxy = createFakeImageProxy(16, 12, Rect(8, 0, 16, 12))
-        val transform = ImageProxyTransform.Builder(imageProxy).build()
-
-        // Assert: the center of the normalized space (0.5, 0.5) mapped to the center of the crop
-        // rect, but the coordinate system is based on the full buffer.
-        val point = floatArrayOf(.5f, .5f)
-        transform.matrix.mapPoints(point)
-        assertThat(point).isEqualTo(floatArrayOf(12f, 6f))
-    }
-
-    @Test
     public fun rotationAndCrop() {
         // Arrange: crop rect with rotation.
-        val cropRect = Rect(8, 0, 16, 12)
-        val imageProxy = createFakeImageProxy(16, 12, cropRect)
-        val transform = ImageProxyTransform.Builder(imageProxy)
-            .setCropRect(cropRect)
-            .setRotationDegrees(90)
+        val imageProxyTransformFactory = ImageProxyTransformFactory.Builder()
+            .setUseCropRect(true)
+            .setUseRotationDegrees(true)
             .build()
+        val imageProxy = createFakeImageProxy(16, 12, 90, Rect(8, 0, 16, 12))
+        val transform = imageProxyTransformFactory.getOutputTransform(imageProxy)
 
         // Assert: the center of the normalized space (0.5, 0.5) mapped to the center of the
         // rotated crop rect (4,6).
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/transform/TransformTestUtils.java b/camera/camera-view/src/androidTest/java/androidx/camera/view/transform/TransformTestUtils.java
index 8e3e294..1843b7a 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/transform/TransformTestUtils.java
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/transform/TransformTestUtils.java
@@ -28,8 +28,11 @@
  */
 class TransformTestUtils {
 
-    static ImageProxy createFakeImageProxy(int width, int height, Rect cropRect) {
-        FakeImageProxy imageProxy = new FakeImageProxy(new FakeImageInfo());
+    static ImageProxy createFakeImageProxy(int width, int height,
+            int rotationDegrees, Rect cropRect) {
+        FakeImageInfo fakeImageInfo = new FakeImageInfo();
+        fakeImageInfo.setRotationDegrees(rotationDegrees);
+        FakeImageProxy imageProxy = new FakeImageProxy(fakeImageInfo);
         imageProxy.setHeight(height);
         imageProxy.setWidth(width);
         imageProxy.setCropRect(cropRect);
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/PreviewTransformation.java b/camera/camera-view/src/main/java/androidx/camera/view/PreviewTransformation.java
index 9024bb2..9291c93 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/PreviewTransformation.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/PreviewTransformation.java
@@ -54,6 +54,8 @@
 import androidx.camera.core.Logger;
 import androidx.camera.core.SurfaceRequest;
 import androidx.camera.core.ViewPort;
+import androidx.camera.view.internal.compat.quirk.DeviceQuirks;
+import androidx.camera.view.internal.compat.quirk.PreviewStretchedQuirk;
 import androidx.core.util.Preconditions;
 
 /**
@@ -248,7 +250,7 @@
                 previewViewCropRectVertices, mPreviewRotationDegrees);
 
         // Get the source of the mapping, the vertices of the crop rect in Surface.
-        float[] surfaceCropRectVertices = rectToVertices(new RectF(mSurfaceCropRect));
+        float[] surfaceCropRectVertices = getSurfaceCropRectVertices();
 
         // Map source to target.
         matrix.setPolyToPoly(surfaceCropRectVertices, 0, rotatedPreviewViewCropRectVertices, 0, 4);
@@ -275,6 +277,25 @@
     }
 
     /**
+     * Gets the vertices of the crop rect in Surface.
+     */
+    private float[] getSurfaceCropRectVertices() {
+        RectF cropRectF = new RectF(mSurfaceCropRect);
+        PreviewStretchedQuirk quirk = DeviceQuirks.get(PreviewStretchedQuirk.class);
+        if (quirk != null) {
+            // Correct crop rect if the device has a quirk.
+            Matrix correction = new Matrix();
+            correction.setScale(
+                    quirk.getCropRectScaleX(),
+                    quirk.getCropRectScaleY(),
+                    mSurfaceCropRect.centerX(),
+                    mSurfaceCropRect.centerY());
+            correction.mapRect(cropRectF);
+        }
+        return rectToVertices(cropRectF);
+    }
+
+    /**
      * Gets the crop rect in {@link PreviewView} coordinates for the case where crop rect's aspect
      * ratio doesn't match {@link PreviewView}'s aspect ratio.
      *
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/TransformUtils.java b/camera/camera-view/src/main/java/androidx/camera/view/TransformUtils.java
index 37ccf4f..4e06287 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/TransformUtils.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/TransformUtils.java
@@ -16,6 +16,7 @@
 
 package androidx.camera.view;
 
+import android.graphics.Rect;
 import android.graphics.RectF;
 import android.util.Size;
 import android.view.Surface;
@@ -74,6 +75,16 @@
     }
 
     /**
+     * Gets the size of the {@link Rect}.
+     * @param rect
+     * @return
+     */
+    @NonNull
+    public static Size rectToSize(@NonNull Rect rect) {
+        return new Size(rect.width(), rect.height());
+    }
+
+    /**
      * Converts an array of vertices to a {@link RectF}.
      */
     @NonNull
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/DeviceQuirks.java b/camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/DeviceQuirks.java
new file mode 100644
index 0000000..3ae984d
--- /dev/null
+++ b/camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/DeviceQuirks.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021 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.camera.view.internal.compat.quirk;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.camera.core.impl.Quirk;
+import androidx.camera.core.impl.Quirks;
+
+/**
+ * Provider of device specific quirks for the view module, which are used for device specific
+ * workarounds.
+ * <p>
+ * Device specific quirks depend on device properties, including the manufacturer
+ * ({@link android.os.Build#MANUFACTURER}), model ({@link android.os.Build#MODEL}) and OS
+ * level ({@link android.os.Build.VERSION#SDK_INT}).
+ * <p>
+ * Device specific quirks are lazily loaded, i.e. They are loaded the first time they're needed.
+ */
+public class DeviceQuirks {
+
+    @NonNull
+    private static final Quirks QUIRKS;
+
+    static {
+        QUIRKS = new Quirks(DeviceQuirksLoader.loadQuirks());
+    }
+
+    private DeviceQuirks() {
+    }
+
+    /**
+     * Retrieves a specific device {@link Quirk} instance given its type.
+     *
+     * @param quirkClass The type of device quirk to retrieve.
+     * @return A device {@link Quirk} instance of the provided type, or {@code null} if it isn't
+     * found.
+     */
+    @Nullable
+    public static <T extends Quirk> T get(@NonNull final Class<T> quirkClass) {
+        return QUIRKS.get(quirkClass);
+    }
+}
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/DeviceQuirksLoader.java b/camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/DeviceQuirksLoader.java
new file mode 100644
index 0000000..65e35b3
--- /dev/null
+++ b/camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/DeviceQuirksLoader.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2021 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.camera.view.internal.compat.quirk;
+
+import androidx.annotation.NonNull;
+import androidx.camera.core.impl.Quirk;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Loads all device specific quirks required for the current device
+ */
+public class DeviceQuirksLoader {
+
+    private DeviceQuirksLoader() {
+    }
+
+    /**
+     * Goes through all defined device-specific quirks, and returns those that should be loaded
+     * on the current device.
+     */
+    @NonNull
+    static List<Quirk> loadQuirks() {
+        final List<Quirk> quirks = new ArrayList<>();
+
+        // Load all device specific quirks
+        if (PreviewStretchedQuirk.load()) {
+            quirks.add(new PreviewStretchedQuirk());
+        }
+
+        return quirks;
+    }
+}
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/PreviewStretchedQuirk.java b/camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/PreviewStretchedQuirk.java
new file mode 100644
index 0000000..fd274fa
--- /dev/null
+++ b/camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/PreviewStretchedQuirk.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2021 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.camera.view.internal.compat.quirk;
+
+import android.os.Build;
+
+import androidx.camera.core.impl.Quirk;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * A quirk where the preview buffer is stretched.
+ *
+ * <p> This is similar to the SamsungPreviewTargetAspectRatioQuirk in camera-camera2 artifact.
+ * The difference is, the other quirk can be fixed by choosing a different resolution,
+ * while for this one the preview is always stretched no matter what resolution is selected.
+ */
+public class PreviewStretchedQuirk implements Quirk {
+
+    private static final String SAMSUNG_A3_2017 = "A3Y17LTE"; // b/180121821
+
+    private static final List<String> KNOWN_AFFECTED_DEVICES = Arrays.asList(SAMSUNG_A3_2017);
+
+    static boolean load() {
+        return KNOWN_AFFECTED_DEVICES.contains(Build.DEVICE.toUpperCase());
+    }
+
+    /**
+     * The mount that the crop rect needs to be scaled in x.
+     */
+    public float getCropRectScaleX() {
+        if (SAMSUNG_A3_2017.equals(Build.DEVICE.toUpperCase())) {
+            // For Samsung A3 2017, the symptom seems to be that the preview's FOV is always 1/3
+            // wider than it's supposed to be. For example, if the preview Surface is 800x600, it's
+            // actually has a FOV of 1066x600, but stretched to fit the 800x600 buffer. To correct
+            // the preview, we need to crop out the extra 25% FOV.
+            return 0.75f;
+        }
+        // No scale.
+        return 1;
+    }
+
+    /**
+     * The mount that the crop rect needs to be scaled in y.
+     */
+    public float getCropRectScaleY() {
+        // No scale.
+        return 1;
+    }
+}
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt b/camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/package-info.java
similarity index 78%
copy from compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
copy to camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/package-info.java
index 7e01354..435388f 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
+++ b/camera/camera-view/src/main/java/androidx/camera/view/internal/compat/quirk/package-info.java
@@ -1,5 +1,3 @@
-// ktlint-disable filename
-
 /*
  * Copyright 2021 The Android Open Source Project
  *
@@ -16,6 +14,10 @@
  * limitations under the License.
  */
 
-package androidx.compose.foundation
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+package androidx.camera.view.internal.compat.quirk;
 
-internal actual typealias AtomicReference<V> = java.util.concurrent.atomic.AtomicReference<V>
\ No newline at end of file
+import androidx.annotation.RestrictTo;
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/transform/ImageProxyTransform.java b/camera/camera-view/src/main/java/androidx/camera/view/transform/ImageProxyTransform.java
deleted file mode 100644
index 0be0ab7..0000000
--- a/camera/camera-view/src/main/java/androidx/camera/view/transform/ImageProxyTransform.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright 2021 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.camera.view.transform;
-
-import static androidx.camera.view.TransformUtils.min;
-import static androidx.camera.view.TransformUtils.rectToVertices;
-
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.util.Size;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-import androidx.camera.core.ImageAnalysis;
-import androidx.camera.core.ImageCapture;
-import androidx.camera.core.ImageProxy;
-import androidx.camera.view.TransformExperimental;
-
-/**
- * The transform of a {@link ImageProxy}.
- *
- * <p> {@link ImageProxy} can be the output of {@link ImageAnalysis} or in-memory
- * {@link ImageCapture}. This class represents the transform applied to the raw buffer of a
- * {@link ImageProxy}.
- *
- * TODO(b/179827713): unhide this class once all transform utils are done.
- *
- * @hide
- */
-@TransformExperimental
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class ImageProxyTransform extends OutputTransform {
-
-    ImageProxyTransform(@NonNull Matrix matrix, @NonNull Rect viewPortRect) {
-        super(matrix, new Size(viewPortRect.width(), viewPortRect.height()));
-    }
-
-    /**
-     * Builder of {@link ImageProxyTransform}.
-     */
-    public static class Builder extends OutputTransform.Builder {
-
-        private final Rect mViewPortRect;
-        private int mRotationDegrees;
-        private Rect mCropRect;
-
-        /**
-         * @param imageProxy the {@link ImageProxy} that the transform applies to.
-         */
-        public Builder(@NonNull ImageProxy imageProxy) {
-            mViewPortRect = imageProxy.getCropRect();
-            mCropRect = new Rect(0, 0, imageProxy.getWidth(), imageProxy.getHeight());
-            mRotationDegrees = 0;
-        }
-
-        /**
-         * Sets the crop rect.
-         *
-         * <p> Only sets this value if the coordinates to be transformed respect the crop
-         * rect, for example, the origin of the coordinates system is the (top, left) of the crop
-         * rect.
-         */
-        @NonNull
-        public Builder setCropRect(@NonNull Rect cropRect) {
-            mCropRect = cropRect;
-            return this;
-        }
-
-        /**
-         * Sets the rotation degrees.
-         *
-         * <p> Only sets this value if the coordinates to be transformed respect the rotation
-         * degrees.
-         */
-        @NonNull
-        public Builder setRotationDegrees(int rotationDegrees) {
-            mRotationDegrees = rotationDegrees;
-            return this;
-        }
-
-        // TODO(b/179827713): Support mirroring.
-
-        /**
-         * Builds the {@link ImageProxyTransform} object.
-         */
-        @NonNull
-        public ImageProxyTransform build() {
-            Matrix matrix = new Matrix();
-
-            // Map the viewport to output.
-            float[] cropRectVertices = rectToVertices(new RectF(mCropRect));
-            float[] outputVertices = getRotatedVertices(cropRectVertices, mRotationDegrees);
-            matrix.setPolyToPoly(cropRectVertices, 0, outputVertices, 0, 4);
-
-            // Map the normalized space to viewport.
-            matrix.preConcat(getNormalizedToBuffer(mViewPortRect));
-
-            return new ImageProxyTransform(matrix, mViewPortRect);
-        }
-
-        /**
-         * Rotates the crop rect with given degrees.
-         *
-         * <p> Rotate the vertices, then align the top left corner to (0, 0).
-         *
-         * <pre>
-         *         (0, 0)                          (0, 0)
-         * Before  +-----Surface-----+     After:  a--------------------b
-         *         |                 |             |          ^         |
-         *         |  d-crop rect-a  |             |          |         |
-         *         |  |           |  |             d--------------------c
-         *         |  |           |  |
-         *         |  |    -->    |  |    Rotation:        <-----+
-         *         |  |           |  |                       270°|
-         *         |  |           |  |                           |
-         *         |  c-----------b  |
-         *         +-----------------+
-         * </pre>
-         */
-        static float[] getRotatedVertices(float[] cropRectVertices, int rotationDegrees) {
-            // Rotate the vertices. The pivot point doesn't matter since we are gong to align it to
-            // the origin afterwards.
-            float[] vertices = cropRectVertices.clone();
-            Matrix matrix = new Matrix();
-            matrix.setRotate(rotationDegrees);
-            matrix.mapPoints(vertices);
-
-            // Align the rotated vertices to origin. The transformed output always starts at (0, 0).
-            float left = min(vertices[0], vertices[2], vertices[4], vertices[6]);
-            float top = min(vertices[1], vertices[3], vertices[5], vertices[7]);
-            for (int i = 0; i < vertices.length; i += 2) {
-                vertices[i] -= left;
-                vertices[i + 1] -= top;
-            }
-            return vertices;
-        }
-    }
-}
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/transform/ImageProxyTransformFactory.java b/camera/camera-view/src/main/java/androidx/camera/view/transform/ImageProxyTransformFactory.java
new file mode 100644
index 0000000..06e422a
--- /dev/null
+++ b/camera/camera-view/src/main/java/androidx/camera/view/transform/ImageProxyTransformFactory.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2021 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.camera.view.transform;
+
+import static androidx.camera.view.TransformUtils.min;
+import static androidx.camera.view.TransformUtils.rectToSize;
+import static androidx.camera.view.TransformUtils.rectToVertices;
+import static androidx.camera.view.transform.OutputTransform.getNormalizedToBuffer;
+
+import android.graphics.Matrix;
+import android.graphics.RectF;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.camera.core.ImageAnalysis;
+import androidx.camera.core.ImageCapture;
+import androidx.camera.core.ImageProxy;
+import androidx.camera.view.TransformExperimental;
+
+/**
+ * Factory for extracting transform info from {@link ImageProxy}.
+ *
+ * TODO(b/179827713): unhide this class once all transform utils are done.
+ *
+ * @hide
+ */
+@TransformExperimental
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class ImageProxyTransformFactory {
+
+    private final boolean mUseCropRect;
+    private final boolean mUseRotationDegrees;
+
+    ImageProxyTransformFactory(boolean useCropRect, boolean useRotationDegrees) {
+        mUseCropRect = useCropRect;
+        mUseRotationDegrees = useRotationDegrees;
+    }
+
+    /**
+     * Extracts the transform from the given {@link ImageProxy}.
+     *
+     * <p> This method returns a {@link OutputTransform} that represents the
+     * transform applied to the buffer of a {@link ImageProxy} based on factory settings.  An
+     * {@link ImageProxy} can be the output of {@link ImageAnalysis} or in-memory
+     * {@link ImageCapture}.
+     */
+    @NonNull
+    public OutputTransform getOutputTransform(@NonNull ImageProxy imageProxy) {
+        Matrix matrix = new Matrix();
+
+        // Map the viewport to output.
+        float[] cropRectVertices = rectToVertices(getCropRect(imageProxy));
+        float[] outputVertices = getRotatedVertices(cropRectVertices,
+                getRotationDegrees(imageProxy));
+        matrix.setPolyToPoly(cropRectVertices, 0, outputVertices, 0, 4);
+
+        // Map the normalized space to viewport.
+        matrix.preConcat(getNormalizedToBuffer(imageProxy.getCropRect()));
+
+        return new OutputTransform(matrix, rectToSize(imageProxy.getCropRect()));
+    }
+
+    /**
+     * Gets the crop rect based on factory settings.
+     */
+    private RectF getCropRect(@NonNull ImageProxy imageProxy) {
+        if (mUseCropRect) {
+            return new RectF(imageProxy.getCropRect());
+        }
+        // The default crop rect is the full buffer.
+        return new RectF(0, 0, imageProxy.getWidth(), imageProxy.getHeight());
+    }
+
+    /**
+     * Gets the rotation degrees based on factory settings.
+     */
+    private int getRotationDegrees(@NonNull ImageProxy imageProxy) {
+        if (mUseRotationDegrees) {
+            return imageProxy.getImageInfo().getRotationDegrees();
+        }
+        // The default is no rotation.
+        return 0;
+    }
+
+    /**
+     * Rotates the crop rect with given degrees.
+     *
+     * <p> Rotate the vertices, then align the top left corner to (0, 0).
+     *
+     * <pre>
+     *         (0, 0)                          (0, 0)
+     * Before  +-----Surface-----+     After:  a--------------------b
+     *         |                 |             |          ^         |
+     *         |  d-crop rect-a  |             |          |         |
+     *         |  |           |  |             d--------------------c
+     *         |  |           |  |
+     *         |  |    -->    |  |    Rotation:        <-----+
+     *         |  |           |  |                       270°|
+     *         |  |           |  |                           |
+     *         |  c-----------b  |
+     *         +-----------------+
+     * </pre>
+     */
+    static float[] getRotatedVertices(float[] cropRectVertices, int rotationDegrees) {
+        // Rotate the vertices. The pivot point doesn't matter since we are gong to align it to
+        // the origin afterwards.
+        float[] vertices = cropRectVertices.clone();
+        Matrix matrix = new Matrix();
+        matrix.setRotate(rotationDegrees);
+        matrix.mapPoints(vertices);
+
+        // Align the rotated vertices to origin. The transformed output always starts at (0, 0).
+        float left = min(vertices[0], vertices[2], vertices[4], vertices[6]);
+        float top = min(vertices[1], vertices[3], vertices[5], vertices[7]);
+        for (int i = 0; i < vertices.length; i += 2) {
+            vertices[i] -= left;
+            vertices[i + 1] -= top;
+        }
+        return vertices;
+    }
+
+    /**
+     * Builder of {@link ImageProxyTransformFactory}.
+     */
+    public static class Builder {
+
+        private boolean mUseCropRect = false;
+        private boolean mUseRotationDegrees = false;
+
+        /**
+         * Whether to use the crop rect of the {@link ImageProxy}.
+         *
+         * <p> By default, the value is false and the factory uses the {@link ImageProxy}'s
+         * entire buffer. Only set this value if the coordinates to be transformed respect the
+         * crop rect. For example, top-left corner of the crop rect is (0, 0).
+         */
+        @NonNull
+        public Builder setUseCropRect(boolean useCropRect) {
+            mUseCropRect = useCropRect;
+            return this;
+        }
+
+        /**
+         * Whether to use the rotation degrees of the {@link ImageProxy}.
+         *
+         * <p> By default, the value is false and the factory uses a rotation degree of 0. Only
+         * set this value if the coordinates to be transformed respect the rotation degrees. For
+         * example, if rotation is 90°, (0, 0) should map to (0, height) on the buffer.
+         */
+        @NonNull
+        public Builder setUseRotationDegrees(boolean useRotationDegrees) {
+            mUseRotationDegrees = useRotationDegrees;
+            return this;
+        }
+
+        // TODO(b/179827713): Add support for mirroring.
+
+        /**
+         * Builds the {@link ImageProxyTransformFactory} object.
+         */
+        @NonNull
+        public ImageProxyTransformFactory build() {
+            return new ImageProxyTransformFactory(mUseCropRect, mUseRotationDegrees);
+        }
+    }
+}
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/transform/OutputTransform.java b/camera/camera-view/src/main/java/androidx/camera/view/transform/OutputTransform.java
index cc31198..c931b8f 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/transform/OutputTransform.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/transform/OutputTransform.java
@@ -39,7 +39,10 @@
  */
 @TransformExperimental
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public abstract class OutputTransform {
+public class OutputTransform {
+
+    // Normalized space that maps to the viewport rect.
+    private static final RectF NORMALIZED_RECT = new RectF(0, 0, 1, 1);
 
     @NonNull
     final Matrix mMatrix;
@@ -73,27 +76,18 @@
         return mViewPortSize;
     }
 
+    @NonNull
+    static Matrix getNormalizedToBuffer(@NonNull Rect viewPortRect) {
+        return getNormalizedToBuffer(new RectF(viewPortRect));
+    }
+
     /**
-     * Abstract builder of {@link OutputTransform} that provides shared functionalities.
+     * Gets the transform from a normalized space (0, 0) - (1, 1) to viewport rect.
      */
-    static class Builder {
-
-        // Normalized space that maps to the viewport rect.
-        private static final RectF NORMALIZED_RECT = new RectF(0, 0, 1, 1);
-
-        @NonNull
-        Matrix getNormalizedToBuffer(@NonNull Rect viewPortRect) {
-            return getNormalizedToBuffer(new RectF(viewPortRect));
-        }
-
-        /**
-         * Gets the transform from a normalized space (0, 0) - (1, 1) to viewport rect.
-         */
-        @NonNull
-        Matrix getNormalizedToBuffer(@NonNull RectF viewPortRect) {
-            Matrix normalizedToBuffer = new Matrix();
-            normalizedToBuffer.setRectToRect(NORMALIZED_RECT, viewPortRect, Matrix.ScaleToFit.FILL);
-            return normalizedToBuffer;
-        }
+    @NonNull
+    static Matrix getNormalizedToBuffer(@NonNull RectF viewPortRect) {
+        Matrix normalizedToBuffer = new Matrix();
+        normalizedToBuffer.setRectToRect(NORMALIZED_RECT, viewPortRect, Matrix.ScaleToFit.FILL);
+        return normalizedToBuffer;
     }
 }
diff --git a/camera/camera-view/src/test/java/androidx/camera/view/internal/compat/quirk/PreviewStretchedQuirkTest.java b/camera/camera-view/src/test/java/androidx/camera/view/internal/compat/quirk/PreviewStretchedQuirkTest.java
new file mode 100644
index 0000000..0b42944
--- /dev/null
+++ b/camera/camera-view/src/test/java/androidx/camera/view/internal/compat/quirk/PreviewStretchedQuirkTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2021 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.camera.view.internal.compat.quirk;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Build;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.internal.DoNotInstrument;
+import org.robolectric.util.ReflectionHelpers;
+
+/**
+ * Unit tests for {@link PreviewStretchedQuirk}.
+ */
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+@Config(minSdk = Build.VERSION_CODES.LOLLIPOP)
+public class PreviewStretchedQuirkTest {
+
+    @Test
+    public void quirkExistsOnSamsungA3() {
+        // Arrange.
+        ReflectionHelpers.setStaticField(Build.class, "DEVICE", "A3Y17LTE");
+
+        // Act.
+        final PreviewStretchedQuirk quirk = DeviceQuirks.get(PreviewStretchedQuirk.class);
+
+        // Assert.
+        assertThat(quirk).isNotNull();
+        assertThat(quirk.getCropRectScaleX()).isEqualTo(0.75F);
+        assertThat(quirk.getCropRectScaleY()).isEqualTo(1F);
+    }
+}
diff --git a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraUtils.kt b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraUtils.kt
index 6bcc17c..9c5e7f9 100644
--- a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraUtils.kt
+++ b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraUtils.kt
@@ -75,8 +75,9 @@
     val manager = activity.getSystemService(AppCompatActivity.CAMERA_SERVICE) as CameraManager
     try {
         val numCameras = manager.cameraIdList.size
-
         for (cameraId in manager.cameraIdList) {
+            var cameraParamsValid = true
+
             val tempCameraParams = CameraParams().apply {
 
                 val cameraChars = manager.getCameraCharacteristics(cameraId)
@@ -84,6 +85,17 @@
                     cameraChars.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)
                         ?: IntArray(0)
 
+                // Check supported format.
+                val map = cameraChars.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
+                if (map == null || map.isOutputSupportedFor(ImageFormat.JPEG) == false) {
+                    cameraParamsValid = false
+                    logd(
+                        "Null streamConfigurationMap or not supporting JPEG output format " +
+                            "in cameraId:" + cameraId
+                    )
+                    return@apply
+                }
+
                 // Multi-camera
                 for (capability in cameraCapabilities) {
                     if (capability ==
@@ -178,27 +190,29 @@
                     physicalCameras = cameraChars.physicalCameraIds
                 }
 
-                // Get Camera2 and CameraX image capture sizes
-                val map =
-                    characteristics?.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
-                if (map != null) {
-                    cam2MaxSize = Collections.max(
-                        Arrays.asList(*map.getOutputSizes(ImageFormat.JPEG)),
-                        CompareSizesByArea()
-                    )
-                    cam2MinSize = Collections.min(
-                        Arrays.asList(*map.getOutputSizes(ImageFormat.JPEG)),
-                        CompareSizesByArea()
-                    )
+                // Get Camera2 and CameraX image capture sizes.
+                cam2MaxSize = Collections.max(
+                    Arrays.asList(*map.getOutputSizes(ImageFormat.JPEG)),
+                    CompareSizesByArea()
+                )
 
-                    // Use minimum image size for preview
-                    previewSurfaceView?.holder?.setFixedSize(cam2MinSize.width, cam2MinSize.height)
-                }
+                cam2MinSize = Collections.min(
+                    Arrays.asList(*map.getOutputSizes(ImageFormat.JPEG)),
+                    CompareSizesByArea()
+                )
+
+                // Use minimum image size for preview
+                previewSurfaceView?.holder?.setFixedSize(cam2MinSize.width, cam2MinSize.height)
 
                 setupImageReader(activity, this, TestConfig())
             }
 
-            cameraParams.put(cameraId, tempCameraParams)
+            if (cameraParamsValid == false) {
+                logd("Don't put Camera " + cameraId + "of " + numCameras)
+                continue
+            } else {
+                cameraParams.put(cameraId, tempCameraParams)
+            }
         } // For all camera devices
     } catch (accessError: CameraAccessException) {
         accessError.printStackTrace()
diff --git a/camera/integration-tests/viewtestapp/build.gradle b/camera/integration-tests/viewtestapp/build.gradle
index 21c0089..0a85291 100644
--- a/camera/integration-tests/viewtestapp/build.gradle
+++ b/camera/integration-tests/viewtestapp/build.gradle
@@ -23,6 +23,8 @@
     id("kotlin-android")
 }
 
+apply(from: "../../camera-view/dependencies.gradle")
+
 android {
     defaultConfig {
         applicationId "androidx.camera.integration.view"
@@ -51,8 +53,8 @@
 
 dependencies {
     // Internal library
-    implementation(project(":camera:camera-camera2"))
-    implementation(project(":camera:camera-lifecycle"))
+    implementation("androidx.camera:camera-camera2:${VIEW_ATOMIC_GROUP_PINNED_VER}")
+    implementation("androidx.camera:camera-lifecycle:${VIEW_ATOMIC_GROUP_PINNED_VER}")
     implementation(project(":lifecycle:lifecycle-runtime"))
     implementation(project(":camera:camera-view"))
     implementation(GUAVA_ANDROID)
diff --git a/car/app/app-testing/api/current.txt b/car/app/app-testing/api/current.txt
index 6637757..126bce5 100644
--- a/car/app/app-testing/api/current.txt
+++ b/car/app/app-testing/api/current.txt
@@ -25,11 +25,12 @@
     method public static androidx.car.app.testing.SessionController of(androidx.car.app.Session, androidx.car.app.testing.TestCarContext);
     method public androidx.car.app.testing.SessionController pause();
     method public androidx.car.app.testing.SessionController resume();
+    method public androidx.car.app.testing.SessionController start();
     method public androidx.car.app.testing.SessionController stop();
   }
 
   public class TestAppManager extends androidx.car.app.AppManager {
-    method public androidx.car.app.SurfaceCallback? getSurfaceListener();
+    method public androidx.car.app.SurfaceCallback? getSurfaceCallback();
     method public java.util.List<android.util.Pair<androidx.car.app.Screen!,androidx.car.app.model.Template!>!> getTemplatesReturned();
     method public java.util.List<java.lang.CharSequence!> getToastsShown();
     method public void reset();
diff --git a/car/app/app-testing/api/public_plus_experimental_current.txt b/car/app/app-testing/api/public_plus_experimental_current.txt
index 6637757..126bce5 100644
--- a/car/app/app-testing/api/public_plus_experimental_current.txt
+++ b/car/app/app-testing/api/public_plus_experimental_current.txt
@@ -25,11 +25,12 @@
     method public static androidx.car.app.testing.SessionController of(androidx.car.app.Session, androidx.car.app.testing.TestCarContext);
     method public androidx.car.app.testing.SessionController pause();
     method public androidx.car.app.testing.SessionController resume();
+    method public androidx.car.app.testing.SessionController start();
     method public androidx.car.app.testing.SessionController stop();
   }
 
   public class TestAppManager extends androidx.car.app.AppManager {
-    method public androidx.car.app.SurfaceCallback? getSurfaceListener();
+    method public androidx.car.app.SurfaceCallback? getSurfaceCallback();
     method public java.util.List<android.util.Pair<androidx.car.app.Screen!,androidx.car.app.model.Template!>!> getTemplatesReturned();
     method public java.util.List<java.lang.CharSequence!> getToastsShown();
     method public void reset();
diff --git a/car/app/app-testing/api/restricted_current.txt b/car/app/app-testing/api/restricted_current.txt
index 6637757..126bce5 100644
--- a/car/app/app-testing/api/restricted_current.txt
+++ b/car/app/app-testing/api/restricted_current.txt
@@ -25,11 +25,12 @@
     method public static androidx.car.app.testing.SessionController of(androidx.car.app.Session, androidx.car.app.testing.TestCarContext);
     method public androidx.car.app.testing.SessionController pause();
     method public androidx.car.app.testing.SessionController resume();
+    method public androidx.car.app.testing.SessionController start();
     method public androidx.car.app.testing.SessionController stop();
   }
 
   public class TestAppManager extends androidx.car.app.AppManager {
-    method public androidx.car.app.SurfaceCallback? getSurfaceListener();
+    method public androidx.car.app.SurfaceCallback? getSurfaceCallback();
     method public java.util.List<android.util.Pair<androidx.car.app.Screen!,androidx.car.app.model.Template!>!> getTemplatesReturned();
     method public java.util.List<java.lang.CharSequence!> getToastsShown();
     method public void reset();
diff --git a/car/app/app-testing/build.gradle b/car/app/app-testing/build.gradle
index 369bfc1..69dfbaa 100644
--- a/car/app/app-testing/build.gradle
+++ b/car/app/app-testing/build.gradle
@@ -18,7 +18,13 @@
 import androidx.build.Publish
 import androidx.build.LibraryVersions
 
+import static androidx.build.dependencies.DependenciesKt.ANDROIDX_TEST_CORE
+import static androidx.build.dependencies.DependenciesKt.ANDROIDX_TEST_RUNNER
+import static androidx.build.dependencies.DependenciesKt.JUNIT
+import static androidx.build.dependencies.DependenciesKt.MOCKITO_CORE
 import static androidx.build.dependencies.DependenciesKt.NULLAWAY
+import static androidx.build.dependencies.DependenciesKt.ROBOLECTRIC
+import static androidx.build.dependencies.DependenciesKt.TRUTH
 
 plugins {
     id("AndroidXPlugin")
@@ -31,6 +37,14 @@
     implementation 'androidx.annotation:annotation:1.1.0'
     implementation project(path: ':lifecycle:lifecycle-runtime')
 
+    testImplementation("junit:junit:4.13")
+    testImplementation(ANDROIDX_TEST_CORE)
+    testImplementation(ANDROIDX_TEST_RUNNER)
+    testImplementation(JUNIT)
+    testImplementation(MOCKITO_CORE)
+    testImplementation(ROBOLECTRIC)
+    testImplementation(TRUTH)
+
     annotationProcessor(NULLAWAY)
 }
 
diff --git a/car/app/app-testing/src/main/java/androidx/car/app/testing/SessionController.java b/car/app/app-testing/src/main/java/androidx/car/app/testing/SessionController.java
index f7d4692..2854441 100644
--- a/car/app/app-testing/src/main/java/androidx/car/app/testing/SessionController.java
+++ b/car/app/app-testing/src/main/java/androidx/car/app/testing/SessionController.java
@@ -53,7 +53,7 @@
     }
 
     /**
-     * Starts the {@link Session} that is being controlled.
+     * Creates the {@link Session} that is being controlled.
      *
      * @see Session#getLifecycle
      */
@@ -66,6 +66,20 @@
     }
 
     /**
+     * Starts the {@link Session} that is being controlled.
+     *
+     * @see Session#getLifecycle
+     */
+    @NonNull
+    public SessionController start() {
+        LifecycleRegistry registry = (LifecycleRegistry) mSession.getLifecycle();
+        registry.handleLifecycleEvent(Event.ON_START);
+
+        return this;
+    }
+
+
+    /**
      * Resumes the {@link Session} that is being controlled.
      *
      * @see Session#getLifecycle
diff --git a/car/app/app-testing/src/main/java/androidx/car/app/testing/TestAppManager.java b/car/app/app-testing/src/main/java/androidx/car/app/testing/TestAppManager.java
index 19fb4b9..35c91f8 100644
--- a/car/app/app-testing/src/main/java/androidx/car/app/testing/TestAppManager.java
+++ b/car/app/app-testing/src/main/java/androidx/car/app/testing/TestAppManager.java
@@ -66,7 +66,7 @@
      * set.
      */
     @Nullable
-    public SurfaceCallback getSurfaceListener() {
+    public SurfaceCallback getSurfaceCallback() {
         return mSurfaceCallback;
     }
 
diff --git a/car/app/app-testing/src/main/java/androidx/car/app/testing/TestScreenManager.java b/car/app/app-testing/src/main/java/androidx/car/app/testing/TestScreenManager.java
index e563063..dfe78a3 100644
--- a/car/app/app-testing/src/main/java/androidx/car/app/testing/TestScreenManager.java
+++ b/car/app/app-testing/src/main/java/androidx/car/app/testing/TestScreenManager.java
@@ -128,6 +128,19 @@
     }
 
     @Override
+    public void popToRoot() {
+        Set<Screen> screensBefore = getScreensInStack();
+        super.popToRoot();
+        Set<Screen> screensAfter = getScreensInStack();
+
+        for (Screen screen : screensBefore) {
+            if (!screensAfter.contains(screen)) {
+                mScreensRemoved.add(screen);
+            }
+        }
+    }
+
+    @Override
     public void remove(@NonNull Screen screen) {
         super.remove(screen);
         if (screen.getLifecycle().getCurrentState() == State.DESTROYED) {
diff --git a/car/app/app-testing/src/test/java/androidx/car/app/testing/FakeHostTest.java b/car/app/app-testing/src/test/java/androidx/car/app/testing/FakeHostTest.java
new file mode 100644
index 0000000..aecef0c
--- /dev/null
+++ b/car/app/app-testing/src/test/java/androidx/car/app/testing/FakeHostTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2021 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.car.app.testing;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+/** Tests for {@link FakeHost}. */
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+public class FakeHostTest {
+    private final TestCarContext mCarContext =
+            TestCarContext.createCarContext(ApplicationProvider.getApplicationContext());
+
+    @Test
+    @SuppressWarnings("PendingIntentMutability")
+    public void performNotificationActionClick() {
+        Intent broadcast = new Intent("foo");
+        PendingIntent pendingIntent = PendingIntent.getBroadcast(mCarContext, 1, broadcast, 0);
+
+        mCarContext.getFakeHost().performNotificationActionClick(pendingIntent);
+
+        assertThat(Shadows.shadowOf(mCarContext).getBroadcastIntents().get(0).getAction())
+                .isEqualTo(broadcast.getAction());
+    }
+}
diff --git a/car/app/app-testing/src/test/java/androidx/car/app/testing/ScreenControllerTest.java b/car/app/app-testing/src/test/java/androidx/car/app/testing/ScreenControllerTest.java
new file mode 100644
index 0000000..c64f636
--- /dev/null
+++ b/car/app/app-testing/src/test/java/androidx/car/app/testing/ScreenControllerTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2021 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.car.app.testing;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+
+import androidx.annotation.NonNull;
+import androidx.car.app.Screen;
+import androidx.car.app.model.Template;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+/** Tests for {@link ScreenController}. */
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+public class ScreenControllerTest {
+
+    @Mock
+    private DefaultLifecycleObserver mMockObserver;
+
+    private final Template mTemplate = new Template() {
+    };
+
+    private final Screen mTestScreen =
+            new Screen(
+                    TestCarContext.createCarContext(ApplicationProvider.getApplicationContext())) {
+                @NonNull
+                @Override
+                public Template onGetTemplate() {
+                    return mTemplate;
+                }
+            };
+
+    private ScreenController mScreenController;
+    private TestCarContext mCarContext;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+
+        mCarContext = TestCarContext.createCarContext(ApplicationProvider.getApplicationContext());
+        mScreenController = ScreenController.of(mCarContext, mTestScreen);
+
+        mTestScreen.getLifecycle().addObserver(mMockObserver);
+    }
+
+    @Test
+    public void create_movesLifecycleAndAddsToStack() {
+        mScreenController.create();
+
+        verify(mMockObserver).onCreate(any());
+        assertThat(mCarContext.getCarService(TestScreenManager.class).getScreensPushed())
+                .containsExactly(mTestScreen);
+    }
+
+    @Test
+    public void create_wasInStack_movesLifecycle() {
+        mCarContext.getCarService(TestScreenManager.class).push(mTestScreen);
+
+        mScreenController.create();
+
+        verify(mMockObserver).onCreate(any());
+        assertThat(mCarContext.getCarService(TestScreenManager.class).getScreensPushed())
+                .containsExactly(mTestScreen);
+    }
+
+    @Test
+    public void start_movesLifecycle() {
+        mScreenController.start();
+
+        verify(mMockObserver).onCreate(any());
+        verify(mMockObserver).onStart(any());
+    }
+
+    @Test
+    public void resume_movesLifecycle() {
+        mScreenController.resume();
+
+        verify(mMockObserver).onCreate(any());
+        verify(mMockObserver).onStart(any());
+        verify(mMockObserver).onResume(any());
+    }
+
+    @Test
+    public void pause_movesLifecycle() {
+        mScreenController.resume();
+        mScreenController.pause();
+
+        verify(mMockObserver).onCreate(any());
+        verify(mMockObserver).onStart(any());
+        verify(mMockObserver).onResume(any());
+        verify(mMockObserver).onPause(any());
+    }
+
+    @Test
+    public void stop_movesLifecycle() {
+        mScreenController.resume();
+        mScreenController.stop();
+
+        verify(mMockObserver).onCreate(any());
+        verify(mMockObserver).onStart(any());
+        verify(mMockObserver).onResume(any());
+        verify(mMockObserver).onPause(any());
+        verify(mMockObserver).onStop(any());
+    }
+
+    @Test
+    public void destroy_movesLifecycle() {
+        mScreenController.resume();
+        mScreenController.destroy();
+
+        verify(mMockObserver).onCreate(any());
+        verify(mMockObserver).onStart(any());
+        verify(mMockObserver).onResume(any());
+        verify(mMockObserver).onPause(any());
+        verify(mMockObserver).onStop(any());
+        verify(mMockObserver).onDestroy(any());
+    }
+
+    @Test
+    public void getReturnedTemplates() {
+        mScreenController.start();
+        mScreenController.reset();
+
+        mTestScreen.invalidate();
+
+        assertThat(mScreenController.getTemplatesReturned()).containsExactly(mTemplate);
+
+        mTestScreen.invalidate();
+        mTestScreen.invalidate();
+
+        assertThat(mScreenController.getTemplatesReturned())
+                .containsExactly(mTemplate, mTemplate, mTemplate);
+    }
+
+    @Test
+    public void reset() {
+        mScreenController.start();
+        mScreenController.reset();
+
+        mTestScreen.invalidate();
+        mTestScreen.invalidate();
+        mTestScreen.invalidate();
+
+        assertThat(mScreenController.getTemplatesReturned())
+                .containsExactly(mTemplate, mTemplate, mTemplate);
+
+        mScreenController.reset();
+        assertThat(mScreenController.getTemplatesReturned()).isEmpty();
+    }
+}
diff --git a/car/app/app-testing/src/test/java/androidx/car/app/testing/SessionControllerTest.java b/car/app/app-testing/src/test/java/androidx/car/app/testing/SessionControllerTest.java
new file mode 100644
index 0000000..4faf72b
--- /dev/null
+++ b/car/app/app-testing/src/test/java/androidx/car/app/testing/SessionControllerTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2021 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.car.app.testing;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+
+import android.content.Intent;
+
+import androidx.annotation.NonNull;
+import androidx.car.app.Screen;
+import androidx.car.app.Session;
+import androidx.car.app.model.Template;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+/** Tests for {@link SessionController}. */
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+public class SessionControllerTest {
+    private final Screen mScreen = new TestScreen();
+
+    @Mock
+    private DefaultLifecycleObserver mMockObserver;
+
+    private SessionController mSessionController;
+    private TestCarContext mCarContext;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mCarContext = TestCarContext.createCarContext(
+                ApplicationProvider.getApplicationContext());
+
+        Session session = new Session() {
+            @NonNull
+            @Override
+            public Screen onCreateScreen(@NonNull Intent intent) {
+                return mScreen;
+            }
+
+        };
+
+        mSessionController = SessionController.of(session, mCarContext);
+        session.getLifecycle().addObserver(mMockObserver);
+    }
+
+    @Test
+    public void create() {
+        mSessionController.create();
+
+        verify(mMockObserver).onCreate(any());
+    }
+
+    @Test
+    public void start() {
+        mSessionController.create().start();
+
+        verify(mMockObserver).onCreate(any());
+        verify(mMockObserver).onStart(any());
+    }
+
+    @Test
+    public void resume() {
+        mSessionController.create().resume();
+
+        verify(mMockObserver).onCreate(any());
+        verify(mMockObserver).onStart(any());
+        verify(mMockObserver).onResume(any());
+    }
+
+    @Test
+    public void pause() {
+        mSessionController.create().resume().pause();
+
+        verify(mMockObserver).onCreate(any());
+        verify(mMockObserver).onStart(any());
+        verify(mMockObserver).onResume(any());
+        verify(mMockObserver).onPause(any());
+    }
+
+    @Test
+    public void stop() {
+        mSessionController.create().resume().stop();
+
+        verify(mMockObserver).onCreate(any());
+        verify(mMockObserver).onStart(any());
+        verify(mMockObserver).onResume(any());
+        verify(mMockObserver).onPause(any());
+        verify(mMockObserver).onStop(any());
+    }
+
+    @Test
+    public void destroy() {
+        mSessionController.create().resume().destroy();
+
+        verify(mMockObserver).onCreate(any());
+        verify(mMockObserver).onStart(any());
+        verify(mMockObserver).onResume(any());
+        verify(mMockObserver).onPause(any());
+        verify(mMockObserver).onStop(any());
+        verify(mMockObserver).onDestroy(any());
+    }
+
+
+    /** A no-op screen for testing. */
+    private static class TestScreen extends Screen {
+        private TestScreen() {
+            super(TestCarContext.createCarContext(ApplicationProvider.getApplicationContext()));
+        }
+
+        @NonNull
+        @Override
+        public Template onGetTemplate() {
+            return new Template() {
+            };
+        }
+    }
+}
diff --git a/car/app/app-testing/src/test/java/androidx/car/app/testing/TestAppManagerTest.java b/car/app/app-testing/src/test/java/androidx/car/app/testing/TestAppManagerTest.java
new file mode 100644
index 0000000..841a00d
--- /dev/null
+++ b/car/app/app-testing/src/test/java/androidx/car/app/testing/TestAppManagerTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2021 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.car.app.testing;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.graphics.Rect;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+import androidx.car.app.AppManager;
+import androidx.car.app.CarToast;
+import androidx.car.app.Screen;
+import androidx.car.app.ScreenManager;
+import androidx.car.app.SurfaceCallback;
+import androidx.car.app.SurfaceContainer;
+import androidx.car.app.model.Template;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+/** Tests for {@link TestAppManager}. */
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+public class TestAppManagerTest {
+
+    private TestCarContext mCarContext;
+
+    private final Template mTemplate = new Template() {};
+
+    private Screen mTestScreen;
+
+    @Before
+    public void setup() {
+        mCarContext = TestCarContext.createCarContext(ApplicationProvider.getApplicationContext());
+
+        mTestScreen =
+                new Screen(mCarContext) {
+                    @NonNull
+                    @Override
+                    public Template onGetTemplate() {
+                        return mTemplate;
+                    }
+                };
+    }
+
+    @Test
+    public void getSurfaceCallbacks() {
+        SurfaceCallback callback1 = new TestSurfaceCallback();
+        SurfaceCallback callback2 = new TestSurfaceCallback();
+        SurfaceCallback callback3 = new TestSurfaceCallback();
+
+        mCarContext.getCarService(AppManager.class).setSurfaceCallback(callback1);
+
+        assertThat(mCarContext.getCarService(TestAppManager.class).getSurfaceCallback())
+                .isEqualTo(callback1);
+
+        mCarContext.getCarService(AppManager.class).setSurfaceCallback(callback2);
+        mCarContext.getCarService(AppManager.class).setSurfaceCallback(callback3);
+
+        assertThat(mCarContext.getCarService(TestAppManager.class).getSurfaceCallback())
+                .isEqualTo(callback3);
+    }
+
+    @Test
+    public void getToastsShown() {
+        String toast1 = "foo";
+        String toast2 = "bar";
+        String toast3 = "baz";
+        mCarContext.getCarService(AppManager.class).showToast(toast1, CarToast.LENGTH_LONG);
+
+        assertThat(mCarContext.getCarService(TestAppManager.class).getToastsShown())
+                .containsExactly(toast1);
+
+        mCarContext.getCarService(AppManager.class).showToast(toast2, CarToast.LENGTH_LONG);
+        mCarContext.getCarService(AppManager.class).showToast(toast3, CarToast.LENGTH_LONG);
+
+        assertThat(mCarContext.getCarService(TestAppManager.class).getToastsShown())
+                .containsExactly(toast1, toast2, toast3);
+    }
+
+    @Test
+    public void getTemplatesReturned() {
+        mCarContext.getCarService(ScreenManager.class).push(mTestScreen);
+        mCarContext.getCarService(TestAppManager.class).reset();
+
+        mCarContext.getCarService(AppManager.class).invalidate();
+
+        assertThat(mCarContext.getCarService(TestAppManager.class).getTemplatesReturned())
+                .containsExactly(Pair.create(mTestScreen, mTemplate));
+
+        mCarContext.getCarService(AppManager.class).invalidate();
+
+        Screen screen2 =
+                new Screen(mCarContext) {
+                    @NonNull
+                    @Override
+                    public Template onGetTemplate() {
+                        return mTemplate;
+                    }
+                };
+
+        mCarContext.getCarService(ScreenManager.class).push(screen2);
+        mCarContext.getCarService(AppManager.class).invalidate();
+
+        assertThat(mCarContext.getCarService(TestAppManager.class).getTemplatesReturned())
+                .containsExactly(
+                        Pair.create(mTestScreen, mTemplate),
+                        Pair.create(mTestScreen, mTemplate),
+                        Pair.create(screen2, mTemplate));
+    }
+
+    @Test
+    public void resetTemplatesStoredForScreen() {
+        mCarContext.getCarService(ScreenManager.class).push(mTestScreen);
+        mCarContext.getCarService(TestAppManager.class).reset();
+
+        mCarContext.getCarService(AppManager.class).invalidate();
+
+        assertThat(mCarContext.getCarService(TestAppManager.class).getTemplatesReturned())
+                .containsExactly(Pair.create(mTestScreen, mTemplate));
+
+        mCarContext.getCarService(AppManager.class).invalidate();
+
+        Screen screen2 =
+                new Screen(mCarContext) {
+                    @NonNull
+                    @Override
+                    public Template onGetTemplate() {
+                        return mTemplate;
+                    }
+                };
+
+        mCarContext.getCarService(ScreenManager.class).push(screen2);
+        mCarContext.getCarService(AppManager.class).invalidate();
+
+        assertThat(mCarContext.getCarService(TestAppManager.class).getTemplatesReturned())
+                .containsExactly(
+                        Pair.create(mTestScreen, mTemplate),
+                        Pair.create(mTestScreen, mTemplate),
+                        Pair.create(screen2, mTemplate));
+
+        mCarContext.getCarService(TestAppManager.class).resetTemplatesStoredForScreen(mTestScreen);
+        assertThat(mCarContext.getCarService(TestAppManager.class).getTemplatesReturned())
+                .containsExactly(Pair.create(screen2, mTemplate));
+    }
+
+    private static class TestSurfaceCallback implements SurfaceCallback {
+        @Override
+        public void onSurfaceAvailable(@NonNull SurfaceContainer surfaceContainer) {}
+
+        @Override
+        public void onVisibleAreaChanged(@NonNull Rect visibleArea) {}
+
+        @Override
+        public void onStableAreaChanged(@NonNull Rect stableArea) {}
+
+        @Override
+        public void onSurfaceDestroyed(@NonNull SurfaceContainer surfaceContainer) {}
+    }
+}
+
diff --git a/car/app/app-testing/src/test/java/androidx/car/app/testing/TestCarContextTest.java b/car/app/app-testing/src/test/java/androidx/car/app/testing/TestCarContextTest.java
new file mode 100644
index 0000000..fc9ebc0
--- /dev/null
+++ b/car/app/app-testing/src/test/java/androidx/car/app/testing/TestCarContextTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2021 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.car.app.testing;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+
+import androidx.car.app.AppManager;
+import androidx.car.app.CarContext;
+import androidx.car.app.ScreenManager;
+import androidx.car.app.navigation.NavigationManager;
+import androidx.car.app.testing.navigation.TestNavigationManager;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+/** Tests for {@link TestCarContext}. */
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+public class TestCarContextTest {
+    private final TestCarContext mCarContext =
+            TestCarContext.createCarContext(ApplicationProvider.getApplicationContext());
+
+    @Test
+    public void getCarService_appManager_returnsTestAppManager() {
+        assertThat(mCarContext.getCarService(AppManager.class))
+                .isSameInstanceAs(mCarContext.getCarService(TestAppManager.class));
+    }
+
+    @Test
+    public void getCarService_navigationManager_returnsTestNavigationManager() {
+        assertThat(mCarContext.getCarService(NavigationManager.class))
+                .isSameInstanceAs(mCarContext.getCarService(TestNavigationManager.class));
+    }
+
+    @Test
+    public void getCarService_screenManager_returnsTestAppManager() {
+        assertThat(mCarContext.getCarService(ScreenManager.class))
+                .isSameInstanceAs(mCarContext.getCarService(TestScreenManager.class));
+    }
+
+    @Test
+    @SuppressWarnings("PendingIntentMutability")
+    public void getStartCarAppIntents() {
+        Intent startApp = new Intent(Intent.ACTION_VIEW);
+
+        mCarContext.startCarApp(startApp);
+
+        assertThat(mCarContext.getStartCarAppIntents()).containsExactly(startApp);
+
+        Intent broadcast = new Intent("foo");
+        PendingIntent pendingIntent = PendingIntent.getBroadcast(mCarContext, 1, broadcast, 0);
+
+        mCarContext.getFakeHost().performNotificationActionClick(pendingIntent);
+
+        Intent broadcastedIntent = Shadows.shadowOf(mCarContext).getBroadcastIntents().get(0);
+        Intent startApp2 = new Intent(Intent.ACTION_SEND);
+        CarContext.startCarApp(broadcastedIntent, startApp2);
+
+        assertThat(mCarContext.getStartCarAppIntents()).containsExactly(startApp, startApp2);
+    }
+
+    @Test
+    public void hasCalledFinishCarApp() {
+        assertThat(mCarContext.hasCalledFinishCarApp()).isFalse();
+
+        mCarContext.finishCarApp();
+
+        assertThat(mCarContext.hasCalledFinishCarApp()).isTrue();
+    }
+}
diff --git a/car/app/app-testing/src/test/java/androidx/car/app/testing/TestScreenManagerTest.java b/car/app/app-testing/src/test/java/androidx/car/app/testing/TestScreenManagerTest.java
new file mode 100644
index 0000000..15e07d2
--- /dev/null
+++ b/car/app/app-testing/src/test/java/androidx/car/app/testing/TestScreenManagerTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2021 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.car.app.testing;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.annotation.NonNull;
+import androidx.car.app.Screen;
+import androidx.car.app.ScreenManager;
+import androidx.car.app.model.Template;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+/** Tests for {@link TestScreenManager}. */
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+public class TestScreenManagerTest {
+    private TestCarContext mCarContext;
+
+    @Before
+    public void setup() {
+        mCarContext = TestCarContext.createCarContext(ApplicationProvider.getApplicationContext());
+    }
+
+    @Test
+    public void push_getScreensPushed() {
+        Screen screen1 = new TestScreen();
+
+        mCarContext.getCarService(ScreenManager.class).push(screen1);
+        assertThat(mCarContext.getCarService(TestScreenManager.class).getScreensPushed())
+                .containsExactly(screen1);
+    }
+
+    @Test
+    public void pushForResult_getScreensPushed() {
+        Screen screen1 = new TestScreen();
+        Screen screen2 = new TestScreen();
+
+        mCarContext.getCarService(ScreenManager.class).push(screen1);
+        assertThat(mCarContext.getCarService(TestScreenManager.class).getScreensPushed())
+                .containsExactly(screen1);
+
+        mCarContext.getCarService(ScreenManager.class).pushForResult(screen2, result -> {});
+        assertThat(mCarContext.getCarService(TestScreenManager.class).getScreensPushed())
+                .containsExactly(screen1, screen2);
+    }
+
+    @Test
+    public void pop_getScreensRemoved() {
+        Screen screen1 = new TestScreen();
+        Screen screen2 = new TestScreen();
+        Screen screen3 = new TestScreen();
+        Screen screen4 = new TestScreen();
+
+        mCarContext.getCarService(ScreenManager.class).push(screen1);
+        mCarContext.getCarService(ScreenManager.class).push(screen2);
+        mCarContext.getCarService(ScreenManager.class).push(screen3);
+        mCarContext.getCarService(ScreenManager.class).push(screen4);
+
+        mCarContext.getCarService(ScreenManager.class).pop();
+        assertThat(mCarContext.getCarService(TestScreenManager.class).getScreensRemoved())
+                .containsExactly(screen4);
+    }
+
+    @Test
+    public void remove_getScreensRemoved() {
+        Screen screen1 = new TestScreen();
+        Screen screen2 = new TestScreen();
+        Screen screen3 = new TestScreen();
+        Screen screen4 = new TestScreen();
+
+        mCarContext.getCarService(ScreenManager.class).push(screen1);
+        mCarContext.getCarService(ScreenManager.class).push(screen2);
+        mCarContext.getCarService(ScreenManager.class).push(screen3);
+        mCarContext.getCarService(ScreenManager.class).push(screen4);
+
+        mCarContext.getCarService(ScreenManager.class).remove(screen2);
+        assertThat(mCarContext.getCarService(TestScreenManager.class).getScreensRemoved())
+                .containsExactly(screen2);
+    }
+
+    @Test
+    public void popTo_getScreensRemoved() {
+        Screen screen1 = new TestScreen();
+        Screen screen2 = new TestScreen();
+        Screen screen3 = new TestScreen();
+        Screen screen4 = new TestScreen();
+
+        mCarContext.getCarService(ScreenManager.class).push(screen1);
+        mCarContext.getCarService(ScreenManager.class).push(screen2);
+        mCarContext.getCarService(ScreenManager.class).push(screen3);
+        mCarContext.getCarService(ScreenManager.class).push(screen4);
+
+        String marker = "foo";
+        screen2.setMarker(marker);
+
+        mCarContext.getCarService(ScreenManager.class).popTo(marker);
+        assertThat(mCarContext.getCarService(TestScreenManager.class).getScreensRemoved())
+                .containsExactly(screen4, screen3);
+    }
+
+    @Test
+    public void popToRoot_getScreensRemoved() {
+        Screen screen1 = new TestScreen();
+        Screen screen2 = new TestScreen();
+        Screen screen3 = new TestScreen();
+        Screen screen4 = new TestScreen();
+
+        mCarContext.getCarService(ScreenManager.class).push(screen1);
+        mCarContext.getCarService(ScreenManager.class).push(screen2);
+        mCarContext.getCarService(ScreenManager.class).push(screen3);
+        mCarContext.getCarService(ScreenManager.class).push(screen4);
+
+        mCarContext.getCarService(ScreenManager.class).popToRoot();
+        assertThat(mCarContext.getCarService(TestScreenManager.class).getScreensRemoved())
+                .containsExactly(screen4, screen3, screen2);
+    }
+
+    private static class TestScreen extends Screen {
+        private TestScreen() {
+            super(TestCarContext.createCarContext(ApplicationProvider.getApplicationContext()));
+        }
+
+        @NonNull
+        @Override
+        public Template onGetTemplate() {
+            return new Template() {};
+        }
+    }
+}
diff --git a/car/app/app-testing/src/test/java/androidx/car/app/testing/navigation/TestNavigationManagerTest.java b/car/app/app-testing/src/test/java/androidx/car/app/testing/navigation/TestNavigationManagerTest.java
new file mode 100644
index 0000000..389ea8d
--- /dev/null
+++ b/car/app/app-testing/src/test/java/androidx/car/app/testing/navigation/TestNavigationManagerTest.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2021 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.car.app.testing.navigation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.car.app.model.CarText;
+import androidx.car.app.model.DateTimeWithZone;
+import androidx.car.app.model.Distance;
+import androidx.car.app.navigation.NavigationManager;
+import androidx.car.app.navigation.NavigationManagerCallback;
+import androidx.car.app.navigation.model.Destination;
+import androidx.car.app.navigation.model.Step;
+import androidx.car.app.navigation.model.TravelEstimate;
+import androidx.car.app.navigation.model.Trip;
+import androidx.car.app.testing.TestCarContext;
+import androidx.test.core.app.ApplicationProvider;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.internal.DoNotInstrument;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.Duration;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+
+/** Tests for {@link TestNavigationManager}. */
+@RunWith(RobolectricTestRunner.class)
+@DoNotInstrument
+public class TestNavigationManagerTest {
+    private TestCarContext mCarContext;
+
+    @Before
+    public void setup() {
+        mCarContext = TestCarContext.createCarContext(ApplicationProvider.getApplicationContext());
+    }
+
+    @Test
+    public void getNavigationStatesSent() {
+        // First need to set a listener and start navigation.
+        NavigationManagerCallback listener1 = new TestNavigationManagerCallback();
+        mCarContext.getCarService(NavigationManager.class).setNavigationManagerCallback(listener1);
+        mCarContext.getCarService(NavigationManager.class).navigationStarted();
+
+        Destination destination1 =
+                new Destination.Builder().setName("Home").setAddress("123 State Street").build();
+        Step step1 = new Step.Builder("Straight Ahead").build();
+        TravelEstimate stepTravelEstimate1 =
+                new TravelEstimate.Builder(
+                        Distance.create(/* displayDistance= */ 100, Distance.UNIT_METERS),
+                        createDateTimeWithZone("2020-04-14T15:57:00",
+                                "US/Pacific")).setRemainingTime(Duration.ofMinutes(1)).build();
+        TravelEstimate destinationTravelEstimate1 =
+                new TravelEstimate.Builder(
+                        Distance.create(/* displayDistance= */ 10000, Distance.UNIT_METERS),
+                        createDateTimeWithZone("2020-04-14T16:57:00",
+                                "US/Pacific")).setRemainingTime(Duration.ofHours(1)).build();
+        String road1 = "State St.";
+        Trip trip1 =
+                new Trip.Builder()
+                        .addDestination(destination1, destinationTravelEstimate1)
+                        .addStep(step1, stepTravelEstimate1)
+                        .setCurrentRoad(road1)
+                        .build();
+        mCarContext.getCarService(NavigationManager.class).updateTrip(trip1);
+        List<Trip> tripsSent1 =
+                mCarContext.getCarService(TestNavigationManager.class).getTripsSent();
+        assertThat(tripsSent1).hasSize(1);
+        checkTrip(
+                tripsSent1.get(0),
+                ImmutableList.of(destination1),
+                ImmutableList.of(step1),
+                ImmutableList.of(destinationTravelEstimate1),
+                ImmutableList.of(stepTravelEstimate1),
+                road1);
+
+        Destination destination2 =
+                new Destination.Builder().setName("Gas").setAddress("456 State Street").build();
+        Step step2 = new Step.Builder("Turn Left").build();
+        TravelEstimate stepTravelEstimate2 =
+                new TravelEstimate.Builder(
+                        Distance.create(/* displayDistance= */ 200, Distance.UNIT_METERS),
+                        createDateTimeWithZone("2020-04-14T15:57:00",
+                                "US/Pacific")).setRemainingTime(Duration.ofMinutes(2)).build();
+        TravelEstimate destinationTravelEstimate2 =
+                new TravelEstimate.Builder(
+                        Distance.create(/* displayDistance= */ 20000, Distance.UNIT_METERS),
+                        createDateTimeWithZone("2020-04-14T17:57:00",
+                                "US/Pacific")).setRemainingTime(Duration.ofHours(2)).build();
+        String road2 = "6th St.";
+        Trip trip2 =
+                new Trip.Builder()
+                        .addDestination(destination2, destinationTravelEstimate2)
+                        .addStep(step2, stepTravelEstimate2)
+                        .setCurrentRoad(road2)
+                        .build();
+
+        Destination destination3 =
+                new Destination.Builder().setName("Work").setAddress("789 State Street").build();
+        Step step3 = new Step.Builder("Turn Right").build();
+        TravelEstimate stepTravelEstimate3 =
+                new TravelEstimate.Builder(
+                        Distance.create(/* displayDistance= */ 300, Distance.UNIT_METERS),
+                        createDateTimeWithZone("2020-04-14T15:57:00",
+                                "US/Pacific")).setRemainingTime(Duration.ofMinutes(3)).build();
+        TravelEstimate destinationTravelEstimate3 =
+                new TravelEstimate.Builder(
+                        Distance.create(/* displayDistance= */ 30000, Distance.UNIT_METERS),
+                        createDateTimeWithZone("2020-04-14T15:57:00",
+                                "US/Pacific")).setRemainingTime(Duration.ofHours(3)).build();
+        String road3 = "Kirkland Way";
+        Trip trip3 =
+                new Trip.Builder()
+                        .addDestination(destination3, destinationTravelEstimate3)
+                        .addStep(step3, stepTravelEstimate3)
+                        .setCurrentRoad(road3)
+                        .build();
+
+        mCarContext.getCarService(NavigationManager.class).updateTrip(trip2);
+        mCarContext.getCarService(NavigationManager.class).updateTrip(trip3);
+        List<Trip> tripsSent2 =
+                mCarContext.getCarService(TestNavigationManager.class).getTripsSent();
+        assertThat(tripsSent2).hasSize(3);
+
+        checkTrip(
+                tripsSent2.get(0),
+                ImmutableList.of(destination1),
+                ImmutableList.of(step1),
+                ImmutableList.of(destinationTravelEstimate1),
+                ImmutableList.of(stepTravelEstimate1),
+                road1);
+        checkTrip(
+                tripsSent2.get(1),
+                ImmutableList.of(destination2),
+                ImmutableList.of(step2),
+                ImmutableList.of(destinationTravelEstimate2),
+                ImmutableList.of(stepTravelEstimate2),
+                road2);
+        checkTrip(
+                tripsSent2.get(2),
+                ImmutableList.of(destination3),
+                ImmutableList.of(step3),
+                ImmutableList.of(destinationTravelEstimate3),
+                ImmutableList.of(stepTravelEstimate3),
+                road3);
+    }
+
+    @Test
+    public void getNavigationManagerCallbacksSet() {
+        NavigationManagerCallback listener1 = new TestNavigationManagerCallback();
+
+        mCarContext.getCarService(NavigationManager.class).setNavigationManagerCallback(listener1);
+        assertThat(
+                mCarContext
+                        .getCarService(TestNavigationManager.class)
+                        .getNavigationManagerCallback())
+                .isEqualTo(listener1);
+
+        NavigationManagerCallback listener2 = new TestNavigationManagerCallback();
+        NavigationManagerCallback listener3 = new TestNavigationManagerCallback();
+
+        mCarContext.getCarService(NavigationManager.class).setNavigationManagerCallback(listener2);
+        mCarContext.getCarService(NavigationManager.class).setNavigationManagerCallback(listener3);
+
+        assertThat(
+                mCarContext
+                        .getCarService(TestNavigationManager.class)
+                        .getNavigationManagerCallback())
+                .isEqualTo(listener3);
+
+        mCarContext.getCarService(NavigationManager.class).navigationEnded();
+        mCarContext.getCarService(NavigationManager.class).clearNavigationManagerCallback();
+        assertThat(
+                mCarContext
+                        .getCarService(TestNavigationManager.class)
+                        .getNavigationManagerCallback())
+                .isEqualTo(null);
+    }
+
+    @Test
+    public void getNavigationStartedCount() {
+        mCarContext
+                .getCarService(NavigationManager.class)
+                .setNavigationManagerCallback(new TestNavigationManagerCallback());
+
+        assertThat(
+                mCarContext.getCarService(TestNavigationManager.class).getNavigationStartedCount())
+                .isEqualTo(0);
+
+        mCarContext.getCarService(NavigationManager.class).navigationStarted();
+        assertThat(
+                mCarContext.getCarService(TestNavigationManager.class).getNavigationStartedCount())
+                .isEqualTo(1);
+    }
+
+    @Test
+    public void getNavigationEndedCount() {
+        assertThat(mCarContext.getCarService(TestNavigationManager.class).getNavigationEndedCount())
+                .isEqualTo(0);
+
+        mCarContext.getCarService(NavigationManager.class).navigationEnded();
+        assertThat(mCarContext.getCarService(TestNavigationManager.class).getNavigationEndedCount())
+                .isEqualTo(1);
+    }
+
+    private static void checkTrip(
+            Trip trip,
+            List<Destination> destinations,
+            List<Step> steps,
+            List<TravelEstimate> destinationTravelEstimates,
+            List<TravelEstimate> stepTravelEstimates,
+            String currentRoad) {
+        assertThat(trip.getDestinations()).hasSize(destinations.size());
+        int destinationIndex = 0;
+        for (Destination destination : destinations) {
+            assertThat(trip.getDestinations().get(destinationIndex++))
+                    .isEqualTo(destination);
+        }
+        assertThat(trip.getSteps()).hasSize(steps.size());
+        int stepIndex = 0;
+        for (Step step : steps) {
+            assertThat(trip.getSteps().get(stepIndex++)).isEqualTo(step);
+        }
+        assertThat(trip.getDestinationTravelEstimates())
+                .containsExactlyElementsIn(destinationTravelEstimates);
+        assertThat(trip.getStepTravelEstimates())
+                .containsExactlyElementsIn(stepTravelEstimates);
+        assertThat(trip.getCurrentRoad()).isEqualTo(CarText.create(currentRoad));
+    }
+
+    /** A no-op callback for testing purposes. */
+    private static class TestNavigationManagerCallback implements NavigationManagerCallback {
+        @Override
+        public void onStopNavigation() {
+        }
+
+        @Override
+        public void onAutoDriveEnabled() {
+        }
+    }
+
+    /**
+     * Returns a {@link DateTimeWithZone} instance from a date string and a time zone id.
+     *
+     * @param dateTimeString The string in ISO format, for example "2020-04-14T15:57:00".
+     * @param zoneIdString   An Olson DB time zone identifier, for example "US/Pacific".
+     */
+    private DateTimeWithZone createDateTimeWithZone(String dateTimeString, String zoneIdString) {
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+        TimeZone timeZone = TimeZone.getTimeZone(zoneIdString);
+        dateFormat.setTimeZone(timeZone);
+        Date date;
+        try {
+            date = dateFormat.parse(dateTimeString);
+        } catch (ParseException e) {
+            throw new IllegalArgumentException("Failed to parse string: " + dateTimeString, e);
+        }
+        if (date == null) {
+            throw new IllegalArgumentException("Failed to parse string: " + dateTimeString);
+        }
+        return DateTimeWithZone.create(date.getTime(), timeZone);
+    }
+}
diff --git a/car/app/app-testing/src/test/resources/robolectric.properties b/car/app/app-testing/src/test/resources/robolectric.properties
new file mode 100644
index 0000000..f129cbb
--- /dev/null
+++ b/car/app/app-testing/src/test/resources/robolectric.properties
@@ -0,0 +1,19 @@
+#
+# Copyright 2021 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.
+#
+
+# Robolectric currently doesn't support API 30, so we have to explicitly specify 29 as the target
+# sdk for now. Remove when no longer necessary.
+sdk=29
\ No newline at end of file
diff --git a/car/app/app/src/main/java/androidx/car/app/model/Action.java b/car/app/app/src/main/java/androidx/car/app/model/Action.java
index 335cc99..d9cc274 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/Action.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/Action.java
@@ -286,7 +286,7 @@
          * <p>Spans are not supported in the input string.
          *
          * @throws NullPointerException if {@code title} is {@code null}
-         * @see CarText for details on text handling and span support.
+         * @see CarText
          */
         @NonNull
         public Builder setTitle(@NonNull CharSequence title) {
diff --git a/car/app/app/src/main/java/androidx/car/app/model/MessageTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/MessageTemplate.java
index f2a5cd7..48010f8 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/MessageTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/MessageTemplate.java
@@ -198,7 +198,7 @@
          * <p>Spans are not supported in the input string.
          *
          * @throws NullPointerException if {@code title} is {@code null}
-         * @see CarText for details on text handling and span support.
+         * @see CarText
          */
         @NonNull
         public Builder setTitle(@NonNull CharSequence title) {
diff --git a/car/app/app/src/main/java/androidx/car/app/model/PaneTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/PaneTemplate.java
index b54c1a8..237ae8c 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/PaneTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/PaneTemplate.java
@@ -160,7 +160,7 @@
          * <p>Spans are not supported in the input string.
          *
          * @throws NullPointerException if {@code title} is {@code null}
-         * @see CarText for details on text handling and span support.
+         * @see CarText
          */
         @NonNull
         public Builder setTitle(@NonNull CharSequence title) {
diff --git a/car/app/app/src/main/java/androidx/car/app/model/PlaceListMapTemplate.java b/car/app/app/src/main/java/androidx/car/app/model/PlaceListMapTemplate.java
index 5eb6f9e..8737c88 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/PlaceListMapTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/PlaceListMapTemplate.java
@@ -263,7 +263,7 @@
          * <p>Spans are not supported in the input string.
          *
          * @throws NullPointerException if {@code title} is {@code null}
-         * @see CarText for details on text handling and span support.
+         * @see CarText
          */
         @NonNull
         public Builder setTitle(@NonNull CharSequence title) {
diff --git a/car/app/app/src/main/java/androidx/car/app/model/PlaceMarker.java b/car/app/app/src/main/java/androidx/car/app/model/PlaceMarker.java
index b7ca8fa..8ae7537 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/PlaceMarker.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/PlaceMarker.java
@@ -219,7 +219,7 @@
          *              size of 3 characters. Set to {@code null} to let the host choose a
          *              labelling scheme (for example, using a sequence of numbers)
          * @throws NullPointerException if the {@code label} is {@code null}
-         * @see CarText for details on text handling and span support.
+         * @see CarText
          */
         @NonNull
         public Builder setLabel(@NonNull CharSequence label) {
diff --git a/car/app/app/src/main/java/androidx/car/app/navigation/model/Destination.java b/car/app/app/src/main/java/androidx/car/app/navigation/model/Destination.java
index 4683cb0..e63a297 100644
--- a/car/app/app/src/main/java/androidx/car/app/navigation/model/Destination.java
+++ b/car/app/app/src/main/java/androidx/car/app/navigation/model/Destination.java
@@ -130,7 +130,7 @@
          * <p>Spans are not supported in the input string.
          *
          * @throws NullPointerException if {@code name} is {@code null}
-         * @see CarText for details on text handling and span support.
+         * @see CarText
          */
         @NonNull
         public Builder setName(@NonNull CharSequence name) {
@@ -144,7 +144,7 @@
          * <p>Spans are not supported in the input string.
          *
          * @throws NullPointerException if {@code address} is {@code null}
-         * @see CarText for details on text handling and span support.
+         * @see CarText
          */
         @NonNull
         public Builder setAddress(@NonNull CharSequence address) {
diff --git a/car/app/app/src/main/java/androidx/car/app/navigation/model/MessageInfo.java b/car/app/app/src/main/java/androidx/car/app/navigation/model/MessageInfo.java
index 186bb9d..2fa728d 100644
--- a/car/app/app/src/main/java/androidx/car/app/navigation/model/MessageInfo.java
+++ b/car/app/app/src/main/java/androidx/car/app/navigation/model/MessageInfo.java
@@ -126,7 +126,7 @@
          * <p>Spans are not supported in the input string.
          *
          * @throws NullPointerException if {@code message} is {@code null}
-         * @see CarText for details on text handling and span support.
+         * @see CarText
          */
         @NonNull
         public Builder setTitle(@NonNull CharSequence title) {
@@ -142,7 +142,7 @@
          * <p>Spans are not supported in the input string.
          *
          * @throws NullPointerException if {@code text} is {@code null}
-         * @see CarText for details on text handling and span support.
+         * @see CarText
          */
         @NonNull
         public Builder setText(@NonNull CharSequence text) {
diff --git a/car/app/app/src/main/java/androidx/car/app/navigation/model/PlaceListNavigationTemplate.java b/car/app/app/src/main/java/androidx/car/app/navigation/model/PlaceListNavigationTemplate.java
index 8c8833d..f55367b 100644
--- a/car/app/app/src/main/java/androidx/car/app/navigation/model/PlaceListNavigationTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/navigation/model/PlaceListNavigationTemplate.java
@@ -197,7 +197,7 @@
          * <p>Spans are not supported in the input string.
          *
          * @throws NullPointerException if {@code title} is null
-         * @see CarText for details on text handling and span support.
+         * @see CarText
          */
         @NonNull
         public Builder setTitle(@NonNull CharSequence title) {
diff --git a/car/app/app/src/main/java/androidx/car/app/navigation/model/RoutePreviewNavigationTemplate.java b/car/app/app/src/main/java/androidx/car/app/navigation/model/RoutePreviewNavigationTemplate.java
index 66a0da6..5cb909f 100644
--- a/car/app/app/src/main/java/androidx/car/app/navigation/model/RoutePreviewNavigationTemplate.java
+++ b/car/app/app/src/main/java/androidx/car/app/navigation/model/RoutePreviewNavigationTemplate.java
@@ -224,7 +224,7 @@
          * <p>Spans are not supported in the input string.
          *
          * @throws NullPointerException if {@code title} is null
-         * @see CarText for details on text handling and span support.
+         * @see CarText
          */
         @NonNull
         public Builder setTitle(@NonNull CharSequence title) {
diff --git a/car/app/app/src/main/java/androidx/car/app/navigation/model/Step.java b/car/app/app/src/main/java/androidx/car/app/navigation/model/Step.java
index 3c52e43..a4b0a4b 100644
--- a/car/app/app/src/main/java/androidx/car/app/navigation/model/Step.java
+++ b/car/app/app/src/main/java/androidx/car/app/navigation/model/Step.java
@@ -283,7 +283,7 @@
          * that work with different car screen pixel densities.
          *
          * @throws NullPointerException if {@code cue} is {@code null}
-         * @see CarText for details on text handling and span support.
+         * @see CarText
          */
         @NonNull
         public Builder setCue(@NonNull CharSequence cue) {
@@ -302,7 +302,7 @@
          * <p>Spans are not supported in the input string.
          *
          * @throws NullPointerException if {@code destinations} is {@code null}
-         * @see CarText for details on text handling and span support.
+         * @see CarText
          */
         @NonNull
         public Builder setRoad(@NonNull CharSequence road) {
diff --git a/car/app/app/src/main/java/androidx/car/app/navigation/model/Trip.java b/car/app/app/src/main/java/androidx/car/app/navigation/model/Trip.java
index 1e2ed08..03a9fe1 100644
--- a/car/app/app/src/main/java/androidx/car/app/navigation/model/Trip.java
+++ b/car/app/app/src/main/java/androidx/car/app/navigation/model/Trip.java
@@ -234,7 +234,7 @@
          * <p>Spans are not supported in the input string.
          *
          * @throws NullPointerException if {@code currentRoad} is {@code null}
-         * @see CarText for details on text handling and span support.
+         * @see CarText
          */
         @NonNull
         public Builder setCurrentRoad(@NonNull CharSequence currentRoad) {
diff --git a/cleanBuild.sh b/cleanBuild.sh
index 55b7736..3ee4ae6 100755
--- a/cleanBuild.sh
+++ b/cleanBuild.sh
@@ -73,7 +73,7 @@
   # ~/.gradle as the Gradle cache dir, which could surprise users because it might hold
   # different state. So, we preemptively remove ~/.gradle too, just in case the user
   # is going to want that for their following build
-  rm ~/.gradle -rf
+  rm -rf ~/.gradle
   # AGP should (also) do this automatically (b/170640263)
   rm -rf appsearch/appsearch/.cxx
   rm -rf appsearch/local-backend/.cxx
diff --git a/compose/animation/animation-core/benchmark/build.gradle b/compose/animation/animation-core/benchmark/build.gradle
new file mode 100644
index 0000000..de70087
--- /dev/null
+++ b/compose/animation/animation-core/benchmark/build.gradle
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2021 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("AndroidXPlugin")
+    id("com.android.library")
+    id("AndroidXUiPlugin")
+    id("org.jetbrains.kotlin.android")
+    id("androidx.benchmark")
+}
+
+dependencies {
+    kotlinPlugin project(":compose:compiler:compiler")
+
+    androidTestImplementation project(":benchmark:benchmark-junit4")
+    androidTestImplementation project(":compose:runtime:runtime")
+    androidTestImplementation project(":compose:benchmark-utils")
+    androidTestImplementation(ANDROIDX_TEST_RULES)
+    androidTestImplementation(KOTLIN_STDLIB)
+    androidTestImplementation(KOTLIN_TEST_COMMON)
+    androidTestImplementation(JUNIT)
+}
diff --git a/compose/animation/animation-core/benchmark/src/androidTest/AndroidManifest.xml b/compose/animation/animation-core/benchmark/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..fea4215
--- /dev/null
+++ b/compose/animation/animation-core/benchmark/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2021 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"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="androidx.compose.animation.core.benchmark">
+
+    <!--
+      ~ Important: disable debuggable for accurate performance results
+      -->
+    <application
+            android:debuggable="false"
+            tools:replace="android:debuggable">
+        <!-- enable profileableByShell for non-intrusive profiling tools -->
+        <!--suppress AndroidElementNotAllowed -->
+        <profileable android:shell="true"/>
+    </application>
+</manifest>
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/AnimationBenchmark.kt b/compose/animation/animation-core/benchmark/src/androidTest/java/androidx/compose/animation/core/benchmark/AnimationBenchmark.kt
similarity index 98%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/AnimationBenchmark.kt
rename to compose/animation/animation-core/benchmark/src/androidTest/java/androidx/compose/animation/core/benchmark/AnimationBenchmark.kt
index 3911015..f004d5e 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/AnimationBenchmark.kt
+++ b/compose/animation/animation-core/benchmark/src/androidTest/java/androidx/compose/animation/core/benchmark/AnimationBenchmark.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.ui.benchmark.test
+package androidx.compose.animation.core.benchmark
 
 import androidx.benchmark.junit4.BenchmarkRule
 import androidx.benchmark.junit4.measureRepeated
@@ -31,11 +31,11 @@
 import androidx.compose.animation.core.VectorizedSpringSpec
 import androidx.compose.animation.core.VectorizedTweenSpec
 import androidx.compose.animation.core.createAnimation
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import androidx.test.ext.junit.runners.AndroidJUnit4
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
@@ -162,4 +162,4 @@
             }
         }
     }
-}
+}
\ No newline at end of file
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/SpringEstimationBenchmark.kt b/compose/animation/animation-core/benchmark/src/androidTest/java/androidx/compose/animation/core/benchmark/SpringEstimationBenchmark.kt
similarity index 97%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/SpringEstimationBenchmark.kt
rename to compose/animation/animation-core/benchmark/src/androidTest/java/androidx/compose/animation/core/benchmark/SpringEstimationBenchmark.kt
index 743b2bc..7c72011 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/SpringEstimationBenchmark.kt
+++ b/compose/animation/animation-core/benchmark/src/androidTest/java/androidx/compose/animation/core/benchmark/SpringEstimationBenchmark.kt
@@ -14,16 +14,16 @@
  * limitations under the License.
  */
 
-package androidx.ui.benchmark.test
+package androidx.compose.animation.core.benchmark
 
 import androidx.benchmark.junit4.BenchmarkRule
 import androidx.benchmark.junit4.measureRepeated
 import androidx.compose.animation.core.estimateAnimationDurationMillis
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import androidx.test.ext.junit.runners.AndroidJUnit4
 import kotlin.math.sqrt
 
 @LargeTest
diff --git a/compose/animation/animation-core/benchmark/src/main/AndroidManifest.xml b/compose/animation/animation-core/benchmark/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e2b118f
--- /dev/null
+++ b/compose/animation/animation-core/benchmark/src/main/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2021 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.compose.animation.core.benchmark">
+    <application/>
+</manifest>
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt
index 7e4c686..3e39440 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibilityDemo.kt
@@ -72,14 +72,6 @@
     Box(
         Modifier.padding(bottom = 20.dp)
     ) {
-        Button(
-            modifier = Modifier.align(Alignment.TopEnd).padding(10.dp),
-            onClick = {
-                counter = (counter + 1) % 12
-            }
-        ) {
-            Text("Click Me")
-        }
 
         val modifier = if (animateContentSize) Modifier.animateContentSize() else Modifier
         Column(
@@ -122,6 +114,15 @@
                 )
             }
         }
+
+        Button(
+            modifier = Modifier.align(Alignment.TopEnd).padding(10.dp),
+            onClick = {
+                counter = (counter + 1) % 12
+            }
+        ) {
+            Text("Click Me")
+        }
     }
 }
 
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibiltyContentSizeChangeDemo.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibiltyContentSizeChangeDemo.kt
new file mode 100644
index 0000000..7e9a774
--- /dev/null
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimatedVisibiltyContentSizeChangeDemo.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2021 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.compose.animation.demos
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.ExperimentalAnimationApi
+import androidx.compose.animation.animateContentSize
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.material.Button
+import androidx.compose.material.Checkbox
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+
+@OptIn(ExperimentalAnimationApi::class)
+@Composable
+fun AnimatedVisibilityContentSizeChangeDemo() {
+    Column {
+        val isOpen = remember { mutableStateOf(true) }
+        val itemListState = remember { mutableStateOf(listOf(1)) }
+        val itemList = itemListState.value
+        val (checked, onCheckedChanged) = remember { mutableStateOf(false) }
+        Row(
+            Modifier.height(60.dp).fillMaxWidth(),
+            horizontalArrangement = Arrangement.SpaceEvenly
+        ) {
+            Button(
+                onClick = { isOpen.value = !isOpen.value },
+                modifier = Modifier.align(Alignment.CenterVertically)
+            ) {
+                Text("Toggle\n visibility")
+            }
+
+            Row(modifier = Modifier.align(Alignment.CenterVertically)) {
+                Checkbox(
+                    checked,
+                    onCheckedChanged,
+                )
+                Text("animateContentSize", Modifier.clickable { onCheckedChanged(!checked) })
+            }
+
+            Button(
+                onClick = { itemListState.value = itemList + (itemList.size + 1) },
+                modifier = Modifier.align(Alignment.CenterVertically)
+            ) {
+                Text("Add\n item")
+            }
+        }
+
+        AnimatedVisibility(visible = isOpen.value) {
+            Column(
+                Modifier.background(pastelColors[2]).fillMaxWidth()
+                    .then(if (checked) Modifier.animateContentSize() else Modifier)
+            ) {
+                itemList.map {
+                    Text("Item #$it", Modifier.align(Alignment.CenterHorizontally))
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
index 75ed229..bfc8ce6 100644
--- a/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
+++ b/compose/animation/animation/integration-tests/animation-demos/src/main/java/androidx/compose/animation/demos/AnimationDemos.kt
@@ -40,6 +40,9 @@
                 ComposableDemo("Animate Visibility Lazy Column Demo") {
                     AnimatedVisibilityLazyColumnDemo()
                 },
+                ComposableDemo("Animate Visibility Content Size Change Demo") {
+                    AnimatedVisibilityContentSizeChangeDemo()
+                },
                 ComposableDemo("Cross Fade") { CrossfadeDemo() },
                 ComposableDemo("Enter/Exit Transition Demo") { EnterExitTransitionDemo() },
             )
diff --git a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
index d758980..27be5f9 100644
--- a/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
+++ b/compose/animation/animation/src/androidAndroidTest/kotlin/androidx/compose/animation/AnimatedVisibilityTest.kt
@@ -21,6 +21,8 @@
 import androidx.compose.animation.core.tween
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.requiredSize
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -32,6 +34,7 @@
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.test.ExperimentalTestApi
 import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.dp
@@ -275,4 +278,43 @@
             rule.waitForIdle()
         }
     }
+
+    @OptIn(ExperimentalAnimationApi::class)
+    @Test
+    fun animateVisibilityContentSizeChangeTest() {
+        val size = mutableStateOf(40.dp)
+        val testModifier by mutableStateOf(TestModifier())
+        var visible by mutableStateOf(true)
+        rule.setContent {
+            CompositionLocalProvider(LocalDensity provides Density(1f)) {
+                AnimatedVisibility(visible, testModifier) {
+                    Box(modifier = Modifier.size(size = size.value))
+                }
+            }
+        }
+        rule.runOnIdle {
+            assertEquals(40, testModifier.height)
+            assertEquals(40, testModifier.width)
+            size.value = 60.dp
+        }
+        rule.runOnIdle {
+            assertEquals(60, testModifier.height)
+            assertEquals(60, testModifier.width)
+        }
+        rule.runOnIdle {
+            visible = false
+        }
+        rule.runOnIdle {
+            visible = true
+        }
+        rule.runOnIdle {
+            assertEquals(60, testModifier.height)
+            assertEquals(60, testModifier.width)
+            size.value = 30.dp
+        }
+        rule.runOnIdle {
+            assertEquals(30, testModifier.height)
+            assertEquals(30, testModifier.width)
+        }
+    }
 }
diff --git a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
index 0224332..0d2890b7 100644
--- a/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
+++ b/compose/animation/animation/src/commonMain/kotlin/androidx/compose/animation/EnterExitTransition.kt
@@ -18,21 +18,21 @@
 
 import androidx.compose.animation.core.Animatable
 import androidx.compose.animation.core.AnimationEndReason
-import androidx.compose.animation.core.FiniteAnimationSpec
 import androidx.compose.animation.core.AnimationVector2D
+import androidx.compose.animation.core.FiniteAnimationSpec
 import androidx.compose.animation.core.VectorConverter
 import androidx.compose.animation.core.spring
 import androidx.compose.runtime.Immutable
 import androidx.compose.runtime.Stable
 import androidx.compose.ui.Alignment
-import androidx.compose.ui.layout.LayoutModifier
-import androidx.compose.ui.layout.Measurable
-import androidx.compose.ui.layout.MeasureScope
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
 import androidx.compose.ui.draw.clipToBounds
 import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.layout.LayoutModifier
+import androidx.compose.ui.layout.Measurable
 import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.layout.MeasureScope
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.IntOffset
 import androidx.compose.ui.unit.IntSize
@@ -673,6 +673,11 @@
         scope: CoroutineScope,
     ): SizeAnimation
 
+    /**
+     * Returns what the offset will be once the target size is applied.
+     */
+    fun snapTo(target: IntSize, scope: CoroutineScope): IntOffset
+
     val alignment: Alignment
 }
 
@@ -718,6 +723,13 @@
         }
     }
 
+    override fun snapTo(target: IntSize, scope: CoroutineScope): IntOffset {
+        scope.launch {
+            anim.snapTo(target)
+        }
+        return alignment.align(target, target, LayoutDirection.Ltr)
+    }
+
     override val isAnimating: Boolean
         get() = anim.isRunning
 }
@@ -777,6 +789,15 @@
         return this
     }
 
+    override fun snapTo(target: IntSize, scope: CoroutineScope): IntOffset {
+        val targetOffSet = alignment.align(target, target, LayoutDirection.Ltr)
+        scope.launch {
+            offsetAnim.snapTo(targetOffSet)
+            anim.snapTo(target)
+        }
+        return targetOffSet
+    }
+
     override val isAnimating: Boolean
         get() = (anim.isRunning || offsetAnim.isRunning)
 }
@@ -991,6 +1012,11 @@
         sizeAnim?.apply {
             if (state == currentState) {
                 // If no state change, return the current size animation value.
+                if (state == AnimStates.Entering) {
+                    animateTo(fullSize, alignment, fullSize, spring(), scope)
+                } else if (state == AnimStates.Visible) {
+                    return snapTo(fullSize, scope) to fullSize
+                }
                 return offset(fullSize) to size
             }
         }
diff --git a/compose/benchmark-utils/OWNERS b/compose/benchmark-utils/OWNERS
new file mode 100644
index 0000000..305021a
--- /dev/null
+++ b/compose/benchmark-utils/OWNERS
@@ -0,0 +1,2 @@
+pavlis@google.com
+jellefresen@google.com
diff --git a/compose/benchmark-utils/benchmark/build.gradle b/compose/benchmark-utils/benchmark/build.gradle
new file mode 100644
index 0000000..699caad
--- /dev/null
+++ b/compose/benchmark-utils/benchmark/build.gradle
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 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.Publish
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("AndroidXUiPlugin")
+    id("org.jetbrains.kotlin.android")
+    id("androidx.benchmark")
+}
+
+dependencies {
+    kotlinPlugin project(":compose:compiler:compiler")
+
+    androidTestImplementation project(":benchmark:benchmark-junit4")
+    androidTestImplementation project(":compose:benchmark-utils")
+    androidTestImplementation project(":compose:runtime:runtime")
+    androidTestImplementation project(":compose:foundation:foundation-layout")
+    androidTestImplementation(ANDROIDX_TEST_RULES)
+    androidTestImplementation(KOTLIN_STDLIB)
+    androidTestImplementation(KOTLIN_TEST_COMMON)
+    androidTestImplementation(JUNIT)
+}
diff --git a/compose/benchmark-utils/benchmark/src/androidTest/AndroidManifest.xml b/compose/benchmark-utils/benchmark/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..b4b3fae
--- /dev/null
+++ b/compose/benchmark-utils/benchmark/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2021 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"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="androidx.compose.benchmarkutils.benchmark">
+
+    <!--
+      ~ Important: disable debuggable for accurate performance results
+      -->
+    <application
+            android:debuggable="false"
+            tools:replace="android:debuggable">
+        <!-- enable profileableByShell for non-intrusive profiling tools -->
+        <!--suppress AndroidElementNotAllowed -->
+        <profileable android:shell="true"/>
+    </application>
+</manifest>
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/EmptyBenchmark.kt b/compose/benchmark-utils/benchmark/src/androidTest/java/androidx/compose/benchmarkutils/benchmark/EmptyBenchmark.kt
similarity index 88%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/EmptyBenchmark.kt
rename to compose/benchmark-utils/benchmark/src/androidTest/java/androidx/compose/benchmarkutils/benchmark/EmptyBenchmark.kt
index f0d978c..a3ffd44 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/EmptyBenchmark.kt
+++ b/compose/benchmark-utils/benchmark/src/androidTest/java/androidx/compose/benchmarkutils/benchmark/EmptyBenchmark.kt
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 
-package androidx.compose.ui
+package androidx.compose.ui.testutils.benchmark
 
+import androidx.compose.runtime.Composable
+import androidx.compose.testutils.ComposeTestCase
 import androidx.compose.testutils.benchmark.ComposeBenchmarkRule
 import androidx.compose.testutils.benchmark.benchmarkDrawPerf
 import androidx.compose.testutils.benchmark.benchmarkFirstCompose
@@ -23,7 +25,6 @@
 import androidx.compose.testutils.benchmark.benchmarkFirstLayout
 import androidx.compose.testutils.benchmark.benchmarkFirstMeasure
 import androidx.test.filters.LargeTest
-import androidx.ui.integration.test.core.EmptyTestCase
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -62,4 +63,10 @@
     fun draw() {
         benchmarkRule.benchmarkDrawPerf(textCaseFactory)
     }
+}
+
+class EmptyTestCase : ComposeTestCase {
+    @Composable
+    override fun Content() {
+    }
 }
\ No newline at end of file
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/EmptyFirstFastBenchmark.kt b/compose/benchmark-utils/benchmark/src/androidTest/java/androidx/compose/benchmarkutils/benchmark/EmptyFirstFastBenchmark.kt
similarity index 97%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/EmptyFirstFastBenchmark.kt
rename to compose/benchmark-utils/benchmark/src/androidTest/java/androidx/compose/benchmarkutils/benchmark/EmptyFirstFastBenchmark.kt
index 9bc03cd..e5b3694 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/EmptyFirstFastBenchmark.kt
+++ b/compose/benchmark-utils/benchmark/src/androidTest/java/androidx/compose/benchmarkutils/benchmark/EmptyFirstFastBenchmark.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.compose.ui
+package androidx.compose.ui.testutils.benchmark
 
 import androidx.compose.foundation.layout.Box
 import androidx.compose.runtime.Composable
diff --git a/compose/benchmark-utils/benchmark/src/main/AndroidManifest.xml b/compose/benchmark-utils/benchmark/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..2157585
--- /dev/null
+++ b/compose/benchmark-utils/benchmark/src/main/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2021 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.compose.benchmarkutils.benchmark">
+    <application/>
+</manifest>
diff --git a/compose/benchmark-utils/build.gradle b/compose/benchmark-utils/build.gradle
new file mode 100644
index 0000000..a6654e3
--- /dev/null
+++ b/compose/benchmark-utils/build.gradle
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2021 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 androidx.build.AndroidXUiPlugin
+
+import static androidx.build.dependencies.DependenciesKt.*
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("AndroidXUiPlugin")
+    id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+    kotlinPlugin project(":compose:compiler:compiler")
+
+    api("androidx.activity:activity:1.2.0")
+    api(project(":compose:test-utils"))
+    api(project(":benchmark:benchmark-junit4"))
+
+    implementation(KOTLIN_STDLIB_COMMON)
+    implementation(project(":compose:runtime:runtime"))
+    implementation(project(":compose:ui:ui"))
+    implementation(ANDROIDX_TEST_RULES)
+
+    // This has stub APIs for access to legacy Android APIs, so we don't want
+    // any dependency on this module.
+    compileOnly(project(":compose:ui:ui-android-stubs"))
+}
\ No newline at end of file
diff --git a/compose/benchmark-utils/src/androidTest/AndroidManifest.xml b/compose/benchmark-utils/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..6aca4a1
--- /dev/null
+++ b/compose/benchmark-utils/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2021 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.compose.benchmarkutils"/>
diff --git a/compose/benchmark-utils/src/main/AndroidManifest.xml b/compose/benchmark-utils/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..19f27c9
--- /dev/null
+++ b/compose/benchmark-utils/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 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.compose.benchmarkutils"/>
diff --git a/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/AndroidBenchmarkRule.android.kt b/compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/AndroidBenchmarkRule.kt
similarity index 100%
rename from compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/AndroidBenchmarkRule.android.kt
rename to compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/AndroidBenchmarkRule.kt
diff --git a/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/BenchmarkFirstExtensions.android.kt b/compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/BenchmarkFirstExtensions.kt
similarity index 100%
rename from compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/BenchmarkFirstExtensions.android.kt
rename to compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/BenchmarkFirstExtensions.kt
diff --git a/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/BenchmarkHelpers.android.kt b/compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/BenchmarkHelpers.kt
similarity index 91%
rename from compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/BenchmarkHelpers.android.kt
rename to compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/BenchmarkHelpers.kt
index b0e52249..ec3c2e7 100644
--- a/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/BenchmarkHelpers.android.kt
+++ b/compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/BenchmarkHelpers.kt
@@ -16,10 +16,10 @@
 
 package androidx.compose.testutils.benchmark
 
-import android.annotation.TargetApi
 import android.graphics.Picture
 import android.graphics.RenderNode
 import android.os.Build
+import androidx.annotation.RequiresApi
 import androidx.compose.ui.graphics.Canvas
 
 // We must separate the use of RenderNode so that it isn't referenced in any
@@ -31,15 +31,14 @@
 }
 
 fun DrawCapture(): DrawCapture {
-    val supportsRenderNode = Build.VERSION.SDK_INT >= 29
-    return if (supportsRenderNode) {
+    return if (Build.VERSION.SDK_INT >= 29) {
         RenderNodeCapture()
     } else {
         PictureCapture()
     }
 }
 
-@TargetApi(Build.VERSION_CODES.Q)
+@RequiresApi(Build.VERSION_CODES.Q)
 private class RenderNodeCapture : DrawCapture {
     private val renderNode = RenderNode("Test")
 
diff --git a/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/BenchmarksExtensions.android.kt b/compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/BenchmarksExtensions.kt
similarity index 100%
rename from compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/BenchmarksExtensions.android.kt
rename to compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/BenchmarksExtensions.kt
diff --git a/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/ComposeBenchmarkRule.android.kt b/compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/ComposeBenchmarkRule.kt
similarity index 100%
rename from compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/ComposeBenchmarkRule.android.kt
rename to compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/ComposeBenchmarkRule.kt
diff --git a/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/android/AndroidTestCase.android.kt b/compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/android/AndroidTestCase.kt
similarity index 100%
rename from compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/android/AndroidTestCase.android.kt
rename to compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/android/AndroidTestCase.kt
diff --git a/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/android/AndroidTestCaseRunner.android.kt b/compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/android/AndroidTestCaseRunner.kt
similarity index 94%
rename from compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/android/AndroidTestCaseRunner.android.kt
rename to compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/android/AndroidTestCaseRunner.kt
index da23f9e..0376b84 100644
--- a/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/benchmark/android/AndroidTestCaseRunner.android.kt
+++ b/compose/benchmark-utils/src/main/java/androidx/compose/testutils/benchmark/android/AndroidTestCaseRunner.kt
@@ -17,7 +17,6 @@
 package androidx.compose.testutils.benchmark.android
 
 import android.R
-import android.annotation.TargetApi
 import android.app.Activity
 import android.graphics.Canvas
 import android.graphics.Picture
@@ -26,6 +25,7 @@
 import android.util.DisplayMetrics
 import android.view.View
 import android.view.ViewGroup
+import androidx.annotation.RequiresApi
 
 class AndroidTestCaseRunner<T : AndroidTestCase>(
     private val testCaseFactory: () -> T,
@@ -39,11 +39,9 @@
 
     private var view: ViewGroup? = null
 
-    private val supportsRenderNode = Build.VERSION.SDK_INT >= 29
-
     private val screenWithSpec: Int
     private val screenHeightSpec: Int
-    private val capture = if (supportsRenderNode) RenderNodeCapture() else PictureCapture()
+    private val capture = if (Build.VERSION.SDK_INT >= 29) RenderNodeCapture() else PictureCapture()
     private var canvas: Canvas? = null
 
     private var testCase: T? = null
@@ -156,7 +154,7 @@
     fun endRecording()
 }
 
-@TargetApi(Build.VERSION_CODES.Q)
+@RequiresApi(Build.VERSION_CODES.Q)
 private class RenderNodeCapture : DrawCapture {
     private val renderNode = RenderNode("Test")
 
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
index 0ea3fb6..5a3ba82 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/ControlFlowTransformTests.kt
@@ -3135,6 +3135,67 @@
     )
 
     @Test
+    fun testSourceLocationOfCapturingComposableLambdas(): Unit = verifyComposeIrTransform(
+        source = """
+            import androidx.compose.runtime.Composable
+
+            class SomeClass {
+                var a = "Test"
+                fun onCreate() {
+                    setContent {
+                        B(a)
+                        B(a)
+                    }
+                }
+            }
+
+            fun Test() {
+                var a = "Test"
+                setContent {
+                    B(a)
+                    B(a)
+                }
+            }
+        """,
+        extra = """
+            import androidx.compose.runtime.Composable
+
+            fun setContent(block: @Composable () -> Unit) { }
+            @Composable fun B(value: String) { }
+        """,
+        expectedTransformed = """
+            @StabilityInferred(parameters = 0)
+            class SomeClass {
+              var a: String = "Test"
+              fun onCreate() {
+                setContent(composableLambdaInstance(<>, true, "C<B(a)>,<B(a)>:Test.kt") { %composer: Composer?, %changed: Int ->
+                  if (%changed and 0b1011 xor 0b0010 !== 0 || !%composer.skipping) {
+                    B(a, %composer, 0)
+                    B(a, %composer, 0)
+                  } else {
+                    %composer.skipToGroupEnd()
+                  }
+                }
+                )
+              }
+              static val %stable: Int = 8
+            }
+            fun Test() {
+              var a = "Test"
+              setContent(composableLambdaInstance(<>, true, "C<B(a)>,<B(a)>:Test.kt") { %composer: Composer?, %changed: Int ->
+                if (%changed and 0b1011 xor 0b0010 !== 0 || !%composer.skipping) {
+                  B(a, %composer, 0)
+                  B(a, %composer, 0)
+                } else {
+                  %composer.skipToGroupEnd()
+                }
+              }
+              )
+            }
+        """
+    )
+
+    @Test
     fun testSourceLineInformationForNormalInline(): Unit = verifyComposeIrTransform(
         source = """
             import androidx.compose.runtime.Composable
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt
index e44d51e..7e64583 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/LambdaMemoizationTransformTests.kt
@@ -36,7 +36,7 @@
             @StabilityInferred(parameters = 0)
             class A {
               val b: String = ""
-              val c: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, true, "") { %composer: Composer?, %changed: Int ->
+              val c: Function2<Composer, Int, Unit> = composableLambdaInstance(<>, true, "C:") { %composer: Composer?, %changed: Int ->
                 if (%changed and 0b1011 xor 0b0010 !== 0 || !%composer.skipping) {
                   print(b)
                 } else {
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFqNames.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFqNames.kt
index caa79a3..8d87cfc 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFqNames.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeFqNames.kt
@@ -45,6 +45,7 @@
     val ExplicitGroupsComposable = fqNameFor("ExplicitGroupsComposable")
     val NonRestartableComposable = fqNameFor("NonRestartableComposable")
     val composableLambda = internalFqNameFor("composableLambda")
+    val composableLambdaInstance = internalFqNameFor("composableLambdaInstance")
     val remember = fqNameFor("remember")
     val key = fqNameFor("key")
     val StableMarker = fqNameFor("StableMarker")
diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
index 1ff75849..a872344 100644
--- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
+++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt
@@ -2487,21 +2487,26 @@
             }
             expression.isComposableSingletonGetter() -> {
                 // This looks like `ComposableSingletonClass.lambda-123`, which is a static/saved
-                // call of composableLambdaInstance. We want to pass
-                // locations on the top level of the lambda as the startRestartGroup is in the
-                // composable lambda wrapper.
+                // call of composableLambdaInstance. We want to transform the property here now
+                // so the assuptions about the invocation order assumed by source locations is
+                // preserved.
                 val getter = expression.symbol.owner
                 val property = getter.correspondingPropertySymbol?.owner
-                val fieldInitializer = property?.backingField?.initializer?.expression
-                val composableLambdaInstanceCall = fieldInitializer as IrCall
-                val composableLambdaScope = withScope(Scope.ComposableLambdaScope()) {
-                    property.transformChildrenVoid()
-                }
-                if (collectSourceInformation) {
-                    recordSourceParameter(composableLambdaInstanceCall, 2, composableLambdaScope)
-                }
+                property?.transformChildrenVoid()
                 return super.visitCall(expression)
             }
+            collectSourceInformation &&
+                expression.symbol.descriptor.fqNameSafe ==
+                ComposeFqNames.composableLambdaInstance -> {
+                // For calls to `composableLambdaInstance` that are not singletons we introduce a
+                // scope to collect the source locations on the top level of the lambda as the
+                // startRestartGroup is in the composable lambda wrapper.
+                val composableLambdaScope = withScope(Scope.ComposableLambdaScope()) {
+                    expression.transformChildrenVoid()
+                }
+                recordSourceParameter(expression, 2, composableLambdaScope)
+                return expression
+            }
             else -> return super.visitCall(expression)
         }
     }
diff --git a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.jvm.kt b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.jvm.kt
index 385b464..9eae1d7 100644
--- a/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.jvm.kt
+++ b/compose/desktop/desktop/samples/src/jvmMain/kotlin/androidx/compose/desktop/examples/example1/Main.jvm.kt
@@ -70,7 +70,10 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
+import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusOrder
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shadow
@@ -107,6 +110,7 @@
 
 val italicFont = FontFamily(Font("NotoSans-Italic.ttf"))
 
+@OptIn(ExperimentalComposeUiApi::class)
 fun main() {
     Window(title, IntSize(1024, 850)) {
         App()
@@ -169,13 +173,11 @@
     )
 }
 
+@OptIn(ExperimentalComposeUiApi::class)
 @Composable
 private fun ScrollableContent(scrollState: ScrollState) {
     val amount = remember { mutableStateOf(0) }
     val animation = remember { mutableStateOf(true) }
-    val text = remember {
-        mutableStateOf("Hello \uD83E\uDDD1\uD83C\uDFFF\u200D\uD83E\uDDB0\nПривет")
-    }
     Column(Modifier.fillMaxSize().verticalScroll(scrollState)) {
         Text(
             text = "Привет! 你好! Desktop Compose ${amount.value}",
@@ -407,6 +409,10 @@
             label = { Text(text = "Input1") }
         )
 
+        val (focusItem1, focusItem2) = FocusRequester.createRefs()
+        val text = remember {
+            mutableStateOf("Hello \uD83E\uDDD1\uD83C\uDFFF\u200D\uD83E\uDDB0")
+        }
         TextField(
             value = text.value,
             onValueChange = { text.value = it },
@@ -414,6 +420,7 @@
             placeholder = {
                 Text(text = "Important input")
             },
+            maxLines = 1,
             modifier = Modifier.shortcuts {
                 on(Key.MetaLeft + Key.ShiftLeft + Key.Enter) {
                     text.value = "Cleared with shift!"
@@ -421,9 +428,27 @@
                 on(Key.MetaLeft + Key.Enter) {
                     text.value = "Cleared!"
                 }
+            }.focusOrder(focusItem1) {
+                next = focusItem2
             }
         )
 
+        var text2 by remember {
+            val initText = buildString {
+                (1..1000).forEach {
+                    append("$it\n")
+                }
+            }
+            mutableStateOf(initText)
+        }
+        TextField(
+            text2,
+            modifier = Modifier.height(200.dp).focusOrder(focusItem2) {
+                previous = focusItem1
+            },
+            onValueChange = { text2 = it }
+        )
+
         Row {
             Image(
                 imageResource("androidx/compose/desktop/example/circus.jpg"),
diff --git a/compose/foundation/foundation-layout/benchmark/build.gradle b/compose/foundation/foundation-layout/benchmark/build.gradle
index e54e54f..cb7cc0e 100644
--- a/compose/foundation/foundation-layout/benchmark/build.gradle
+++ b/compose/foundation/foundation-layout/benchmark/build.gradle
@@ -33,7 +33,7 @@
     androidTestImplementation project(":compose:foundation:foundation-layout")
     androidTestImplementation project(":compose:material:material")
     androidTestImplementation project(":compose:runtime:runtime")
-    androidTestImplementation project(":compose:test-utils")
+    androidTestImplementation project(":compose:benchmark-utils")
     androidTestImplementation(ANDROIDX_TEST_RULES)
     androidTestImplementation(JUNIT)
     androidTestImplementation(KOTLIN_STDLIB)
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/SpacingBenchmark.kt b/compose/foundation/foundation-layout/benchmark/src/androidTest/java/androidx/compose/foundation/layout/benchmark/SpacingBenchmark.kt
similarity index 98%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/SpacingBenchmark.kt
rename to compose/foundation/foundation-layout/benchmark/src/androidTest/java/androidx/compose/foundation/layout/benchmark/SpacingBenchmark.kt
index 5eae5b2..ca00d7b 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/SpacingBenchmark.kt
+++ b/compose/foundation/foundation-layout/benchmark/src/androidTest/java/androidx/compose/foundation/layout/benchmark/SpacingBenchmark.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.ui.benchmark.test
+package androidx.compose.foundation.layout.benchmark
 
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.calculateEndPadding
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/WithConstraintsBenchmark.kt b/compose/foundation/foundation-layout/benchmark/src/androidTest/java/androidx/compose/foundation/layout/benchmark/WithConstraintsBenchmark.kt
similarity index 96%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/WithConstraintsBenchmark.kt
rename to compose/foundation/foundation-layout/benchmark/src/androidTest/java/androidx/compose/foundation/layout/benchmark/WithConstraintsBenchmark.kt
index b57c79a..79a5adb 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/WithConstraintsBenchmark.kt
+++ b/compose/foundation/foundation-layout/benchmark/src/androidTest/java/androidx/compose/foundation/layout/benchmark/WithConstraintsBenchmark.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.compose.ui
+package androidx.compose.foundation.layout.benchmark
 
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxWithConstraints
@@ -31,6 +31,8 @@
 import androidx.compose.testutils.benchmark.ComposeBenchmarkRule
 import androidx.compose.testutils.benchmark.toggleStateBenchmarkComposeMeasureLayout
 import androidx.compose.testutils.benchmark.toggleStateBenchmarkMeasureLayout
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
 import androidx.compose.ui.layout.Layout
 import androidx.compose.ui.layout.Placeable
 import androidx.compose.ui.unit.Constraints
diff --git a/compose/foundation/foundation-layout/src/androidAndroidTest/kotlin/androidx/compose/foundation/layout/OffsetTest.kt b/compose/foundation/foundation-layout/src/androidAndroidTest/kotlin/androidx/compose/foundation/layout/OffsetTest.kt
index 0e1a1e4..a20f98e 100644
--- a/compose/foundation/foundation-layout/src/androidAndroidTest/kotlin/androidx/compose/foundation/layout/OffsetTest.kt
+++ b/compose/foundation/foundation-layout/src/androidAndroidTest/kotlin/androidx/compose/foundation/layout/OffsetTest.kt
@@ -42,6 +42,7 @@
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Assert
+import org.junit.Assert.assertEquals
 import org.junit.Assume
 import org.junit.Before
 import org.junit.Rule
@@ -51,7 +52,7 @@
 
 @MediumTest
 @RunWith(AndroidJUnit4::class)
-class OffsetTest : LayoutTest() {
+class OffsetTest {
     @get:Rule
     val rule = createComposeRule()
 
@@ -70,7 +71,7 @@
     }
 
     @Test
-    fun offset_positionIsModified() = with(density) {
+    fun offset_positionIsModified() = with(rule.density) {
         val offsetX = 10.dp
         val offsetY = 20.dp
         var positionX = 0
@@ -96,7 +97,7 @@
     }
 
     @Test
-    fun offset_positionIsModified_rtl() = with(density) {
+    fun offset_positionIsModified_rtl() = with(rule.density) {
         val containerWidth = 30.dp
         val boxSize = 1
         val offsetX = 10.dp
@@ -130,7 +131,7 @@
     }
 
     @Test
-    fun absoluteOffset_positionModified() = with(density) {
+    fun absoluteOffset_positionModified() = with(rule.density) {
         val offsetX = 10.dp
         val offsetY = 20.dp
         var positionX = 0
@@ -156,7 +157,7 @@
     }
 
     @Test
-    fun absoluteOffset_positionModified_rtl() = with(density) {
+    fun absoluteOffset_positionModified_rtl() = with(rule.density) {
         val containerWidth = 30.dp
         val boxSize = 1
         val offsetX = 10.dp
@@ -190,7 +191,7 @@
     }
 
     @Test
-    fun offsetPx_positionIsModified() = with(density) {
+    fun offsetPx_positionIsModified() = with(rule.density) {
         val offsetX = 10f
         val offsetY = 20f
         var positionX = 0f
@@ -216,7 +217,7 @@
     }
 
     @Test
-    fun offsetPx_positionIsModified_rtl() = with(density) {
+    fun offsetPx_positionIsModified_rtl() = with(rule.density) {
         val containerWidth = 30.dp
         val boxSize = 1
         val offsetX = 10
@@ -253,7 +254,7 @@
     }
 
     @Test
-    fun absoluteOffsetPx_positionIsModified() = with(density) {
+    fun absoluteOffsetPx_positionIsModified() = with(rule.density) {
         val offsetX = 10
         val offsetY = 20
         var positionX = 0
@@ -279,7 +280,7 @@
     }
 
     @Test
-    fun absoluteOffsetPx_positionIsModified_rtl() = with(density) {
+    fun absoluteOffsetPx_positionIsModified_rtl() = with(rule.density) {
         val containerWidth = 30.dp
         val boxSize = 1
         val offsetX = 10
diff --git a/compose/foundation/foundation-layout/src/androidAndroidTest/kotlin/androidx/compose/foundation/layout/SizeTest.kt b/compose/foundation/foundation-layout/src/androidAndroidTest/kotlin/androidx/compose/foundation/layout/SizeTest.kt
index b463ff2..a7c7475 100644
--- a/compose/foundation/foundation-layout/src/androidAndroidTest/kotlin/androidx/compose/foundation/layout/SizeTest.kt
+++ b/compose/foundation/foundation-layout/src/androidAndroidTest/kotlin/androidx/compose/foundation/layout/SizeTest.kt
@@ -18,11 +18,20 @@
 
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.layout.Layout
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.layout.IntrinsicMeasurable
+import androidx.compose.ui.layout.IntrinsicMeasureScope
 import androidx.compose.ui.layout.LayoutCoordinates
+import androidx.compose.ui.layout.Measurable
+import androidx.compose.ui.layout.MeasurePolicy
+import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.layout.MeasureScope
 import androidx.compose.ui.node.Ref
 import androidx.compose.ui.layout.onGloballyPositioned
 import androidx.compose.ui.layout.positionInParent
@@ -47,6 +56,7 @@
 import org.junit.runner.RunWith
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
+import org.junit.Assert.assertNotEquals
 import java.util.concurrent.CountDownLatch
 import java.util.concurrent.TimeUnit
 import kotlin.math.roundToInt
@@ -1795,4 +1805,150 @@
             childPosition.value
         )
     }
+
+    @Test
+    fun testModifiers_doNotCauseUnnecessaryRemeasure() {
+        var first by mutableStateOf(true)
+        var totalMeasures = 0
+        @Composable fun CountMeasures(modifier: Modifier) {
+            Layout(
+                content = {},
+                modifier = modifier,
+                measurePolicy = { _, _ ->
+                    ++totalMeasures
+                    layout(0, 0) {}
+                }
+            )
+        }
+        show {
+            Box {
+                if (first) Box {} else Row {}
+                CountMeasures(Modifier.size(10.dp))
+                CountMeasures(Modifier.requiredSize(10.dp))
+                CountMeasures(Modifier.wrapContentSize(Alignment.BottomEnd))
+                CountMeasures(Modifier.fillMaxSize(0.8f))
+                CountMeasures(Modifier.defaultMinSize(10.dp, 20.dp))
+            }
+        }
+
+        val root = findComposeView()
+        waitForDraw(root)
+
+        activityTestRule.runOnUiThread {
+            assertEquals(5, totalMeasures)
+            first = false
+        }
+
+        activityTestRule.runOnUiThread {
+            assertEquals(5, totalMeasures)
+        }
+    }
+
+    @Test
+    fun testModifiers_equals() {
+        assertEquals(Modifier.size(10.dp, 20.dp), Modifier.size(10.dp, 20.dp))
+        assertEquals(Modifier.requiredSize(10.dp, 20.dp), Modifier.requiredSize(10.dp, 20.dp))
+        assertEquals(
+            Modifier.wrapContentSize(Alignment.BottomEnd),
+            Modifier.wrapContentSize(Alignment.BottomEnd)
+        )
+        assertEquals(Modifier.fillMaxSize(0.8f), Modifier.fillMaxSize(0.8f))
+        assertEquals(Modifier.defaultMinSize(10.dp, 20.dp), Modifier.defaultMinSize(10.dp, 20.dp))
+
+        assertNotEquals(Modifier.size(10.dp, 20.dp), Modifier.size(20.dp, 10.dp))
+        assertNotEquals(Modifier.requiredSize(10.dp, 20.dp), Modifier.requiredSize(20.dp, 10.dp))
+        assertNotEquals(
+            Modifier.wrapContentSize(Alignment.BottomEnd),
+            Modifier.wrapContentSize(Alignment.BottomCenter)
+        )
+        assertNotEquals(Modifier.fillMaxSize(0.8f), Modifier.fillMaxSize())
+        assertNotEquals(
+            Modifier.defaultMinSize(10.dp, 20.dp),
+            Modifier.defaultMinSize(20.dp, 10.dp)
+        )
+    }
+
+    @Test
+    fun testIntrinsicMeasurements_notQueriedWhenConstraintsAreFixed() {
+        @Composable fun ErrorIntrinsicsLayout(modifier: Modifier) {
+            Layout(
+                {},
+                modifier,
+                object : MeasurePolicy {
+                    override fun MeasureScope.measure(
+                        measurables: List<Measurable>,
+                        constraints: Constraints
+                    ): MeasureResult {
+                        return layout(0, 0) {}
+                    }
+
+                    override fun IntrinsicMeasureScope.minIntrinsicWidth(
+                        measurables: List<IntrinsicMeasurable>,
+                        height: Int
+                    ) = error("Error intrinsic")
+
+                    override fun IntrinsicMeasureScope.minIntrinsicHeight(
+                        measurables: List<IntrinsicMeasurable>,
+                        width: Int
+                    ) = error("Error intrinsic")
+
+                    override fun IntrinsicMeasureScope.maxIntrinsicWidth(
+                        measurables: List<IntrinsicMeasurable>,
+                        height: Int
+                    ) = error("Error intrinsic")
+
+                    override fun IntrinsicMeasureScope.maxIntrinsicHeight(
+                        measurables: List<IntrinsicMeasurable>,
+                        width: Int
+                    ) = error("Error intrinsic")
+                }
+            )
+        }
+
+        show {
+            Box(Modifier.width(IntrinsicSize.Min)) { ErrorIntrinsicsLayout(Modifier.width(1.dp)) }
+            Box(Modifier.width(IntrinsicSize.Min)) {
+                ErrorIntrinsicsLayout(Modifier.width(1.dp))
+            }
+            Box(Modifier.width(IntrinsicSize.Max)) { ErrorIntrinsicsLayout(Modifier.width(1.dp)) }
+            Box(Modifier.width(IntrinsicSize.Max)) {
+                ErrorIntrinsicsLayout(Modifier.width(1.dp))
+            }
+            Box(Modifier.requiredWidth(IntrinsicSize.Min)) {
+                ErrorIntrinsicsLayout(Modifier.width(1.dp))
+            }
+            Box(Modifier.requiredWidth(IntrinsicSize.Min)) {
+                ErrorIntrinsicsLayout(Modifier.width(1.dp))
+            }
+            Box(Modifier.requiredWidth(IntrinsicSize.Max)) {
+                ErrorIntrinsicsLayout(Modifier.width(1.dp))
+            }
+            Box(Modifier.requiredWidth(IntrinsicSize.Max)) {
+                ErrorIntrinsicsLayout(Modifier.width(1.dp))
+            }
+            Box(Modifier.height(IntrinsicSize.Min)) { ErrorIntrinsicsLayout(Modifier.height(1.dp)) }
+            Box(Modifier.height(IntrinsicSize.Min)) {
+                ErrorIntrinsicsLayout(Modifier.height(1.dp))
+            }
+            Box(Modifier.height(IntrinsicSize.Max)) { ErrorIntrinsicsLayout(Modifier.height(1.dp)) }
+            Box(Modifier.height(IntrinsicSize.Max)) {
+                ErrorIntrinsicsLayout(Modifier.height(1.dp))
+            }
+            Box(Modifier.requiredHeight(IntrinsicSize.Min)) {
+                ErrorIntrinsicsLayout(Modifier.height(1.dp))
+            }
+            Box(Modifier.requiredHeight(IntrinsicSize.Min)) {
+                ErrorIntrinsicsLayout(Modifier.height(1.dp))
+            }
+            Box(Modifier.requiredHeight(IntrinsicSize.Max)) {
+                ErrorIntrinsicsLayout(Modifier.height(1.dp))
+            }
+            Box(Modifier.requiredHeight(IntrinsicSize.Max)) {
+                ErrorIntrinsicsLayout(Modifier.height(1.dp))
+            }
+        }
+        // The test tests that the measure pass should not crash.
+        val root = findComposeView()
+        waitForDraw(root)
+    }
 }
\ No newline at end of file
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Offset.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Offset.kt
index d66f654..99fbe46 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Offset.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Offset.kt
@@ -35,7 +35,10 @@
  * Offset the content by ([x] dp, [y] dp). The offsets can be positive as well as non-positive.
  * Applying an offset only changes the position of the content, without interfering with
  * its size measurement.
- * This modifier will automatically adjust the horizontal offset according to the layout direction.
+ *
+ * This modifier will automatically adjust the horizontal offset according to the layout direction:
+ * when the layout direction is LTR, positive [x] offsets will move the content to the right and
+ * when the layout direction is RTL, positive [x] offsets will move the content to the left.
  * For a modifier that offsets without considering layout direction, see [absoluteOffset].
  *
  * @see absoluteOffset
@@ -61,8 +64,10 @@
  * Offset the content by ([x] dp, [y] dp). The offsets can be positive as well as non-positive.
  * Applying an offset only changes the position of the content, without interfering with
  * its size measurement.
- * This modifier will not consider layout direction when calculating the position of the content.
- * For a modifier that does this, see [offset].
+ *
+ * This modifier will not consider layout direction when calculating the position of the content:
+ * a positive [x] offset will always move the content to the right.
+ * For a modifier that considers the layout direction when applying the offset, see [offset].
  *
  * @see offset
  *
@@ -87,11 +92,13 @@
  * Offset the content by [offset] px. The offsets can be positive as well as non-positive.
  * Applying an offset only changes the position of the content, without interfering with
  * its size measurement.
+ *
  * This modifier is designed to be used for offsets that change, possibly due to user interactions,
  * the advantage being that it avoids recomposition when the offset is changing.
- * Note that, even if for convenience the API is accepting [Float] values, these will be rounded
- * to the closest integer value before applying the offset.
- * This modifier will automatically adjust the horizontal offset according to the layout direction.
+ *
+ * This modifier will automatically adjust the horizontal offset according to the layout direction:
+ * when the LD is LTR, positive horizontal offsets will move the content to the right and
+ * when the LD is RTL, positive horizontal offsets will move the content to the left.
  * For a modifier that offsets without considering layout direction, see [absoluteOffset].
  *
  * @see [absoluteOffset]
@@ -114,12 +121,13 @@
  * Offset the content by [offset] px. The offsets can be positive as well as non-positive.
  * Applying an offset only changes the position of the content, without interfering with
  * its size measurement.
+ *
  * This modifier is designed to be used for offsets that change, possibly due to user interactions,
  * the advantage being that it avoids recomposition when the offset is changing.
- * Note that, even if for convenience the API is accepting [Float] values, these will be rounded
- * to the closest integer value before applying the offset.
- * This modifier will not consider layout direction when calculating the position of the content.
- * For a modifier that does this, see [offset].
+ *
+ * This modifier will not consider layout direction when calculating the position of the content:
+ * a positive horizontal offset will always move the content to the right.
+ * For a modifier that considers layout direction when applying the offset, see [offset].
  *
  * @see offset
  *
diff --git a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Size.kt b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Size.kt
index af08e02..4c4bebc 100644
--- a/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Size.kt
+++ b/compose/foundation/foundation-layout/src/commonMain/kotlin/androidx/compose/foundation/layout/Size.kt
@@ -518,6 +518,7 @@
         alignmentCallback = { size, layoutDirection ->
             IntOffset(align.align(0, size.width, layoutDirection), 0)
         },
+        align,
         inspectorInfo = debugInspectorInfo {
             name = "wrapContentWidth"
             properties["align"] = align
@@ -549,6 +550,7 @@
         alignmentCallback = { size, _ ->
             IntOffset(0, align.align(0, size.height))
         },
+        align,
         inspectorInfo = debugInspectorInfo {
             name = "wrapContentHeight"
             properties["align"] = align
@@ -579,6 +581,7 @@
         alignmentCallback = { size, layoutDirection ->
             align.align(IntSize.Zero, size, layoutDirection)
         },
+        align,
         inspectorInfo = debugInspectorInfo {
             name = "wrapContentSize"
             properties["align"] = align
@@ -652,6 +655,11 @@
             placeable.placeRelative(0, 0)
         }
     }
+
+    override fun equals(other: Any?) =
+        other is FillModifier && direction == other.direction && scale == other.scale
+
+    override fun hashCode() = direction.hashCode() * 31 + scale.hashCode()
 }
 
 private class SizeModifier(
@@ -720,40 +728,74 @@
     override fun IntrinsicMeasureScope.minIntrinsicWidth(
         measurable: IntrinsicMeasurable,
         height: Int
-    ) = measurable.minIntrinsicWidth(height).let {
+    ): Int {
         val constraints = targetConstraints
-        constraints.constrainWidth(it)
-    }
-
-    override fun IntrinsicMeasureScope.maxIntrinsicWidth(
-        measurable: IntrinsicMeasurable,
-        height: Int
-    ) = measurable.maxIntrinsicWidth(height).let {
-        val constraints = targetConstraints
-        constraints.constrainWidth(it)
+        return if (constraints.hasFixedWidth) {
+            constraints.maxWidth
+        } else {
+            constraints.constrainWidth(measurable.minIntrinsicWidth(height))
+        }
     }
 
     override fun IntrinsicMeasureScope.minIntrinsicHeight(
         measurable: IntrinsicMeasurable,
         width: Int
-    ) = measurable.minIntrinsicHeight(width).let {
+    ): Int {
         val constraints = targetConstraints
-        constraints.constrainHeight(it)
+        return if (constraints.hasFixedHeight) {
+            constraints.maxHeight
+        } else {
+            constraints.constrainHeight(measurable.minIntrinsicHeight(width))
+        }
+    }
+
+    override fun IntrinsicMeasureScope.maxIntrinsicWidth(
+        measurable: IntrinsicMeasurable,
+        height: Int
+    ): Int {
+        val constraints = targetConstraints
+        return if (constraints.hasFixedWidth) {
+            constraints.maxWidth
+        } else {
+            constraints.constrainWidth(measurable.maxIntrinsicWidth(height))
+        }
     }
 
     override fun IntrinsicMeasureScope.maxIntrinsicHeight(
         measurable: IntrinsicMeasurable,
         width: Int
-    ) = measurable.maxIntrinsicHeight(width).let {
+    ): Int {
         val constraints = targetConstraints
-        constraints.constrainHeight(it)
+        return if (constraints.hasFixedHeight) {
+            constraints.maxHeight
+        } else {
+            constraints.constrainHeight(measurable.maxIntrinsicHeight(width))
+        }
     }
+
+    override fun equals(other: Any?): Boolean {
+        if (other !is SizeModifier) return false
+        return minWidth == other.minWidth &&
+            minHeight == other.minHeight &&
+            maxWidth == other.maxWidth &&
+            maxHeight == other.maxHeight &&
+            enforceIncoming == other.enforceIncoming
+    }
+
+    override fun hashCode() =
+        (
+            (
+                (((minWidth.hashCode() * 31 + minHeight.hashCode()) * 31) + maxWidth.hashCode()) *
+                    31
+                ) + maxHeight.hashCode()
+            ) * 31
 }
 
 private class WrapContentModifier(
     private val direction: Direction,
     private val unbounded: Boolean,
     private val alignmentCallback: (IntSize, LayoutDirection) -> IntOffset,
+    private val align: Any, // only used for equals and hashcode
     inspectorInfo: InspectorInfo.() -> Unit
 ) : LayoutModifier, InspectorValueInfo(inspectorInfo) {
     override fun MeasureScope.measure(
@@ -788,6 +830,14 @@
             placeable.place(position)
         }
     }
+
+    override fun equals(other: Any?): Boolean {
+        if (other !is WrapContentModifier) return false
+        return direction == other.direction && unbounded == other.unbounded && align == other.align
+    }
+
+    override fun hashCode() =
+        (direction.hashCode() * 31 + unbounded.hashCode()) * 31 + align.hashCode()
 }
 
 private class UnspecifiedConstraintsModifier(
@@ -846,6 +896,13 @@
     ) = measurable.maxIntrinsicHeight(width).coerceAtLeast(
         if (minHeight != Dp.Unspecified) minHeight.roundToPx() else 0
     )
+
+    override fun equals(other: Any?): Boolean {
+        if (other !is UnspecifiedConstraintsModifier) return false
+        return minWidth == other.minWidth && minHeight == other.minHeight
+    }
+
+    override fun hashCode() = minWidth.hashCode() * 31 + minHeight.hashCode()
 }
 
 internal enum class Direction {
diff --git a/compose/foundation/foundation/api/1.0.0-beta02.txt b/compose/foundation/foundation/api/1.0.0-beta02.txt
index 132be90..76b8d5b 100644
--- a/compose/foundation/foundation/api/1.0.0-beta02.txt
+++ b/compose/foundation/foundation/api/1.0.0-beta02.txt
@@ -558,9 +558,6 @@
 
 package androidx.compose.foundation.text {
 
-  public final class AndroidCoreTextField_androidKt {
-  }
-
   public final class BasicTextFieldKt {
     method @androidx.compose.runtime.Composable public static void BasicTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
     method @androidx.compose.runtime.Composable public static void BasicTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
@@ -593,6 +590,12 @@
     method public static void appendInlineContent(androidx.compose.ui.text.AnnotatedString.Builder, String id, optional String alternateText);
   }
 
+  public final class KeyMappingKt {
+  }
+
+  public final class KeyMapping_androidKt {
+  }
+
   public interface KeyboardActionScope {
     method public void defaultKeyboardAction(androidx.compose.ui.text.input.ImeAction imeAction);
   }
@@ -645,6 +648,9 @@
   public final class MaxLinesHeightModifierKt {
   }
 
+  public final class StringHelpers_jvmKt {
+  }
+
   public final class TextFieldCursorKt {
   }
 
@@ -654,6 +660,12 @@
   public final class TextFieldGestureModifiersKt {
   }
 
+  public final class TextFieldKeyInputKt {
+  }
+
+  public final class TextFieldKeyInput_androidKt {
+  }
+
   public final class TextFieldPressGestureFilterKt {
   }
 
@@ -705,6 +717,9 @@
   public final class TextFieldSelectionManagerKt {
   }
 
+  public final class TextFieldSelectionManager_androidKt {
+  }
+
   @androidx.compose.runtime.Immutable public final class TextSelectionColors {
     method public long getBackgroundColor-0d7_KjU();
     method public long getHandleColor-0d7_KjU();
diff --git a/compose/foundation/foundation/api/current.txt b/compose/foundation/foundation/api/current.txt
index 132be90..76b8d5b 100644
--- a/compose/foundation/foundation/api/current.txt
+++ b/compose/foundation/foundation/api/current.txt
@@ -558,9 +558,6 @@
 
 package androidx.compose.foundation.text {
 
-  public final class AndroidCoreTextField_androidKt {
-  }
-
   public final class BasicTextFieldKt {
     method @androidx.compose.runtime.Composable public static void BasicTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
     method @androidx.compose.runtime.Composable public static void BasicTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
@@ -593,6 +590,12 @@
     method public static void appendInlineContent(androidx.compose.ui.text.AnnotatedString.Builder, String id, optional String alternateText);
   }
 
+  public final class KeyMappingKt {
+  }
+
+  public final class KeyMapping_androidKt {
+  }
+
   public interface KeyboardActionScope {
     method public void defaultKeyboardAction(androidx.compose.ui.text.input.ImeAction imeAction);
   }
@@ -645,6 +648,9 @@
   public final class MaxLinesHeightModifierKt {
   }
 
+  public final class StringHelpers_jvmKt {
+  }
+
   public final class TextFieldCursorKt {
   }
 
@@ -654,6 +660,12 @@
   public final class TextFieldGestureModifiersKt {
   }
 
+  public final class TextFieldKeyInputKt {
+  }
+
+  public final class TextFieldKeyInput_androidKt {
+  }
+
   public final class TextFieldPressGestureFilterKt {
   }
 
@@ -705,6 +717,9 @@
   public final class TextFieldSelectionManagerKt {
   }
 
+  public final class TextFieldSelectionManager_androidKt {
+  }
+
   @androidx.compose.runtime.Immutable public final class TextSelectionColors {
     method public long getBackgroundColor-0d7_KjU();
     method public long getHandleColor-0d7_KjU();
diff --git a/compose/foundation/foundation/api/public_plus_experimental_1.0.0-beta02.txt b/compose/foundation/foundation/api/public_plus_experimental_1.0.0-beta02.txt
index 0fac70c..058fea0 100644
--- a/compose/foundation/foundation/api/public_plus_experimental_1.0.0-beta02.txt
+++ b/compose/foundation/foundation/api/public_plus_experimental_1.0.0-beta02.txt
@@ -591,9 +591,6 @@
 
 package androidx.compose.foundation.text {
 
-  public final class AndroidCoreTextField_androidKt {
-  }
-
   public final class BasicTextFieldKt {
     method @androidx.compose.runtime.Composable public static void BasicTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
     method @androidx.compose.runtime.Composable public static void BasicTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
@@ -629,6 +626,12 @@
   @kotlin.RequiresOptIn(message="Internal/Unstable API for use only between foundation modules sharing " + "the same exact version, subject to change without notice.") @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface InternalFoundationTextApi {
   }
 
+  public final class KeyMappingKt {
+  }
+
+  public final class KeyMapping_androidKt {
+  }
+
   public interface KeyboardActionScope {
     method public void defaultKeyboardAction(androidx.compose.ui.text.input.ImeAction imeAction);
   }
@@ -681,6 +684,9 @@
   public final class MaxLinesHeightModifierKt {
   }
 
+  public final class StringHelpers_jvmKt {
+  }
+
   public final class TextFieldCursorKt {
   }
 
@@ -690,6 +696,12 @@
   public final class TextFieldGestureModifiersKt {
   }
 
+  public final class TextFieldKeyInputKt {
+  }
+
+  public final class TextFieldKeyInput_androidKt {
+  }
+
   public final class TextFieldPressGestureFilterKt {
   }
 
@@ -741,6 +753,9 @@
   public final class TextFieldSelectionManagerKt {
   }
 
+  public final class TextFieldSelectionManager_androidKt {
+  }
+
   @androidx.compose.runtime.Immutable public final class TextSelectionColors {
     method public long getBackgroundColor-0d7_KjU();
     method public long getHandleColor-0d7_KjU();
diff --git a/compose/foundation/foundation/api/public_plus_experimental_current.txt b/compose/foundation/foundation/api/public_plus_experimental_current.txt
index 0fac70c..058fea0 100644
--- a/compose/foundation/foundation/api/public_plus_experimental_current.txt
+++ b/compose/foundation/foundation/api/public_plus_experimental_current.txt
@@ -591,9 +591,6 @@
 
 package androidx.compose.foundation.text {
 
-  public final class AndroidCoreTextField_androidKt {
-  }
-
   public final class BasicTextFieldKt {
     method @androidx.compose.runtime.Composable public static void BasicTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
     method @androidx.compose.runtime.Composable public static void BasicTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
@@ -629,6 +626,12 @@
   @kotlin.RequiresOptIn(message="Internal/Unstable API for use only between foundation modules sharing " + "the same exact version, subject to change without notice.") @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface InternalFoundationTextApi {
   }
 
+  public final class KeyMappingKt {
+  }
+
+  public final class KeyMapping_androidKt {
+  }
+
   public interface KeyboardActionScope {
     method public void defaultKeyboardAction(androidx.compose.ui.text.input.ImeAction imeAction);
   }
@@ -681,6 +684,9 @@
   public final class MaxLinesHeightModifierKt {
   }
 
+  public final class StringHelpers_jvmKt {
+  }
+
   public final class TextFieldCursorKt {
   }
 
@@ -690,6 +696,12 @@
   public final class TextFieldGestureModifiersKt {
   }
 
+  public final class TextFieldKeyInputKt {
+  }
+
+  public final class TextFieldKeyInput_androidKt {
+  }
+
   public final class TextFieldPressGestureFilterKt {
   }
 
@@ -741,6 +753,9 @@
   public final class TextFieldSelectionManagerKt {
   }
 
+  public final class TextFieldSelectionManager_androidKt {
+  }
+
   @androidx.compose.runtime.Immutable public final class TextSelectionColors {
     method public long getBackgroundColor-0d7_KjU();
     method public long getHandleColor-0d7_KjU();
diff --git a/compose/foundation/foundation/api/restricted_1.0.0-beta02.txt b/compose/foundation/foundation/api/restricted_1.0.0-beta02.txt
index 132be90..76b8d5b 100644
--- a/compose/foundation/foundation/api/restricted_1.0.0-beta02.txt
+++ b/compose/foundation/foundation/api/restricted_1.0.0-beta02.txt
@@ -558,9 +558,6 @@
 
 package androidx.compose.foundation.text {
 
-  public final class AndroidCoreTextField_androidKt {
-  }
-
   public final class BasicTextFieldKt {
     method @androidx.compose.runtime.Composable public static void BasicTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
     method @androidx.compose.runtime.Composable public static void BasicTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
@@ -593,6 +590,12 @@
     method public static void appendInlineContent(androidx.compose.ui.text.AnnotatedString.Builder, String id, optional String alternateText);
   }
 
+  public final class KeyMappingKt {
+  }
+
+  public final class KeyMapping_androidKt {
+  }
+
   public interface KeyboardActionScope {
     method public void defaultKeyboardAction(androidx.compose.ui.text.input.ImeAction imeAction);
   }
@@ -645,6 +648,9 @@
   public final class MaxLinesHeightModifierKt {
   }
 
+  public final class StringHelpers_jvmKt {
+  }
+
   public final class TextFieldCursorKt {
   }
 
@@ -654,6 +660,12 @@
   public final class TextFieldGestureModifiersKt {
   }
 
+  public final class TextFieldKeyInputKt {
+  }
+
+  public final class TextFieldKeyInput_androidKt {
+  }
+
   public final class TextFieldPressGestureFilterKt {
   }
 
@@ -705,6 +717,9 @@
   public final class TextFieldSelectionManagerKt {
   }
 
+  public final class TextFieldSelectionManager_androidKt {
+  }
+
   @androidx.compose.runtime.Immutable public final class TextSelectionColors {
     method public long getBackgroundColor-0d7_KjU();
     method public long getHandleColor-0d7_KjU();
diff --git a/compose/foundation/foundation/api/restricted_current.txt b/compose/foundation/foundation/api/restricted_current.txt
index 132be90..76b8d5b 100644
--- a/compose/foundation/foundation/api/restricted_current.txt
+++ b/compose/foundation/foundation/api/restricted_current.txt
@@ -558,9 +558,6 @@
 
 package androidx.compose.foundation.text {
 
-  public final class AndroidCoreTextField_androidKt {
-  }
-
   public final class BasicTextFieldKt {
     method @androidx.compose.runtime.Composable public static void BasicTextField(String value, kotlin.jvm.functions.Function1<? super java.lang.String,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
     method @androidx.compose.runtime.Composable public static void BasicTextField(androidx.compose.ui.text.input.TextFieldValue value, kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.input.TextFieldValue,kotlin.Unit> onValueChange, optional androidx.compose.ui.Modifier modifier, optional boolean enabled, optional boolean readOnly, optional androidx.compose.ui.text.TextStyle textStyle, optional androidx.compose.foundation.text.KeyboardOptions keyboardOptions, optional androidx.compose.foundation.text.KeyboardActions keyboardActions, optional boolean singleLine, optional int maxLines, optional androidx.compose.ui.text.input.VisualTransformation visualTransformation, optional kotlin.jvm.functions.Function1<? super androidx.compose.ui.text.TextLayoutResult,kotlin.Unit> onTextLayout, optional androidx.compose.foundation.interaction.MutableInteractionSource interactionSource, optional androidx.compose.ui.graphics.Brush cursorBrush, optional kotlin.jvm.functions.Function1<? super kotlin.jvm.functions.Function0<kotlin.Unit>,kotlin.Unit> decorationBox);
@@ -593,6 +590,12 @@
     method public static void appendInlineContent(androidx.compose.ui.text.AnnotatedString.Builder, String id, optional String alternateText);
   }
 
+  public final class KeyMappingKt {
+  }
+
+  public final class KeyMapping_androidKt {
+  }
+
   public interface KeyboardActionScope {
     method public void defaultKeyboardAction(androidx.compose.ui.text.input.ImeAction imeAction);
   }
@@ -645,6 +648,9 @@
   public final class MaxLinesHeightModifierKt {
   }
 
+  public final class StringHelpers_jvmKt {
+  }
+
   public final class TextFieldCursorKt {
   }
 
@@ -654,6 +660,12 @@
   public final class TextFieldGestureModifiersKt {
   }
 
+  public final class TextFieldKeyInputKt {
+  }
+
+  public final class TextFieldKeyInput_androidKt {
+  }
+
   public final class TextFieldPressGestureFilterKt {
   }
 
@@ -705,6 +717,9 @@
   public final class TextFieldSelectionManagerKt {
   }
 
+  public final class TextFieldSelectionManager_androidKt {
+  }
+
   @androidx.compose.runtime.Immutable public final class TextSelectionColors {
     method public long getBackgroundColor-0d7_KjU();
     method public long getHandleColor-0d7_KjU();
diff --git a/compose/foundation/foundation/benchmark/build.gradle b/compose/foundation/foundation/benchmark/build.gradle
index 53d7b59..36498ab 100644
--- a/compose/foundation/foundation/benchmark/build.gradle
+++ b/compose/foundation/foundation/benchmark/build.gradle
@@ -35,7 +35,7 @@
     androidTestImplementation project(":compose:foundation:foundation-layout")
     androidTestImplementation project(":compose:foundation:foundation")
     androidTestImplementation project(":compose:material:material")
-    androidTestImplementation project(":compose:test-utils")
+    androidTestImplementation project(":compose:benchmark-utils")
     androidTestImplementation(ANDROIDX_TEST_RULES)
     androidTestImplementation(JUNIT)
     androidTestImplementation(KOTLIN_STDLIB)
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/SimpleComponentImplementationBenchmark.kt b/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/SimpleComponentImplementationBenchmark.kt
similarity index 67%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/SimpleComponentImplementationBenchmark.kt
rename to compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/SimpleComponentImplementationBenchmark.kt
index 1c175f4..0e9330f 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/SimpleComponentImplementationBenchmark.kt
+++ b/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/SimpleComponentImplementationBenchmark.kt
@@ -14,8 +14,22 @@
  * limitations under the License.
  */
 
-package androidx.ui.benchmark.test
+package androidx.compose.foundation.benchmark
 
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.testutils.ComposeTestCase
+import androidx.compose.testutils.ToggleableTestCase
 import androidx.compose.testutils.benchmark.ComposeBenchmarkRule
 import androidx.compose.testutils.benchmark.benchmarkDrawPerf
 import androidx.compose.testutils.benchmark.benchmarkFirstCompose
@@ -27,14 +41,18 @@
 import androidx.compose.testutils.benchmark.toggleStateBenchmarkLayout
 import androidx.compose.testutils.benchmark.toggleStateBenchmarkMeasure
 import androidx.compose.testutils.benchmark.toggleStateBenchmarkRecompose
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.drawOutline
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
-import androidx.ui.integration.test.core.ComponentWithTwoLayoutNodesTestCase
-import androidx.ui.integration.test.core.ComponentWithRedrawTestCase
-import androidx.ui.integration.test.core.ComponentWithModifiersTestCase
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import androidx.test.ext.junit.runners.AndroidJUnit4
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
@@ -209,3 +227,77 @@
         benchmarkRule.benchmarkDrawPerf(modifiersOnlyCaseFactory)
     }
 }
+
+class ComponentWithModifiersTestCase : SimpleComponentImplementationTestCase() {
+
+    @Composable
+    override fun Content() {
+        val innerSize = getInnerSize()
+        Box(
+            Modifier.size(48.dp)
+                .background(color = Color.Cyan)
+                .padding(innerSize.value)
+                .border(
+                    color = Color.Cyan,
+                    width = 1.dp,
+                    shape = CircleShape
+                )
+        )
+    }
+}
+
+class ComponentWithRedrawTestCase : SimpleComponentImplementationTestCase() {
+
+    @Composable
+    override fun Content() {
+        val innerSize = getInnerSize()
+        val stroke = Stroke()
+        Canvas(Modifier.size(48.dp)) {
+            drawCircle(Color.Black, size.minDimension, style = stroke)
+            drawCircle(Color.Black, innerSize.value.value / 2f, center)
+        }
+    }
+}
+
+class ComponentWithTwoLayoutNodesTestCase : SimpleComponentImplementationTestCase() {
+    @Composable
+    override fun Content() {
+        Box(
+            modifier = Modifier
+                .size(48.dp)
+                .border(BorderStroke(1.dp, Color.Cyan), CircleShape)
+                .padding(1.dp),
+            contentAlignment = Alignment.Center
+        ) {
+            val innerSize = getInnerSize().value
+            Canvas(Modifier.size(innerSize)) {
+                drawOutline(
+                    CircleShape.createOutline(size, layoutDirection, this),
+                    Color.Cyan
+                )
+            }
+        }
+    }
+}
+
+abstract class SimpleComponentImplementationTestCase : ComposeTestCase, ToggleableTestCase {
+
+    private var state: MutableState<Dp>? = null
+
+    @Composable
+    fun getInnerSize(): MutableState<Dp> {
+        val innerSize = remember { mutableStateOf(10.dp) }
+        state = innerSize
+        return innerSize
+    }
+
+    override fun toggleState() {
+        with(state!!) {
+            value = if (value == 10.dp) {
+                20.dp
+            } else {
+                10.dp
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/TrailingLambdaBenchmark.kt b/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/TrailingLambdaBenchmark.kt
similarity index 98%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/TrailingLambdaBenchmark.kt
rename to compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/TrailingLambdaBenchmark.kt
index cfa8133..335d283 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/TrailingLambdaBenchmark.kt
+++ b/compose/foundation/foundation/benchmark/src/androidTest/java/androidx/compose/foundation/benchmark/TrailingLambdaBenchmark.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.ui.benchmark.test
+package androidx.compose.foundation.benchmark
 
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
diff --git a/compose/foundation/foundation/build.gradle b/compose/foundation/foundation/build.gradle
index c96540c..e991a27 100644
--- a/compose/foundation/foundation/build.gradle
+++ b/compose/foundation/foundation/build.gradle
@@ -102,6 +102,8 @@
                 api("androidx.annotation:annotation:1.1.0")
             }
 
+            desktopMain.dependsOn(jvmMain)
+
             desktopMain.dependencies {
                 implementation(KOTLIN_STDLIB)
             }
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/HardwareKeyboardTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/HardwareKeyboardTest.kt
new file mode 100644
index 0000000..db16b94
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/textfield/HardwareKeyboardTest.kt
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2021 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.compose.foundation.textfield
+
+import android.view.KeyEvent
+import android.view.KeyEvent.META_CTRL_ON
+import android.view.KeyEvent.META_SHIFT_ON
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.text.BasicTextField
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.input.key.nativeKeyCode
+import androidx.compose.ui.platform.LocalTextInputService
+import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.hasSetTextAction
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.performKeyPress
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.text.input.TextInputService
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.google.common.truth.Truth
+import com.nhaarman.mockitokotlin2.mock
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalFoundationApi::class)
+class HardwareKeyboardTest {
+    @get:Rule
+    val rule = createComposeRule()
+
+    @Test
+    fun textField_typedEvents() {
+        keysSequenceTest {
+            Key.H.downAndUp()
+            Key.I.downAndUp(META_SHIFT_ON)
+            expectedText("hI")
+        }
+    }
+
+    @Test
+    fun textField_copyPaste() {
+        keysSequenceTest(initText = "hello") {
+            Key.A.downAndUp(META_CTRL_ON)
+            Key.C.downAndUp(META_CTRL_ON)
+            Key.DirectionRight.downAndUp()
+            Key.Spacebar.downAndUp()
+            Key.V.downAndUp(META_CTRL_ON)
+            expectedText("hello hello")
+        }
+    }
+
+    @Test
+    fun textField_linesNavigation() {
+        keysSequenceTest(initText = "hello\nworld") {
+            Key.DirectionDown.downAndUp()
+            Key.Zero.downAndUp()
+            Key.DirectionUp.downAndUp()
+            Key.Zero.downAndUp()
+            expectedText("h0ello\n0world")
+            Key.DirectionUp.downAndUp()
+            Key.Zero.downAndUp()
+            expectedText("0h0ello\n0world")
+        }
+    }
+
+    @Test
+    fun textField_newLine() {
+        keysSequenceTest(initText = "hello") {
+            Key.Enter.downAndUp()
+            expectedText("\nhello")
+        }
+    }
+
+    @Test
+    fun textField_backspace() {
+        keysSequenceTest(initText = "hello") {
+            Key.DirectionRight.downAndUp()
+            Key.DirectionRight.downAndUp()
+            Key.Backspace.downAndUp()
+            expectedText("hllo")
+        }
+    }
+
+    @Test
+    fun textField_delete() {
+        keysSequenceTest(initText = "hello") {
+            Key.Delete.downAndUp()
+            expectedText("ello")
+        }
+    }
+
+    @Test
+    fun textField_nextWord() {
+        keysSequenceTest(initText = "hello world") {
+            Key.DirectionRight.downAndUp(META_CTRL_ON)
+            Key.Zero.downAndUp()
+            expectedText("hello0 world")
+            Key.DirectionRight.downAndUp(META_CTRL_ON)
+            Key.Zero.downAndUp()
+            expectedText("hello0 world0")
+        }
+    }
+
+    @Test
+    fun textField_nextWord_doubleSpace() {
+        keysSequenceTest(initText = "hello  world") {
+            Key.DirectionRight.downAndUp(META_CTRL_ON)
+            Key.DirectionRight.downAndUp()
+            Key.DirectionRight.downAndUp(META_CTRL_ON)
+            Key.Zero.downAndUp()
+            expectedText("hello  world0")
+        }
+    }
+
+    @Test
+    fun textField_prevWord() {
+        keysSequenceTest(initText = "hello world") {
+            Key.DirectionRight.downAndUp(META_CTRL_ON)
+            Key.DirectionRight.downAndUp(META_CTRL_ON)
+            Key.DirectionLeft.downAndUp(META_CTRL_ON)
+            Key.Zero.downAndUp()
+            expectedText("hello 0world")
+        }
+    }
+
+    @Test
+    fun textField_HomeAndEnd() {
+        keysSequenceTest(initText = "hello world") {
+            Key.MoveEnd.downAndUp()
+            Key.Zero.downAndUp()
+            Key.MoveHome.downAndUp()
+            Key.Zero.downAndUp()
+            expectedText("0hello world0")
+        }
+    }
+
+    @Test
+    fun textField_byWordSelection() {
+        keysSequenceTest(initText = "hello  world\nhi") {
+            Key.DirectionRight.downAndUp(META_SHIFT_ON or META_CTRL_ON)
+            expectedSelection(TextRange(0, 5))
+            Key.DirectionRight.downAndUp(META_SHIFT_ON or META_CTRL_ON)
+            expectedSelection(TextRange(0, 12))
+            Key.DirectionRight.downAndUp(META_SHIFT_ON or META_CTRL_ON)
+            expectedSelection(TextRange(0, 15))
+            Key.DirectionLeft.downAndUp(META_SHIFT_ON or META_CTRL_ON)
+            expectedSelection(TextRange(0, 13))
+        }
+    }
+
+    @Test
+    fun textField_lineEndStart() {
+        keysSequenceTest(initText = "hello world\nhi") {
+            Key.MoveEnd.downAndUp()
+            Key.Zero.downAndUp()
+            expectedText("hello world0\nhi")
+            Key.MoveEnd.downAndUp()
+            Key.MoveHome.downAndUp()
+            Key.Zero.downAndUp()
+            expectedText("0hello world0\nhi")
+            Key.MoveEnd.downAndUp(META_SHIFT_ON)
+            expectedSelection(TextRange(1, 16))
+        }
+    }
+
+    @Test
+    fun textField_deleteWords() {
+        keysSequenceTest(initText = "hello world\nhi world") {
+            Key.MoveEnd.downAndUp()
+            Key.Backspace.downAndUp(META_CTRL_ON)
+            expectedText("hello \nhi world")
+            Key.Delete.downAndUp(META_CTRL_ON)
+            expectedText("hello  world")
+        }
+    }
+
+    @Test
+    fun textField_paragraphNavigation() {
+        keysSequenceTest(initText = "hello world\nhi") {
+            Key.DirectionDown.downAndUp(META_CTRL_ON)
+            Key.Zero.downAndUp()
+            expectedText("hello world0\nhi")
+            Key.DirectionDown.downAndUp(META_CTRL_ON)
+            Key.DirectionUp.downAndUp(META_CTRL_ON)
+            Key.Zero.downAndUp()
+            expectedText("hello world0\n0hi")
+        }
+    }
+
+    @Test
+    fun textField_selectionCaret() {
+        keysSequenceTest(initText = "hello world") {
+            Key.DirectionRight.downAndUp(META_CTRL_ON or META_SHIFT_ON)
+            expectedSelection(TextRange(0, 5))
+            Key.DirectionRight.downAndUp(META_SHIFT_ON)
+            expectedSelection(TextRange(0, 6))
+            Key.Backslash.downAndUp(META_CTRL_ON)
+            expectedSelection(TextRange(6, 6))
+            Key.DirectionLeft.downAndUp(META_CTRL_ON or META_SHIFT_ON)
+            expectedSelection(TextRange(6, 0))
+            Key.DirectionRight.downAndUp(META_SHIFT_ON)
+            expectedSelection(TextRange(6, 1))
+        }
+    }
+
+    private inner class SequenceScope(
+        val state: MutableState<TextFieldValue>,
+        val nodeGetter: () -> SemanticsNodeInteraction
+    ) {
+        fun Key.downAndUp(metaState: Int = 0) {
+            this.down(metaState)
+            this.up(metaState)
+        }
+
+        fun Key.down(metaState: Int = 0) {
+            nodeGetter().performKeyPress(downEvent(this, metaState))
+        }
+
+        fun Key.up(metaState: Int = 0) {
+            nodeGetter().performKeyPress(upEvent(this, metaState))
+        }
+
+        fun expectedText(text: String) {
+            rule.runOnIdle {
+                Truth.assertThat(state.value.text).isEqualTo(text)
+            }
+        }
+
+        fun expectedSelection(selection: TextRange) {
+            rule.runOnIdle {
+                Truth.assertThat(state.value.selection).isEqualTo(selection)
+            }
+        }
+    }
+
+    private fun keysSequenceTest(
+        initText: String = "",
+        sequence: SequenceScope.() -> Unit
+    ) {
+        val inputService = TextInputService(mock())
+
+        val state = mutableStateOf(TextFieldValue(initText))
+        val focusFequester = FocusRequester()
+        rule.setContent {
+            CompositionLocalProvider(
+                LocalTextInputService provides inputService
+            ) {
+                BasicTextField(
+                    value = state.value,
+                    modifier = Modifier.fillMaxSize().focusRequester(focusFequester),
+                    onValueChange = {
+                        state.value = it
+                    }
+                )
+            }
+        }
+
+        rule.runOnIdle { focusFequester.requestFocus() }
+
+        sequence(SequenceScope(state) { rule.onNode(hasSetTextAction()) })
+    }
+}
+
+private fun downEvent(key: Key, metaState: Int = 0): androidx.compose.ui.input.key.KeyEvent {
+    return androidx.compose.ui.input.key.KeyEvent(
+        KeyEvent(0L, 0L, KeyEvent.ACTION_DOWN, key.nativeKeyCode, 0, metaState)
+    )
+}
+
+private fun upEvent(key: Key, metaState: Int = 0): androidx.compose.ui.input.key.KeyEvent {
+    return androidx.compose.ui.input.key.KeyEvent(
+        KeyEvent(0L, 0L, KeyEvent.ACTION_UP, key.nativeKeyCode, 0, metaState)
+    )
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/KeyMapping.android.kt
similarity index 79%
copy from compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
copy to compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/KeyMapping.android.kt
index 7e01354..c4984e3 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/KeyMapping.android.kt
@@ -1,5 +1,3 @@
-// ktlint-disable filename
-
 /*
  * Copyright 2021 The Android Open Source Project
  *
@@ -16,6 +14,6 @@
  * limitations under the License.
  */
 
-package androidx.compose.foundation
+package androidx.compose.foundation.text
 
-internal actual typealias AtomicReference<V> = java.util.concurrent.atomic.AtomicReference<V>
\ No newline at end of file
+internal actual val platformDefaultKeyMapping = defaultKeyMapping
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/AndroidCoreTextField.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/TextFieldKeyInput.android.kt
similarity index 73%
rename from compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/AndroidCoreTextField.android.kt
rename to compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/TextFieldKeyInput.android.kt
index 6a9e70d..f5f3a55 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/AndroidCoreTextField.android.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/TextFieldKeyInput.android.kt
@@ -16,9 +16,8 @@
 
 package androidx.compose.foundation.text
 
-import androidx.compose.foundation.text.selection.TextFieldSelectionManager
-import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.key.KeyEvent
 
-internal actual fun Modifier.textFieldKeyboardModifier(
-    manager: TextFieldSelectionManager
-): Modifier = this.then(Modifier)
\ No newline at end of file
+internal actual val KeyEvent.isTypedEvent: Boolean
+    get() = nativeKeyEvent.action == android.view.KeyEvent.ACTION_DOWN &&
+        nativeKeyEvent.unicodeChar != 0
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.android.kt
similarity index 76%
copy from compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
copy to compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.android.kt
index 7e01354..16182e9 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.android.kt
@@ -1,5 +1,3 @@
-// ktlint-disable filename
-
 /*
  * Copyright 2021 The Android Open Source Project
  *
@@ -16,6 +14,9 @@
  * limitations under the License.
  */
 
-package androidx.compose.foundation
+package androidx.compose.foundation.text.selection
 
-internal actual typealias AtomicReference<V> = java.util.concurrent.atomic.AtomicReference<V>
\ No newline at end of file
+import androidx.compose.ui.input.pointer.PointerEvent
+
+internal actual val PointerEvent.isShiftPressed: Boolean
+    get() = false
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
index 14de931..58f75c4 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/CoreTextField.kt
@@ -299,10 +299,7 @@
             .then(selectionModifier)
             .then(focusRequestTapModifier)
     } else {
-        Modifier.mouseDragGestureFilter(
-            manager.mouseSelectionObserver(onStart = { focusRequester.requestFocus() }),
-            enabled = enabled
-        )
+        Modifier.mouseDragGestureDetector(manager::mouseSelectionDetector, enabled = enabled)
     }
 
     val drawModifier = Modifier.drawBehind {
@@ -432,6 +429,16 @@
         onDispose { manager.hideSelectionToolbar() }
     }
 
+    val textKeyInputModifier =
+        Modifier.textFieldKeyInput(
+            state = state,
+            manager = manager,
+            value = value,
+            editable = !readOnly,
+            singleLine = maxLines == 1,
+            offsetMapping = offsetMapping
+        )
+
     // Modifiers that should be applied to the outer text field container. Usually those include
     // gesture and semantics modifiers.
     val decorationBoxModifier = modifier
@@ -439,6 +446,7 @@
         .then(pointerModifier)
         .then(semanticsModifier)
         .then(focusModifier)
+        .then(textKeyInputModifier)
         .onGloballyPositioned {
             state.layoutResult?.decorationBoxCoordinates = it
         }
@@ -459,7 +467,6 @@
                 .then(drawModifier)
                 .then(onPositionedModifier)
                 .textFieldMinSize(textStyle)
-                .textFieldKeyboardModifier(manager)
 
             SimpleLayout(coreTextFieldModifier) {
                 Layout({ }) { _, constraints ->
@@ -498,8 +505,6 @@
     }
 }
 
-internal expect fun Modifier.textFieldKeyboardModifier(manager: TextFieldSelectionManager): Modifier
-
 @OptIn(InternalFoundationTextApi::class)
 internal class TextFieldState(
     var textDelegate: TextDelegate
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyCommand.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyCommand.kt
new file mode 100644
index 0000000..3b76844
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyCommand.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2021 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.compose.foundation.text
+
+internal enum class KeyCommand(
+    // Indicates, that this command is supposed to edit text so should be applied only to
+    // editable text fields
+    val editsText: Boolean
+) {
+    LEFT_CHAR(false),
+    RIGHT_CHAR(false),
+
+    RIGHT_WORD(false),
+    LEFT_WORD(false),
+
+    NEXT_PARAGRAPH(false),
+    PREV_PARAGRAPH(false),
+
+    LINE_START(false),
+    LINE_END(false),
+    LINE_LEFT(false),
+    LINE_RIGHT(false),
+
+    UP(false),
+    DOWN(false),
+
+    PAGE_UP(false),
+    PAGE_DOWN(false),
+
+    HOME(false),
+    END(false),
+
+    COPY(false),
+    PASTE(true),
+    CUT(true),
+
+    DELETE_PREV_CHAR(true),
+    DELETE_NEXT_CHAR(true),
+
+    DELETE_PREV_WORD(true),
+    DELETE_NEXT_WORD(true),
+
+    DELETE_FROM_LINE_START(true),
+    DELETE_TO_LINE_END(true),
+
+    SELECT_ALL(false),
+
+    SELECT_LEFT_CHAR(false),
+    SELECT_RIGHT_CHAR(false),
+
+    SELECT_UP(false),
+    SELECT_DOWN(false),
+
+    SELECT_PAGE_UP(false),
+    SELECT_PAGE_DOWN(false),
+
+    SELECT_HOME(false),
+    SELECT_END(false),
+
+    SELECT_LEFT_WORD(false),
+    SELECT_RIGHT_WORD(false),
+    SELECT_NEXT_PARAGRAPH(false),
+    SELECT_PREV_PARAGRAPH(false),
+
+    SELECT_LINE_START(false),
+    SELECT_LINE_END(false),
+    SELECT_LINE_LEFT(false),
+    SELECT_LINE_RIGHT(false),
+
+    DESELECT(false),
+
+    NEW_LINE(true),
+    TAB(true)
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyMapping.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyMapping.kt
new file mode 100644
index 0000000..5d393a5
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/KeyMapping.kt
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2021 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.compose.foundation.text
+
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.input.key.KeyEvent
+import androidx.compose.ui.input.key.isCtrlPressed
+import androidx.compose.ui.input.key.isShiftPressed
+import androidx.compose.ui.input.key.key
+
+internal interface KeyMapping {
+    fun map(event: KeyEvent): KeyCommand?
+}
+
+// each platform can define its own key mapping, on Android its just defaultKeyMapping, but on
+// desktop, the value depends on the current OS
+internal expect val platformDefaultKeyMapping: KeyMapping
+
+// It's common for all platforms key mapping
+internal fun commonKeyMapping(
+    shortcutModifier: (KeyEvent) -> Boolean
+): KeyMapping {
+    return object : KeyMapping {
+        override fun map(event: KeyEvent): KeyCommand? {
+            return when {
+                shortcutModifier(event) ->
+                    when (event.key) {
+                        Key.C, Key.Insert -> KeyCommand.COPY
+                        Key.V -> KeyCommand.PASTE
+                        Key.X -> KeyCommand.CUT
+                        Key.A -> KeyCommand.SELECT_ALL
+                        else -> null
+                    }
+                event.isCtrlPressed -> null
+                event.isShiftPressed ->
+                    when (event.key) {
+                        Key.DirectionLeft -> KeyCommand.SELECT_LEFT_CHAR
+                        Key.DirectionRight -> KeyCommand.SELECT_RIGHT_CHAR
+                        Key.DirectionUp -> KeyCommand.SELECT_UP
+                        Key.DirectionDown -> KeyCommand.SELECT_DOWN
+                        Key.PageUp -> KeyCommand.SELECT_PAGE_UP
+                        Key.PageDown -> KeyCommand.SELECT_PAGE_DOWN
+                        Key.MoveHome -> KeyCommand.SELECT_LINE_START
+                        Key.MoveEnd -> KeyCommand.SELECT_LINE_END
+                        Key.Insert -> KeyCommand.PASTE
+                        else -> null
+                    }
+                else ->
+                    when (event.key) {
+                        Key.DirectionLeft -> KeyCommand.LEFT_CHAR
+                        Key.DirectionRight -> KeyCommand.RIGHT_CHAR
+                        Key.DirectionUp -> KeyCommand.UP
+                        Key.DirectionDown -> KeyCommand.DOWN
+                        Key.PageUp -> KeyCommand.PAGE_UP
+                        Key.PageDown -> KeyCommand.PAGE_DOWN
+                        Key.MoveHome -> KeyCommand.LINE_START
+                        Key.MoveEnd -> KeyCommand.LINE_END
+                        Key.Enter -> KeyCommand.NEW_LINE
+                        Key.Backspace -> KeyCommand.DELETE_PREV_CHAR
+                        Key.Delete -> KeyCommand.DELETE_NEXT_CHAR
+                        Key.Paste -> KeyCommand.PASTE
+                        Key.Cut -> KeyCommand.CUT
+                        Key.Tab -> KeyCommand.TAB
+                        else -> null
+                    }
+            }
+        }
+    }
+}
+
+// It's "default" or actually "non macOS" key mapping
+internal val defaultKeyMapping: KeyMapping =
+    commonKeyMapping(KeyEvent::isCtrlPressed).let { common ->
+        object : KeyMapping {
+            override fun map(event: KeyEvent): KeyCommand? {
+                return when {
+                    event.isShiftPressed && event.isCtrlPressed ->
+                        when (event.key) {
+                            Key.DirectionLeft -> KeyCommand.SELECT_LEFT_WORD
+                            Key.DirectionRight -> KeyCommand.SELECT_RIGHT_WORD
+                            Key.DirectionUp -> KeyCommand.SELECT_PREV_PARAGRAPH
+                            Key.DirectionDown -> KeyCommand.SELECT_NEXT_PARAGRAPH
+                            else -> null
+                        }
+                    event.isCtrlPressed ->
+                        when (event.key) {
+                            Key.DirectionLeft -> KeyCommand.LEFT_WORD
+                            Key.DirectionRight -> KeyCommand.RIGHT_WORD
+                            Key.DirectionUp -> KeyCommand.PREV_PARAGRAPH
+                            Key.DirectionDown -> KeyCommand.NEXT_PARAGRAPH
+                            Key.H -> KeyCommand.DELETE_PREV_CHAR
+                            Key.Delete -> KeyCommand.DELETE_NEXT_WORD
+                            Key.Backspace -> KeyCommand.DELETE_PREV_WORD
+                            Key.Backslash -> KeyCommand.DESELECT
+                            else -> null
+                        }
+                    event.isShiftPressed ->
+                        when (event.key) {
+                            Key.MoveHome -> KeyCommand.SELECT_HOME
+                            Key.MoveEnd -> KeyCommand.SELECT_END
+                            else -> null
+                        }
+                    else -> null
+                } ?: common.map(event)
+            }
+        }
+    }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/StringHelpers.kt
similarity index 64%
copy from compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
copy to compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/StringHelpers.kt
index 7e01354..dbbf9df 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/StringHelpers.kt
@@ -1,5 +1,3 @@
-// ktlint-disable filename
-
 /*
  * Copyright 2021 The Android Open Source Project
  *
@@ -16,6 +14,11 @@
  * limitations under the License.
  */
 
-package androidx.compose.foundation
+package androidx.compose.foundation.text
 
-internal actual typealias AtomicReference<V> = java.util.concurrent.atomic.AtomicReference<V>
\ No newline at end of file
+// StringBuilder.appendCodePoint is already defined on JVM so it's called appendCodePointX
+internal expect fun StringBuilder.appendCodePointX(codePoint: Int): StringBuilder
+
+internal expect fun String.findPrecedingBreak(index: Int): Int
+
+internal expect fun String.findFollowingBreak(index: Int): Int
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldGestureModifiers.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldGestureModifiers.kt
index af50a91..b1f6e32 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldGestureModifiers.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldGestureModifiers.kt
@@ -31,6 +31,8 @@
 import androidx.compose.foundation.legacygestures.dragGestureFilter
 import androidx.compose.foundation.legacygestures.longPressDragGestureFilter
 import androidx.compose.foundation.legacygestures.tapGestureFilter
+import androidx.compose.ui.input.pointer.PointerInputScope
+import androidx.compose.ui.input.pointer.pointerInput
 
 // Touch selection
 internal fun Modifier.longPressDragGestureFilter(
@@ -56,4 +58,9 @@
 internal fun Modifier.mouseDragGestureFilter(
     dragObserver: DragObserver,
     enabled: Boolean
-) = if (enabled) this.dragGestureFilter(dragObserver, startDragImmediately = true) else this
\ No newline at end of file
+) = if (enabled) this.dragGestureFilter(dragObserver, startDragImmediately = true) else this
+
+internal fun Modifier.mouseDragGestureDetector(
+    detector: suspend PointerInputScope.() -> Unit,
+    enabled: Boolean
+) = if (enabled) Modifier.pointerInput(Unit, detector) else this
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldKeyInput.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldKeyInput.kt
new file mode 100644
index 0000000..b792da1
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/TextFieldKeyInput.kt
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2021 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.compose.foundation.text
+
+import androidx.compose.foundation.text.selection.TextFieldPreparedSelection
+import androidx.compose.foundation.text.selection.TextFieldSelectionManager
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.key.KeyEvent
+import androidx.compose.ui.input.key.KeyEventType
+import androidx.compose.ui.input.key.onKeyEvent
+import androidx.compose.ui.input.key.type
+import androidx.compose.ui.input.key.utf16CodePoint
+import androidx.compose.ui.text.input.CommitTextCommand
+import androidx.compose.ui.text.input.EditCommand
+import androidx.compose.ui.text.input.OffsetMapping
+import androidx.compose.ui.text.input.TextFieldValue
+
+// AWT and Android have similar but different key event models. In android there are two main
+// types of events: ACTION_DOWN and ACTION_UP. In AWT there is additional KEY_TYPED which should
+// be used to get "typed character". By this simple function we are introducing common
+// denominator for both systems: if KeyEvent.isTypedEvent then it's safe to use
+// KeyEvent.utf16CodePoint
+internal expect val KeyEvent.isTypedEvent: Boolean
+
+/**
+ * It handles [KeyEvent]s and either process them as typed events or maps to
+ * [KeyCommand] via [KeyMapping]. [KeyCommand] then is executed
+ * using utility class [TextFieldPreparedSelection]
+ */
+internal class TextFieldKeyInput(
+    val state: TextFieldState,
+    val selectionManager: TextFieldSelectionManager,
+    val value: TextFieldValue = TextFieldValue(),
+    val editable: Boolean = true,
+    val singleLine: Boolean = false,
+    val offsetMapping: OffsetMapping = OffsetMapping.Identity,
+    private val keyMapping: KeyMapping = platformDefaultKeyMapping,
+) {
+    private fun EditCommand.apply() {
+        state.onValueChange(state.processor.apply(listOf(this)))
+    }
+
+    private fun typedCommand(event: KeyEvent): CommitTextCommand? =
+        if (event.isTypedEvent) {
+            val text = StringBuilder().appendCodePointX(event.utf16CodePoint)
+                .toString()
+            CommitTextCommand(text, 1)
+        } else {
+            null
+        }
+
+    fun process(event: KeyEvent): Boolean {
+        typedCommand(event)?.let {
+            return if (editable) {
+                it.apply()
+                true
+            } else {
+                false
+            }
+        }
+        if (event.type != KeyEventType.KeyDown) {
+            return false
+        }
+        val command = keyMapping.map(event)
+        if (command == null || (command.editsText && !editable)) {
+            return false
+        }
+        var consumed = true
+        commandExecutionContext {
+            when (command) {
+                KeyCommand.COPY -> selectionManager.copy(false)
+                KeyCommand.PASTE -> selectionManager.paste()
+                KeyCommand.CUT -> selectionManager.cut()
+                KeyCommand.LEFT_CHAR -> collapseLeftOr { moveCursorLeft() }
+                KeyCommand.RIGHT_CHAR -> collapseRightOr { moveCursorRight() }
+                KeyCommand.LEFT_WORD -> moveCursorLeftByWord()
+                KeyCommand.RIGHT_WORD -> moveCursorRightByWord()
+                KeyCommand.PREV_PARAGRAPH -> moveCursorPrevByParagraph()
+                KeyCommand.NEXT_PARAGRAPH -> moveCursorNextByParagraph()
+                KeyCommand.UP -> moveCursorUpByLine()
+                KeyCommand.DOWN -> moveCursorDownByLine()
+                KeyCommand.PAGE_UP -> moveCursorUpByPage()
+                KeyCommand.PAGE_DOWN -> moveCursorDownByPage()
+                KeyCommand.LINE_START -> moveCursorToLineStart()
+                KeyCommand.LINE_END -> moveCursorToLineEnd()
+                KeyCommand.LINE_LEFT -> moveCursorToLineLeftSide()
+                KeyCommand.LINE_RIGHT -> moveCursorToLineRightSide()
+                KeyCommand.HOME -> moveCursorToHome()
+                KeyCommand.END -> moveCursorToEnd()
+                KeyCommand.DELETE_PREV_CHAR ->
+                    deleteIfSelectedOr {
+                        moveCursorPrev().selectMovement().deleteSelected()
+                    }
+                KeyCommand.DELETE_NEXT_CHAR -> {
+                    deleteIfSelectedOr {
+                        moveCursorNext().selectMovement().deleteSelected()
+                    }
+                }
+                KeyCommand.DELETE_PREV_WORD ->
+                    deleteIfSelectedOr {
+                        moveCursorPrevByWord().selectMovement().deleteSelected()
+                    }
+                KeyCommand.DELETE_NEXT_WORD ->
+                    deleteIfSelectedOr {
+                        moveCursorNextByWord().selectMovement().deleteSelected()
+                    }
+                KeyCommand.DELETE_FROM_LINE_START ->
+                    deleteIfSelectedOr {
+                        moveCursorToLineStart().selectMovement().deleteSelected()
+                    }
+                KeyCommand.DELETE_TO_LINE_END ->
+                    deleteIfSelectedOr {
+                        moveCursorToLineEnd().selectMovement().deleteSelected()
+                    }
+                KeyCommand.NEW_LINE ->
+                    if (!singleLine) {
+                        CommitTextCommand("\n", 1).apply()
+                    } else {
+                        consumed = false
+                    }
+                KeyCommand.TAB ->
+                    if (!singleLine) {
+                        CommitTextCommand("\t", 1).apply()
+                    } else {
+                        consumed = false
+                    }
+                KeyCommand.SELECT_ALL -> selectAll()
+                KeyCommand.SELECT_LEFT_CHAR -> moveCursorLeft().selectMovement()
+                KeyCommand.SELECT_RIGHT_CHAR -> moveCursorRight().selectMovement()
+                KeyCommand.SELECT_LEFT_WORD -> moveCursorLeftByWord().selectMovement()
+                KeyCommand.SELECT_RIGHT_WORD -> moveCursorRightByWord().selectMovement()
+                KeyCommand.SELECT_PREV_PARAGRAPH -> moveCursorPrevByParagraph().selectMovement()
+                KeyCommand.SELECT_NEXT_PARAGRAPH -> moveCursorNextByParagraph().selectMovement()
+                KeyCommand.SELECT_LINE_START -> moveCursorToLineStart().selectMovement()
+                KeyCommand.SELECT_LINE_END -> moveCursorToLineEnd().selectMovement()
+                KeyCommand.SELECT_LINE_LEFT -> moveCursorToLineLeftSide().selectMovement()
+                KeyCommand.SELECT_LINE_RIGHT -> moveCursorToLineRightSide().selectMovement()
+                KeyCommand.SELECT_UP -> moveCursorUpByLine().selectMovement()
+                KeyCommand.SELECT_DOWN -> moveCursorDownByLine().selectMovement()
+                KeyCommand.SELECT_PAGE_UP -> moveCursorUpByPage().selectMovement()
+                KeyCommand.SELECT_PAGE_DOWN -> moveCursorDownByPage().selectMovement()
+                KeyCommand.SELECT_HOME -> moveCursorToHome().selectMovement()
+                KeyCommand.SELECT_END -> moveCursorToEnd().selectMovement()
+                KeyCommand.DESELECT -> deselect()
+            }
+        }
+        return consumed
+    }
+
+    private fun commandExecutionContext(block: TextFieldPreparedSelection.() -> Unit) {
+        val preparedSelection = TextFieldPreparedSelection(
+            currentValue = value,
+            offsetMapping = offsetMapping,
+            layoutResultProxy = state.layoutResult
+        )
+        block(preparedSelection)
+        if (preparedSelection.selection != value.selection ||
+            preparedSelection.annotatedString != value.annotatedString
+        ) {
+            state.onValueChange(preparedSelection.value)
+        }
+    }
+}
+
+internal fun Modifier.textFieldKeyInput(
+    state: TextFieldState,
+    manager: TextFieldSelectionManager,
+    value: TextFieldValue,
+    editable: Boolean,
+    singleLine: Boolean,
+    offsetMapping: OffsetMapping
+): Modifier {
+    val processor = TextFieldKeyInput(
+        state = state,
+        selectionManager = manager,
+        value = value,
+        editable = editable,
+        singleLine = singleLine,
+        offsetMapping = offsetMapping
+    )
+    return Modifier.onKeyEvent(processor::process)
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
index e8c775c..55616a6 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.kt
@@ -18,6 +18,8 @@
 
 package androidx.compose.foundation.text.selection
 
+import androidx.compose.foundation.gestures.drag
+import androidx.compose.foundation.gestures.forEachGesture
 import androidx.compose.foundation.text.TextFieldDelegate
 import androidx.compose.foundation.text.TextFieldState
 import androidx.compose.runtime.Composable
@@ -34,6 +36,14 @@
 import androidx.compose.foundation.text.InternalFoundationTextApi
 import androidx.compose.ui.hapticfeedback.HapticFeedback
 import androidx.compose.ui.hapticfeedback.HapticFeedbackType
+import androidx.compose.ui.input.pointer.AwaitPointerEventScope
+import androidx.compose.ui.input.pointer.PointerEvent
+import androidx.compose.ui.input.pointer.PointerInputScope
+import androidx.compose.ui.input.pointer.PointerType
+import androidx.compose.ui.input.pointer.changedToDown
+import androidx.compose.ui.input.pointer.consumeAllChanges
+import androidx.compose.ui.input.pointer.consumeDownChange
+import androidx.compose.ui.input.pointer.positionChange
 import androidx.compose.ui.platform.ClipboardManager
 import androidx.compose.ui.platform.TextToolbar
 import androidx.compose.ui.platform.TextToolbarStatus
@@ -48,6 +58,7 @@
 import androidx.compose.ui.text.input.getTextBeforeSelection
 import androidx.compose.ui.text.style.ResolvedTextDirection
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.fastAll
 import kotlin.math.max
 import kotlin.math.min
 
@@ -215,46 +226,81 @@
         }
     }
 
-    internal fun mouseSelectionObserver(onStart: (Offset) -> Unit) = object : DragObserver {
-        override fun onStart(downPosition: Offset) {
-            onStart(downPosition)
+    internal interface MouseSelectionObserver {
+        fun onDown(downPosition: Offset, shiftIsPressed: Boolean)
+        fun onDrag(dragDistance: Offset)
+    }
 
-            state?.layoutResult?.let { layoutResult ->
-                TextFieldDelegate.setCursorOffset(
-                    downPosition,
-                    layoutResult,
-                    state!!.processor,
-                    offsetMapping,
-                    onValueChange
-                )
-                dragBeginOffsetInText = layoutResult.getOffsetForPosition(downPosition)
-            }
+    internal val mouseSelectionObserver = object : MouseSelectionObserver {
+        override fun onDown(downPosition: Offset, shiftIsPressed: Boolean) {
+            focusRequester?.requestFocus()
 
             dragBeginPosition = downPosition
             dragTotalDistance = Offset.Zero
-        }
 
-        override fun onDrag(dragDistance: Offset): Offset {
-            // selection never started, did not consume any drag
-            if (value.text.isEmpty()) return Offset.Zero
+            state?.layoutResult?.let { layoutResult ->
+                dragBeginOffsetInText = layoutResult.getOffsetForPosition(downPosition)
+                // * Without shift it starts the new selection from the scratch.
+                // * With shift expand / shrink existed selection.
+                // * Click sets start and end of the selection, but shift click only the end of
+                // selection.
+                // * The specific case of it when selection is collapsed, but the same logic is
+                // applied for not collapsed selection too.
+                if (shiftIsPressed) {
+                    val startOffset = offsetMapping.originalToTransformed(value.selection.start)
+                    val clickOffset = layoutResult.getOffsetForPosition(dragBeginPosition)
+                    updateSelection(
+                        value = value,
+                        transformedStartOffset = startOffset,
+                        transformedEndOffset = clickOffset,
+                        isStartHandle = false,
+                        wordBasedSelection = false
+                    )
+                } else {
+                    TextFieldDelegate.setCursorOffset(
+                        downPosition,
+                        layoutResult,
+                        state!!.processor,
+                        offsetMapping,
+                        onValueChange
+                    )
+                }
+            }
+        }
+        override fun onDrag(dragDistance: Offset) {
+            if (value.text.isEmpty()) return
 
             dragTotalDistance += dragDistance
             state?.layoutResult?.let { layoutResult ->
-                val startOffset = dragBeginOffsetInText ?: layoutResult
-                    .getOffsetForPosition(dragBeginPosition, false)
-                val endOffset = layoutResult.getOffsetForPosition(
-                    position = dragBeginPosition + dragTotalDistance,
-                    coerceInVisibleBounds = false
-                )
+                val dragOffset =
+                    layoutResult.getOffsetForPosition(
+                        position = dragBeginPosition + dragTotalDistance,
+                        coerceInVisibleBounds = false
+                    )
+                val startOffset = offsetMapping.originalToTransformed(value.selection.start)
                 updateSelection(
                     value = value,
                     transformedStartOffset = startOffset,
-                    transformedEndOffset = endOffset,
+                    transformedEndOffset = dragOffset,
                     isStartHandle = false,
                     wordBasedSelection = false
                 )
             }
-            return dragDistance
+        }
+    }
+
+    internal suspend fun mouseSelectionDetector(scope: PointerInputScope) {
+        scope.forEachGesture {
+            awaitPointerEventScope {
+                val down = awaitMouseEventFirstDown()
+                val downChange = down.changes[0]
+                downChange.consumeDownChange()
+                mouseSelectionObserver.onDown(downChange.position, down.isShiftPressed)
+                drag(downChange.id) {
+                    mouseSelectionObserver.onDrag(it.positionChange())
+                    it.consumeAllChanges()
+                }
+            }
         }
     }
 
@@ -643,3 +689,16 @@
 ): Boolean = state?.layoutCoordinates?.visibleBounds()?.containsInclusive(
     getHandlePosition(isStartHandle)
 ) ?: false
+
+private suspend fun AwaitPointerEventScope.awaitMouseEventFirstDown(): PointerEvent {
+    var event: PointerEvent
+    do {
+        event = awaitPointerEvent()
+    } while (
+        !event.changes.fastAll { it.type == PointerType.Mouse && it.changedToDown() }
+    )
+    return event
+}
+
+// TODO(b/180075467) it should be part of PointerEvent API in one way or another
+internal expect val PointerEvent.isShiftPressed: Boolean
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextPreparedSelection.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextPreparedSelection.kt
new file mode 100644
index 0000000..68d1712
--- /dev/null
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/selection/TextPreparedSelection.kt
@@ -0,0 +1,394 @@
+/*
+ * Copyright 2021 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.compose.foundation.text.selection
+
+import androidx.compose.foundation.text.TextLayoutResultProxy
+import androidx.compose.foundation.text.findFollowingBreak
+import androidx.compose.foundation.text.findPrecedingBreak
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.TextLayoutResult
+import androidx.compose.ui.text.TextRange
+import androidx.compose.ui.text.input.OffsetMapping
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.text.style.ResolvedTextDirection
+import kotlin.math.max
+import kotlin.math.min
+
+/**
+ * This utility class implements many selection-related operations on text (including basic
+ * cursor movements and deletions) and combines them, taking into account how the text was
+ * rendered. So, for example, [moveCursorToLineEnd] moves it to the visual line end.
+ *
+ * For many of these operations, it's particularly important to keep the difference between
+ * selection start and selection end. In some systems, they are called "anchor" and "caret"
+ * respectively. For example, for selection from scratch, after [moveCursorLeftByWord]
+ * [moveCursorRight] will move the left side of the selection, but after [moveCursorRightByWord]
+ * the right one.
+ *
+ * To use it in scope of text fields see [TextFieldPreparedSelection]
+ */
+internal abstract class BaseTextPreparedSelection<T : BaseTextPreparedSelection<T>>(
+    val originalText: AnnotatedString,
+    val originalSelection: TextRange,
+    val layoutResult: TextLayoutResult?,
+    val offsetMapping: OffsetMapping
+) {
+    var selection = originalSelection
+
+    var annotatedString = originalText
+    protected val text
+        get() = annotatedString.text
+
+    @Suppress("UNCHECKED_CAST")
+    inline fun <U> U.apply(block: U.() -> Unit): T {
+        block()
+        return this as T
+    }
+
+    fun setCursor(offset: Int) = apply {
+        setSelection(offset, offset)
+    }
+
+    fun setSelection(start: Int, end: Int) = apply {
+        selection = TextRange(start, end)
+    }
+
+    fun selectAll() = apply {
+        setSelection(0, text.length)
+    }
+
+    fun deselect() = apply {
+        setCursor(selection.end)
+    }
+
+    fun moveCursorLeft() = apply {
+        if (isLtr()) {
+            moveCursorPrev()
+        } else {
+            moveCursorNext()
+        }
+    }
+
+    fun moveCursorRight() = apply {
+        if (isLtr()) {
+            moveCursorNext()
+        } else {
+            moveCursorPrev()
+        }
+    }
+
+    /**
+     * If there is already a selection, collapse it to the left side. Otherwise, execute [or]
+     */
+    fun collapseLeftOr(or: T.() -> Unit) = apply {
+        if (selection.collapsed) {
+            @Suppress("UNCHECKED_CAST")
+            or(this as T)
+        } else {
+            if (isLtr()) {
+                setCursor(selection.min)
+            } else {
+                setCursor(selection.max)
+            }
+        }
+    }
+
+    /**
+     * If there is already a selection, collapse it to the right side. Otherwise, execute [or]
+     */
+    fun collapseRightOr(or: T.() -> Unit) = apply {
+        if (selection.collapsed) {
+            @Suppress("UNCHECKED_CAST")
+            or(this as T)
+        } else {
+            if (isLtr()) {
+                setCursor(selection.max)
+            } else {
+                setCursor(selection.min)
+            }
+        }
+    }
+
+    fun moveCursorPrev() = apply {
+        val prev = annotatedString.text.findPrecedingBreak(selection.end)
+        if (prev != -1) setCursor(prev)
+    }
+
+    fun moveCursorNext() = apply {
+        val next = annotatedString.text.findFollowingBreak(selection.end)
+        if (next != -1) setCursor(next)
+    }
+
+    fun moveCursorToHome() = apply {
+        setCursor(0)
+    }
+
+    fun moveCursorToEnd() = apply {
+        setCursor(text.length)
+    }
+
+    fun moveCursorLeftByWord() = apply {
+        if (isLtr()) {
+            moveCursorPrevByWord()
+        } else {
+            moveCursorNextByWord()
+        }
+    }
+
+    fun moveCursorRightByWord() = apply {
+        if (isLtr()) {
+            moveCursorNextByWord()
+        } else {
+            moveCursorPrevByWord()
+        }
+    }
+
+    fun moveCursorNextByWord() = apply {
+        layoutResult?.getNextWordOffset()?.let { setCursor(it) }
+    }
+
+    fun moveCursorPrevByWord() = apply {
+        layoutResult?.getPrevWordOffset()?.let { setCursor(it) }
+    }
+
+    fun moveCursorPrevByParagraph() = apply {
+        setCursor(getParagraphStart())
+    }
+
+    fun moveCursorNextByParagraph() = apply {
+        setCursor(getParagraphEnd())
+    }
+
+    fun moveCursorUpByLine() = apply {
+        layoutResult?.jumpByLinesOffset(-1)?.let { setCursor(it) }
+    }
+
+    fun moveCursorDownByLine() = apply {
+        layoutResult?.jumpByLinesOffset(1)?.let { setCursor(it) }
+    }
+
+    fun moveCursorToLineStart() = apply {
+        layoutResult?.getLineStartByOffset()?.let { setCursor(it) }
+    }
+
+    fun moveCursorToLineEnd() = apply {
+        layoutResult?.getLineEndByOffset()?.let { setCursor(it) }
+    }
+
+    fun moveCursorToLineLeftSide() = apply {
+        if (isLtr()) {
+            moveCursorToLineStart()
+        } else {
+            moveCursorToLineEnd()
+        }
+    }
+
+    fun moveCursorToLineRightSide() = apply {
+        if (isLtr()) {
+            moveCursorToLineEnd()
+        } else {
+            moveCursorToLineStart()
+        }
+    }
+
+    // it selects a text from the original selection start to a current selection end
+    fun selectMovement() = apply {
+        selection = TextRange(originalSelection.start, selection.end)
+    }
+
+    // delete currently selected text and update [selection] and [annotatedString]
+    fun deleteSelected() = apply {
+        val maxChars = text.length
+        val beforeSelection =
+            annotatedString.subSequence(max(0, selection.min - maxChars), selection.min)
+        val afterSelection =
+            annotatedString.subSequence(selection.max, min(selection.max + maxChars, text.length))
+        annotatedString = beforeSelection + afterSelection
+        setCursor(selection.min)
+    }
+
+    private fun isLtr(): Boolean {
+        val direction = layoutResult?.getBidiRunDirection(selection.end)
+        return direction != ResolvedTextDirection.Rtl
+    }
+
+    private fun TextLayoutResult.getNextWordOffset(
+        currentOffset: Int = transformedEndOffset()
+    ): Int {
+        if (currentOffset >= originalText.length) {
+            return originalText.length
+        }
+        val currentWord = getWordBoundary(charOffset(currentOffset))
+        return if (currentWord.end <= currentOffset) {
+            getNextWordOffset(currentOffset + 1)
+        } else {
+            offsetMapping.transformedToOriginal(currentWord.end)
+        }
+    }
+
+    private fun TextLayoutResult.getPrevWordOffset(
+        currentOffset: Int = transformedEndOffset()
+    ): Int {
+        if (currentOffset < 0) {
+            return 0
+        }
+        val currentWord = getWordBoundary(charOffset(currentOffset))
+        return if (currentWord.start >= currentOffset) {
+            getPrevWordOffset(currentOffset - 1)
+        } else {
+            offsetMapping.transformedToOriginal(currentWord.start)
+        }
+    }
+
+    private fun TextLayoutResult.getLineStartByOffset(
+        currentOffset: Int = transformedMinOffset()
+    ): Int {
+        val currentLine = getLineForOffset(currentOffset)
+        return offsetMapping.transformedToOriginal(getLineStart(currentLine))
+    }
+
+    private fun TextLayoutResult.getLineEndByOffset(
+        currentOffset: Int = transformedMaxOffset()
+    ): Int {
+        val currentLine = getLineForOffset(currentOffset)
+        return offsetMapping.transformedToOriginal(getLineEnd(currentLine, true))
+    }
+
+    private fun TextLayoutResult.jumpByLinesOffset(linesAmount: Int): Int {
+        val currentOffset = transformedEndOffset()
+
+        val newLine = getLineForOffset(currentOffset) + linesAmount
+        when {
+            newLine < 0 -> {
+                return 0
+            }
+            newLine >= lineCount -> {
+                return text.length
+            }
+        }
+
+        val y = getLineBottom(newLine) - 1
+        val x = getCursorRect(currentOffset).left.also {
+            if ((isLtr() && it >= getLineRight(newLine)) ||
+                (!isLtr() && it <= getLineLeft(newLine))
+            ) {
+                return getLineEnd(newLine, true)
+            }
+        }
+
+        val newOffset = getOffsetForPosition(Offset(x, y)).let {
+            offsetMapping.transformedToOriginal(it)
+        }
+
+        return newOffset
+    }
+
+    private fun transformedEndOffset(): Int {
+        return offsetMapping.originalToTransformed(originalSelection.end)
+    }
+
+    private fun transformedMinOffset(): Int {
+        return offsetMapping.originalToTransformed(originalSelection.min)
+    }
+
+    private fun transformedMaxOffset(): Int {
+        return offsetMapping.originalToTransformed(originalSelection.max)
+    }
+
+    private fun charOffset(offset: Int) =
+        offset.coerceAtMost(originalText.length - 1)
+
+    private fun getParagraphStart(): Int {
+        var index = selection.min
+        if (index > 0 && text[index - 1] == '\n') {
+            index--
+        }
+        while (index > 0) {
+            if (text[index - 1] == '\n') {
+                return index
+            }
+            index--
+        }
+        return 0
+    }
+
+    private fun getParagraphEnd(): Int {
+        var index = selection.max
+        if (text[index] == '\n') {
+            index++
+        }
+        while (index < text.length - 1) {
+            if (text[index] == '\n') {
+                return index
+            }
+            index++
+        }
+        return text.length
+    }
+}
+
+internal class TextFieldPreparedSelection(
+    val currentValue: TextFieldValue,
+    offsetMapping: OffsetMapping = OffsetMapping.Identity,
+    val layoutResultProxy: TextLayoutResultProxy?
+) : BaseTextPreparedSelection<TextFieldPreparedSelection>(
+    originalText = currentValue.annotatedString,
+    originalSelection = currentValue.selection,
+    offsetMapping = offsetMapping,
+    layoutResult = layoutResultProxy?.value
+) {
+    val value
+        get() = currentValue.copy(
+            annotatedString = annotatedString,
+            selection = selection
+        )
+
+    fun deleteIfSelectedOr(or: TextFieldPreparedSelection.() -> Unit) = apply {
+        if (selection.collapsed) {
+            or(this)
+        } else {
+            deleteSelected()
+        }
+    }
+
+    fun moveCursorUpByPage() = apply {
+        layoutResultProxy?.jumpByPagesOffset(-1)?.let { setCursor(it) }
+    }
+
+    fun moveCursorDownByPage() = apply {
+        layoutResultProxy?.jumpByPagesOffset(1)?.let { setCursor(it) }
+    }
+
+    /**
+     * Returns a cursor position after jumping back or forth by [pagesAmount] number of pages,
+     * where `page` is the visible amount of space in the text field
+     */
+    private fun TextLayoutResultProxy.jumpByPagesOffset(pagesAmount: Int): Int {
+        val visibleInnerTextFieldRect = innerTextFieldCoordinates?.let { inner ->
+            decorationBoxCoordinates?.localBoundingBoxOf(inner)
+        } ?: Rect.Zero
+        val currentOffset = offsetMapping.originalToTransformed(currentValue.selection.end)
+        val currentPos = value.getCursorRect(currentOffset)
+        val x = currentPos.left
+        val y = currentPos.top + visibleInnerTextFieldRect.size.height * pagesAmount
+        return offsetMapping.transformedToOriginal(
+            value.getOffsetForPosition(Offset(x, y))
+        )
+    }
+}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text/DesktopCoreTextField.desktop.kt b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text/DesktopCoreTextField.desktop.kt
index d5e4a44..e69de29 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text/DesktopCoreTextField.desktop.kt
+++ b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text/DesktopCoreTextField.desktop.kt
@@ -1,59 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.compose.foundation.text
-
-import androidx.compose.foundation.text.selection.TextFieldSelectionManager
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.composed
-import androidx.compose.ui.input.key.Key
-import androidx.compose.ui.input.key.plus
-import androidx.compose.ui.input.key.shortcuts
-import androidx.compose.ui.platform.DesktopPlatform
-
-private val modifier by lazy {
-    when (DesktopPlatform.Current) {
-        DesktopPlatform.MacOS -> Key.MetaLeft
-        else -> Key.CtrlLeft
-    }
-}
-
-private val copyToClipboardKeySet by lazy { modifier + Key.C }
-
-private val pasteFromClipboardKeySet by lazy { modifier + Key.V }
-
-private val cutToClipboardKeySet by lazy { modifier + Key.X }
-
-private val selectAllKeySet by lazy { modifier + Key.A }
-
-internal actual fun Modifier.textFieldKeyboardModifier(
-    manager: TextFieldSelectionManager
-): Modifier = composed {
-    shortcuts {
-        on(copyToClipboardKeySet) {
-            manager.copy(false)
-        }
-        on(pasteFromClipboardKeySet) {
-            manager.paste()
-        }
-        on(cutToClipboardKeySet) {
-            manager.cut()
-        }
-        on(selectAllKeySet) {
-            manager.selectAll()
-        }
-    }
-}
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text/KeyMapping.desktop.kt b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text/KeyMapping.desktop.kt
new file mode 100644
index 0000000..f96b451
--- /dev/null
+++ b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text/KeyMapping.desktop.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2021 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.compose.foundation.text
+
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.input.key.KeyEvent
+import androidx.compose.ui.input.key.isAltPressed
+import androidx.compose.ui.input.key.isCtrlPressed
+import androidx.compose.ui.input.key.isMetaPressed
+import androidx.compose.ui.input.key.isShiftPressed
+import androidx.compose.ui.input.key.key
+import androidx.compose.ui.platform.DesktopPlatform
+
+internal actual val platformDefaultKeyMapping: KeyMapping =
+    when (DesktopPlatform.Current) {
+        DesktopPlatform.MacOS -> {
+            val common = commonKeyMapping(KeyEvent::isMetaPressed)
+            object : KeyMapping {
+                override fun map(event: KeyEvent): KeyCommand? {
+                    return when {
+                        event.isShiftPressed && event.isAltPressed ->
+                            when (event.key) {
+                                Key.DirectionLeft -> KeyCommand.SELECT_LEFT_WORD
+                                Key.DirectionRight -> KeyCommand.SELECT_RIGHT_WORD
+                                Key.DirectionUp -> KeyCommand.SELECT_PREV_PARAGRAPH
+                                Key.DirectionDown -> KeyCommand.SELECT_NEXT_PARAGRAPH
+                                else -> null
+                            }
+                        event.isShiftPressed && event.isMetaPressed ->
+                            when (event.key) {
+                                Key.DirectionLeft -> KeyCommand.SELECT_LINE_LEFT
+                                Key.DirectionRight -> KeyCommand.SELECT_LINE_RIGHT
+                                Key.DirectionUp -> KeyCommand.SELECT_HOME
+                                Key.DirectionDown -> KeyCommand.SELECT_END
+                                else -> null
+                            }
+
+                        event.isMetaPressed ->
+                            when (event.key) {
+                                Key.DirectionLeft -> KeyCommand.LINE_LEFT
+                                Key.DirectionRight -> KeyCommand.LINE_RIGHT
+                                Key.DirectionUp -> KeyCommand.HOME
+                                Key.DirectionDown -> KeyCommand.END
+                                Key.Backspace -> KeyCommand.DELETE_FROM_LINE_START
+                                else -> null
+                            }
+
+                        // Emacs-like shortcuts
+                        event.isCtrlPressed && event.isShiftPressed && event.isAltPressed -> {
+                            when (event.key) {
+                                Key.F -> KeyCommand.SELECT_RIGHT_WORD
+                                Key.B -> KeyCommand.SELECT_LEFT_WORD
+                                else -> null
+                            }
+                        }
+                        event.isCtrlPressed && event.isAltPressed -> {
+                            when (event.key) {
+                                Key.F -> KeyCommand.RIGHT_WORD
+                                Key.B -> KeyCommand.LEFT_WORD
+                                else -> null
+                            }
+                        }
+                        event.isCtrlPressed && event.isShiftPressed -> {
+                            when (event.key) {
+                                Key.F -> KeyCommand.SELECT_RIGHT_CHAR
+                                Key.B -> KeyCommand.SELECT_LEFT_CHAR
+                                Key.P -> KeyCommand.SELECT_UP
+                                Key.N -> KeyCommand.SELECT_DOWN
+                                Key.A -> KeyCommand.SELECT_LINE_START
+                                Key.E -> KeyCommand.SELECT_LINE_END
+                                else -> null
+                            }
+                        }
+                        event.isCtrlPressed -> {
+                            when (event.key) {
+                                Key.F -> KeyCommand.LEFT_CHAR
+                                Key.B -> KeyCommand.RIGHT_CHAR
+                                Key.P -> KeyCommand.UP
+                                Key.N -> KeyCommand.DOWN
+                                Key.A -> KeyCommand.LINE_START
+                                Key.E -> KeyCommand.LINE_END
+                                Key.H -> KeyCommand.DELETE_PREV_CHAR
+                                Key.D -> KeyCommand.DELETE_NEXT_CHAR
+                                Key.K -> KeyCommand.DELETE_TO_LINE_END
+                                Key.O -> KeyCommand.NEW_LINE
+                                else -> null
+                            }
+                        }
+                        // end of emacs-like shortcuts
+
+                        event.isShiftPressed ->
+                            when (event.key) {
+                                Key.MoveHome -> KeyCommand.SELECT_HOME
+                                Key.MoveEnd -> KeyCommand.SELECT_END
+                                else -> null
+                            }
+                        event.isAltPressed ->
+                            when (event.key) {
+                                Key.DirectionLeft -> KeyCommand.LEFT_WORD
+                                Key.DirectionRight -> KeyCommand.RIGHT_WORD
+                                Key.DirectionUp -> KeyCommand.PREV_PARAGRAPH
+                                Key.DirectionDown -> KeyCommand.NEXT_PARAGRAPH
+                                Key.Delete -> KeyCommand.DELETE_NEXT_WORD
+                                Key.Backspace -> KeyCommand.DELETE_PREV_WORD
+                                else -> null
+                            }
+                        else -> null
+                    } ?: common.map(event)
+                }
+            }
+        }
+
+        else -> defaultKeyMapping
+    }
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text/TextFieldKeyInput.desktop.kt b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text/TextFieldKeyInput.desktop.kt
new file mode 100644
index 0000000..7e88a87
--- /dev/null
+++ b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text/TextFieldKeyInput.desktop.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021 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.compose.foundation.text
+
+import androidx.compose.ui.input.key.KeyEvent
+
+private fun Char.isPrintable(): Boolean {
+    val block = Character.UnicodeBlock.of(this)
+    return (!Character.isISOControl(this)) &&
+        this != java.awt.event.KeyEvent.CHAR_UNDEFINED &&
+        block != null &&
+        block != Character.UnicodeBlock.SPECIALS
+}
+
+actual val KeyEvent.isTypedEvent: Boolean
+    get() = nativeKeyEvent.id == java.awt.event.KeyEvent.KEY_TYPED &&
+        nativeKeyEvent.keyChar.isPrintable()
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.desktop.kt
similarity index 74%
copy from compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
copy to compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.desktop.kt
index 7e01354..8ccabc0 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
+++ b/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/text/selection/TextFieldSelectionManager.desktop.kt
@@ -1,5 +1,3 @@
-// ktlint-disable filename
-
 /*
  * Copyright 2021 The Android Open Source Project
  *
@@ -16,6 +14,9 @@
  * limitations under the License.
  */
 
-package androidx.compose.foundation
+package androidx.compose.foundation.text.selection
 
-internal actual typealias AtomicReference<V> = java.util.concurrent.atomic.AtomicReference<V>
\ No newline at end of file
+import androidx.compose.ui.input.pointer.PointerEvent
+
+internal actual val PointerEvent.isShiftPressed: Boolean
+    get() = mouseEvent?.isShiftDown ?: false
\ No newline at end of file
diff --git a/compose/foundation/foundation/src/desktopTest/kotlin/androidx/compose/foundation/text/selection/DesktopTextFieldSelectionManagerTest.kt b/compose/foundation/foundation/src/desktopTest/kotlin/androidx/compose/foundation/text/selection/DesktopTextFieldSelectionManagerTest.kt
index b81bdd8..087ae76 100644
--- a/compose/foundation/foundation/src/desktopTest/kotlin/androidx/compose/foundation/text/selection/DesktopTextFieldSelectionManagerTest.kt
+++ b/compose/foundation/foundation/src/desktopTest/kotlin/androidx/compose/foundation/text/selection/DesktopTextFieldSelectionManagerTest.kt
@@ -18,14 +18,19 @@
 
 import androidx.compose.foundation.text.InternalFoundationTextApi
 import androidx.compose.foundation.text.TextFieldState
+import androidx.compose.foundation.text.TextLayoutResultProxy
+import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.hapticfeedback.HapticFeedback
 import androidx.compose.ui.platform.ClipboardManager
 import androidx.compose.ui.platform.TextToolbar
 import androidx.compose.ui.text.AnnotatedString
-import androidx.compose.ui.text.InternalTextApi
 import androidx.compose.ui.text.TextLayoutInput
+import androidx.compose.ui.text.TextLayoutResult
 import androidx.compose.ui.text.TextRange
 import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.input.EditProcessor
 import androidx.compose.ui.text.input.OffsetMapping
 import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.text.style.TextOverflow
@@ -33,6 +38,7 @@
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.LayoutDirection
 import com.google.common.truth.Truth.assertThat
+import com.nhaarman.mockitokotlin2.any
 import com.nhaarman.mockitokotlin2.mock
 import com.nhaarman.mockitokotlin2.times
 import com.nhaarman.mockitokotlin2.verify
@@ -49,35 +55,35 @@
     private val offsetMapping = OffsetMapping.Identity
     private var value = TextFieldValue(text)
     private val lambda: (TextFieldValue) -> Unit = { value = it }
-    private val state = TextFieldState(mock())
+    private lateinit var state: TextFieldState
 
     private val dragBeginPosition = Offset.Zero
-    private val dragLastPosition = Offset(300f, 15f)
+    private val dragDistance = Offset(300f, 15f)
     private val beginOffset = 0
     private val dragOffset = text.indexOf('r')
-    private val fakeTextRange = TextRange(0, "Hello".length)
-    private val dragTextRange = TextRange("Hello".length + 1, text.length)
-
-    private val manager = TextFieldSelectionManager()
+    private val layoutResult: TextLayoutResult = mock()
+    private val layoutResultProxy: TextLayoutResultProxy = mock()
+    private lateinit var manager: TextFieldSelectionManager
 
     private val clipboardManager = mock<ClipboardManager>()
     private val textToolbar = mock<TextToolbar>()
+    private val hapticFeedback = mock<HapticFeedback>()
+    private val focusRequester = mock<FocusRequester>()
+    private val processor = mock<EditProcessor>()
 
-    @OptIn(InternalFoundationTextApi::class, InternalTextApi::class)
+    @OptIn(InternalFoundationTextApi::class)
     @Before
     fun setup() {
+        manager = TextFieldSelectionManager()
         manager.offsetMapping = offsetMapping
         manager.onValueChange = lambda
-        manager.state = state
         manager.value = value
         manager.clipboardManager = clipboardManager
         manager.textToolbar = textToolbar
+        manager.hapticFeedBack = hapticFeedback
+        manager.focusRequester = focusRequester
 
-        state.layoutResult = mock()
-        state.textDelegate = mock()
-        whenever(state.layoutResult!!.value).thenReturn(mock())
-        whenever(state.textDelegate.density).thenReturn(density)
-        whenever(state.layoutResult!!.value.layoutInput).thenReturn(
+        whenever(layoutResult.layoutInput).thenReturn(
             TextLayoutInput(
                 text = AnnotatedString(text),
                 style = TextStyle.Default,
@@ -91,38 +97,64 @@
                 constraints = Constraints()
             )
         )
-        whenever(state.layoutResult!!.getOffsetForPosition(dragBeginPosition)).thenReturn(
-            beginOffset
-        )
-        whenever(state.layoutResult!!.getOffsetForPosition(dragLastPosition)).thenReturn(dragOffset)
 
-        state.processor.reset(value, state.inputSession)
+        whenever(layoutResult.getBoundingBox(any())).thenReturn(Rect.Zero)
+        whenever(layoutResult.getOffsetForPosition(dragBeginPosition)).thenReturn(beginOffset)
+        whenever(layoutResult.getOffsetForPosition(dragBeginPosition + dragDistance))
+            .thenReturn(dragOffset)
+        whenever(
+            layoutResultProxy.getOffsetForPosition(dragBeginPosition, false)
+        ).thenReturn(beginOffset)
+        whenever(
+            layoutResultProxy.getOffsetForPosition(dragBeginPosition + dragDistance, false)
+        ).thenReturn(dragOffset)
+        whenever(
+            layoutResultProxy.getOffsetForPosition(dragBeginPosition + dragDistance)
+        ).thenReturn(dragOffset)
+
+        whenever(layoutResultProxy.value).thenReturn(layoutResult)
+
+        state = TextFieldState(mock())
+        state.layoutResult = layoutResultProxy
+        state.processor.reset(value, null)
+        manager.state = state
+        whenever(state.textDelegate.density).thenReturn(density)
     }
 
     @Test
     fun TextFieldSelectionManager_mouseSelectionObserver_onStart() {
-        manager.mouseSelectionObserver { }.onStart(dragBeginPosition)
+        manager.mouseSelectionObserver.onDown(dragBeginPosition, false)
 
         assertThat(value.selection).isEqualTo(TextRange(0, 0))
 
-        manager.mouseSelectionObserver { }.onStart(dragLastPosition)
+        manager.mouseSelectionObserver.onDown(dragBeginPosition + dragDistance, false)
         assertThat(value.selection).isEqualTo(TextRange(8, 8))
     }
 
     @Test
+    fun TextFieldSelectionManager_mouseSelectionObserver_onStart_withShift() {
+        manager.mouseSelectionObserver.onDown(dragBeginPosition, false)
+
+        assertThat(value.selection).isEqualTo(TextRange(0, 0))
+
+        manager.mouseSelectionObserver.onDown(dragBeginPosition + dragDistance, true)
+        assertThat(value.selection).isEqualTo(TextRange(0, 8))
+    }
+
+    @Test
     fun TextFieldSelectionManager_mouseSelectionObserver_onDrag() {
-        val observer = manager.mouseSelectionObserver { }
-        observer.onStart(dragBeginPosition)
-        observer.onDrag(dragLastPosition)
+        val observer = manager.mouseSelectionObserver
+        observer.onDown(dragBeginPosition, false)
+        observer.onDrag(dragDistance)
 
         assertThat(value.selection).isEqualTo(TextRange(0, 8))
     }
 
     @Test
     fun TextFieldSelectionManager_mouseSelectionObserver_copy() {
-        val observer = manager.mouseSelectionObserver { }
-        observer.onStart(dragBeginPosition)
-        observer.onDrag(dragLastPosition)
+        val observer = manager.mouseSelectionObserver
+        observer.onDown(dragBeginPosition, false)
+        observer.onDrag(dragDistance)
 
         manager.value = value
         manager.copy(cancelSelection = false)
diff --git a/compose/foundation/foundation/src/jvmMain/kotlin/androidx/compose/foundation/text/StringHelpers.jvm.kt b/compose/foundation/foundation/src/jvmMain/kotlin/androidx/compose/foundation/text/StringHelpers.jvm.kt
new file mode 100644
index 0000000..83d6794
--- /dev/null
+++ b/compose/foundation/foundation/src/jvmMain/kotlin/androidx/compose/foundation/text/StringHelpers.jvm.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2021 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.compose.foundation.text
+
+import java.text.BreakIterator
+
+internal actual fun StringBuilder.appendCodePointX(codePoint: Int): StringBuilder =
+    this.appendCodePoint(codePoint)
+
+internal actual fun String.findPrecedingBreak(index: Int): Int {
+    val it = BreakIterator.getCharacterInstance()
+    it.setText(this)
+    return it.preceding(index)
+}
+
+internal actual fun String.findFollowingBreak(index: Int): Int {
+    val it = BreakIterator.getCharacterInstance()
+    it.setText(this)
+    return it.following(index)
+}
\ No newline at end of file
diff --git a/compose/integration-tests/benchmark/build.gradle b/compose/integration-tests/benchmark/build.gradle
index 6ef5588..dd47137 100644
--- a/compose/integration-tests/benchmark/build.gradle
+++ b/compose/integration-tests/benchmark/build.gradle
@@ -44,7 +44,7 @@
     androidTestImplementation(project(":compose:foundation:foundation"))
     androidTestImplementation(project(":compose:material:material"))
     androidTestImplementation(project(":compose:runtime:runtime"))
-    androidTestImplementation(project(":compose:test-utils"))
+    androidTestImplementation(project(":compose:benchmark-utils"))
     androidTestImplementation(project(":compose:ui:ui"))
     androidTestImplementation(project(":activity:activity-compose"))
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/compose/integration-tests/benchmark/src/androidTest/AndroidManifest.xml b/compose/integration-tests/benchmark/src/androidTest/AndroidManifest.xml
index d50b55c..c828266 100644
--- a/compose/integration-tests/benchmark/src/androidTest/AndroidManifest.xml
+++ b/compose/integration-tests/benchmark/src/androidTest/AndroidManifest.xml
@@ -27,6 +27,5 @@
         <!-- enable profileableByShell for non-intrusive profiling tools -->
         <!--suppress AndroidElementNotAllowed -->
         <profileable android:shell="true"/>
-        <activity android:name="androidx.ui.pointerinput.TestActivity" />
     </application>
 </manifest>
diff --git a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/ComponentWithModifiersTestCase.kt b/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/ComponentWithModifiersTestCase.kt
deleted file mode 100644
index dbf4fed..0000000
--- a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/ComponentWithModifiersTestCase.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.ui.integration.test.core
-
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.background
-import androidx.compose.foundation.border
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.unit.dp
-
-class ComponentWithModifiersTestCase : SimpleComponentImplenentationTestCase() {
-
-    @Composable
-    override fun Content() {
-        val innerSize = getInnerSize()
-        Box(
-            Modifier.size(48.dp)
-                .background(color = Color.Cyan)
-                .padding(innerSize.value)
-                .border(
-                    color = Color.Cyan,
-                    width = 1.dp,
-                    shape = CircleShape
-                )
-        )
-    }
-}
\ No newline at end of file
diff --git a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/ComponentWithRedrawTestCase.kt b/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/ComponentWithRedrawTestCase.kt
deleted file mode 100644
index 149ee4a..0000000
--- a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/ComponentWithRedrawTestCase.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2019 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.ui.integration.test.core
-
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.foundation.Canvas
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.drawscope.Stroke
-import androidx.compose.foundation.layout.size
-import androidx.compose.ui.unit.dp
-
-class ComponentWithRedrawTestCase : SimpleComponentImplenentationTestCase() {
-
-    @Composable
-    override fun Content() {
-        val innerSize = getInnerSize()
-        val stroke = Stroke()
-        Canvas(Modifier.size(48.dp)) {
-            drawCircle(Color.Black, size.minDimension, style = stroke)
-            drawCircle(Color.Black, innerSize.value.value / 2f, center)
-        }
-    }
-}
diff --git a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/ComponentWithTwoLayoutNodesTestCase.kt b/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/ComponentWithTwoLayoutNodesTestCase.kt
deleted file mode 100644
index b0482eb..0000000
--- a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/ComponentWithTwoLayoutNodesTestCase.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2019 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.ui.integration.test.core
-
-import androidx.compose.foundation.BorderStroke
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.Canvas
-import androidx.compose.foundation.border
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.drawOutline
-import androidx.compose.ui.unit.dp
-
-class ComponentWithTwoLayoutNodesTestCase : SimpleComponentImplenentationTestCase() {
-    @Composable
-    override fun Content() {
-        Box(
-            modifier = Modifier
-                .size(48.dp)
-                .border(BorderStroke(1.dp, Color.Cyan), CircleShape)
-                .padding(1.dp),
-            contentAlignment = Alignment.Center
-        ) {
-            val innerSize = getInnerSize().value
-            Canvas(Modifier.size(innerSize)) {
-                drawOutline(
-                    CircleShape.createOutline(size, layoutDirection, this),
-                    Color.Cyan
-                )
-            }
-        }
-    }
-}
diff --git a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/EmptyTestCase.kt b/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/EmptyTestCase.kt
deleted file mode 100644
index 8947a4b..0000000
--- a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/EmptyTestCase.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.ui.integration.test.core
-
-import androidx.compose.runtime.Composable
-import androidx.compose.testutils.ComposeTestCase
-
-class EmptyTestCase : ComposeTestCase {
-    @Composable
-    override fun Content() {
-    }
-}
\ No newline at end of file
diff --git a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/SimpleComponentImplenentationTestCase.kt b/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/SimpleComponentImplenentationTestCase.kt
deleted file mode 100644
index c992384..0000000
--- a/compose/integration-tests/src/main/java/androidx/ui/integration/test/core/SimpleComponentImplenentationTestCase.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2019 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.ui.integration.test.core
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.testutils.ComposeTestCase
-import androidx.compose.testutils.ToggleableTestCase
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.dp
-
-abstract class SimpleComponentImplenentationTestCase : ComposeTestCase, ToggleableTestCase {
-
-    private var state: MutableState<Dp>? = null
-
-    @Composable
-    fun getInnerSize(): MutableState<Dp> {
-        val innerSize = remember { mutableStateOf(10.dp) }
-        state = innerSize
-        return innerSize
-    }
-
-    override fun toggleState() {
-        with(state!!) {
-            value = if (value == 10.dp) {
-                20.dp
-            } else {
-                10.dp
-            }
-        }
-    }
-}
diff --git a/compose/internal-lint-checks/src/main/java/androidx/compose/lint/UnnecessaryLambdaCreationDetector.kt b/compose/internal-lint-checks/src/main/java/androidx/compose/lint/UnnecessaryLambdaCreationDetector.kt
index 60ca677..3806120 100644
--- a/compose/internal-lint-checks/src/main/java/androidx/compose/lint/UnnecessaryLambdaCreationDetector.kt
+++ b/compose/internal-lint-checks/src/main/java/androidx/compose/lint/UnnecessaryLambdaCreationDetector.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("UnstableApiUsage")
+
 package androidx.compose.lint
 
 import com.android.tools.lint.client.api.UElementHandler
@@ -25,12 +27,14 @@
 import com.android.tools.lint.detector.api.Scope
 import com.android.tools.lint.detector.api.Severity
 import com.android.tools.lint.detector.api.SourceCodeScanner
-import com.intellij.psi.PsiElement
 import com.intellij.psi.impl.source.PsiClassReferenceType
 import org.jetbrains.kotlin.psi.KtCallExpression
 import org.jetbrains.kotlin.psi.KtCallableDeclaration
+import org.jetbrains.kotlin.psi.KtTypeReference
 import org.jetbrains.kotlin.psi.psiUtil.referenceExpression
+import org.jetbrains.uast.UAnnotation
 import org.jetbrains.uast.ULambdaExpression
+import org.jetbrains.uast.UMethod
 import org.jetbrains.uast.kotlin.KotlinUBlockExpression
 import org.jetbrains.uast.kotlin.KotlinUFunctionCallExpression
 import org.jetbrains.uast.kotlin.KotlinUImplicitReturnExpression
@@ -135,14 +139,31 @@
             // matches this lambda expression's invocation
             val parameterIndex = parentExpression.valueArguments.indexOf(node)
 
-            // If we cannot resolve the parent expression as a KtCallableDeclaration, it might be a
-            // Java method / exist in bytecode or some other format, so just ignore it as we won't
-            // be able to see @Composable there anyway.
-            val parentDeclaration = parentExpression.resolveToUElement()
-                ?.sourcePsi as? KtCallableDeclaration ?: return
+            // Parent expression source declaration
+            val parentDeclaration = parentExpression.resolveToUElement() as? UMethod ?: return
 
-            val expectedComposable =
-                parentDeclaration.valueParameters[parameterIndex]!!.isComposable
+            val expectedComposable = when (val source = parentDeclaration.sourcePsi) {
+                // The source is in Kotlin source, so check the parameter for @Composable
+                is KtCallableDeclaration -> {
+                    // Currently type annotations don't appear on the psiType, so we have to look
+                    // through the type reference (https://youtrack.jetbrains.com/issue/KT-45244)
+                    val typeReference = source.valueParameters[parameterIndex]!!
+                        .typeReference as KtTypeReference
+                    typeReference.annotationEntries.any {
+                        (it.toUElement() as UAnnotation).qualifiedName == ComposableFqn
+                    }
+                }
+                // If we cannot resolve the parent expression as a KtCallableDeclaration, then
+                // the source is Java source, or in a class file. We ignore Java source, and
+                // currently there is no way to see the @Composable annotation in the class file
+                // (https://youtrack.jetbrains.com/issue/KT-45244). Instead we can look for the
+                // presence of a `Composer` parameter, as this is added by the Compose compiler
+                // to every Composable function / lambda.
+                else -> {
+                    parentDeclaration.uastParameters[parameterIndex].type.canonicalText
+                        .contains(ComposerFqn)
+                }
+            }
 
             // Hack to get the psi of the lambda declaration / source. The !!s here probably
             // aren't safe, but nothing fails with them currently - so it could be a useful
@@ -150,7 +171,14 @@
             val resolvedLambda = expression.sourcePsi.calleeExpression!!.toUElement()!!.tryResolve()
                 .toUElement()!!.sourcePsi!!
 
-            val isComposable = resolvedLambda.isComposable
+            // Unfortunately as Composability isn't carried through UAST, and there are many types
+            // of declarations (types such as foo: @Composable () -> Unit, properties such as val
+            // foo = @Composable {}) the best way to cover this is just check if we contain this
+            // annotation in text. Definitely not ideal, but it should cover most cases so it is
+            // the simplest way for now. Note in particular this will return true for (rare) cases
+            // like (@Composable () -> Unit) -> Unit, so this might need to be updated in the
+            // future if this becomes a common problem.
+            val isComposable = resolvedLambda.text.contains("@Composable")
 
             if (isComposable != expectedComposable) return
 
@@ -189,13 +217,5 @@
     }
 }
 
-/**
- * @return whether this [PsiElement] contains @Composable in its source
- */
-private val PsiElement.isComposable: Boolean
-    // Unfortunately as Composability isn't carried through UAST, and there are many types of
-    // declarations (types such as foo: @Composable () -> Unit, properties such as val
-    // foo = @Composable {}) the best way to cover this is just check if we contain this annotation
-    // in text. Definitely not ideal, but it should cover most cases and ignores false positives, so
-    // it's the best solution for now.
-    get() = text.contains("@Composable")
+private const val ComposableFqn = "androidx.compose.runtime.Composable"
+private const val ComposerFqn = "androidx.compose.runtime.Composer"
diff --git a/compose/internal-lint-checks/src/test/java/androidx/compose/lint/UnnecessaryLambdaCreationDetectorTest.kt b/compose/internal-lint-checks/src/test/java/androidx/compose/lint/UnnecessaryLambdaCreationDetectorTest.kt
index 8d97a2d..12a1f87 100644
--- a/compose/internal-lint-checks/src/test/java/androidx/compose/lint/UnnecessaryLambdaCreationDetectorTest.kt
+++ b/compose/internal-lint-checks/src/test/java/androidx/compose/lint/UnnecessaryLambdaCreationDetectorTest.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("UnstableApiUsage")
+
 package androidx.compose.lint
 
 import com.android.tools.lint.checks.infrastructure.TestFiles.kt
@@ -29,11 +31,27 @@
 @RunWith(JUnit4::class)
 class UnnecessaryLambdaCreationDetectorTest {
 
+    private val composableStub = kt(
+        """
+        package androidx.compose.runtime
+
+        @MustBeDocumented
+        @Retention(AnnotationRetention.BINARY)
+        @Target(
+            AnnotationTarget.FUNCTION,
+            AnnotationTarget.TYPE,
+            AnnotationTarget.TYPE_PARAMETER,
+            AnnotationTarget.PROPERTY
+        )
+        annotation class Composable
+    """
+    )
+
     private val stub = kt(
         """
         package test
 
-        annotation class Composable
+        import androidx.compose.runtime.Composable
 
         val lambda = @Composable { }
         val anonymousFunction = @Composable fun() {}
@@ -43,14 +61,14 @@
 
         @Composable
         fun ComposableFunction(content: @Composable () -> Unit) {
-            children()
+            content()
         }
     """
-    ).indented().within("src")
+    ).to("test/stub.kt")
 
     private fun check(@Language("kotlin") code: String): TestLintResult {
         return TestLintTask.lint()
-            .files(kt(code.trimIndent()), stub)
+            .files(kt(code.trimIndent()), stub, composableStub)
             .allowMissingSdk(true)
             .issues(ISSUE)
             .run()
@@ -62,6 +80,8 @@
             """
             package test
 
+            import androidx.compose.runtime.Composable
+
             @Composable
             fun Test() {
                 ComposableFunction {
@@ -87,10 +107,10 @@
         """
         ).expect(
             """
-src/test/test.kt:6: Error: Creating an unnecessary lambda to emit a captured lambda [UnnecessaryLambdaCreation]
+src/test/test.kt:8: Error: Creating an unnecessary lambda to emit a captured lambda [UnnecessaryLambdaCreation]
         lambda()
         ~~~~~~
-src/test/test.kt:10: Error: Creating an unnecessary lambda to emit a captured lambda [UnnecessaryLambdaCreation]
+src/test/test.kt:12: Error: Creating an unnecessary lambda to emit a captured lambda [UnnecessaryLambdaCreation]
         anonymousFunction()
         ~~~~~~~~~~~~~~~~~
 2 errors, 0 warnings
@@ -104,9 +124,11 @@
             """
             package test
 
+            import androidx.compose.runtime.Composable
+
             @Composable
             fun MultipleChildComposableFunction(
-                firstChild: @Composable () -> Unit, 
+                firstChild: @Composable () -> Unit,
                 secondChild: @Composable () -> Unit
             ) {}
 
@@ -119,10 +141,10 @@
         """
         ).expect(
             """
-src/test/test.kt:11: Error: Creating an unnecessary lambda to emit a captured lambda [UnnecessaryLambdaCreation]
+src/test/test.kt:13: Error: Creating an unnecessary lambda to emit a captured lambda [UnnecessaryLambdaCreation]
     MultipleChildComposableFunction( { lambda() }) {
                                        ~~~~~~
-src/test/test.kt:12: Error: Creating an unnecessary lambda to emit a captured lambda [UnnecessaryLambdaCreation]
+src/test/test.kt:14: Error: Creating an unnecessary lambda to emit a captured lambda [UnnecessaryLambdaCreation]
         lambda()
         ~~~~~~
 2 errors, 0 warnings
@@ -136,6 +158,8 @@
             """
             package test
 
+            import androidx.compose.runtime.Composable
+
             @Composable
             fun Test() {
                 ComposableFunction {
@@ -153,6 +177,8 @@
             """
             package test
 
+            import androidx.compose.runtime.Composable
+
             val property: @Composable () -> Unit = {
                 lambda()
             }
@@ -161,28 +187,12 @@
     }
 
     @Test
-    fun ignoresLayoutNodes() {
-        check(
-            """
-            package test
-
-            class FooNode(val foo: String)
-
-            @Composable
-            fun Test() {
-                FooNode(foo) { 
-                    lambda()
-                }
-            }
-        """
-        ).expectClean()
-    }
-
-    @Test
     fun ignoresDifferentFunctionalTypes_parameters() {
         check(
             """
-            package test 
+            package test
+
+            import androidx.compose.runtime.Composable
 
             @Composable
             fun ComposableFunctionWithParams(
@@ -200,22 +210,22 @@
             val differentlyParameterizedLambda: (Int) -> Unit = { }
 
             @Composable
-            fun Test() {
-                ComposableFunctionWithParams { child -> 
+            fun Test1() {
+                ComposableFunctionWithParams { child ->
                     parameterizedLambda(child)
                 }
-            } 
+            }
 
             @Composable
-            fun Test() {
-                ComposableFunctionWithParams { child -> 
+            fun Test2() {
+                ComposableFunctionWithParams { child ->
                     differentlyParameterizedLambda(5)
                 }
             }
         """
         ).expect(
             """
-src/test/test.kt:21: Error: Creating an unnecessary lambda to emit a captured lambda [UnnecessaryLambdaCreation]
+src/test/test.kt:23: Error: Creating an unnecessary lambda to emit a captured lambda [UnnecessaryLambdaCreation]
         parameterizedLambda(child)
         ~~~~~~~~~~~~~~~~~~~
 1 errors, 0 warnings
@@ -229,12 +239,14 @@
             """
             package test
 
+            import androidx.compose.runtime.Composable
+
             class SomeScope
             class OtherScope
 
             @Composable
             fun ScopedComposableFunction(content: @Composable SomeScope.() -> Unit) {
-                children()
+                SomeScope().content()
             }
 
             @Composable
@@ -252,13 +264,13 @@
                 }
 
                 ScopedComposableFunction {
-                    differentlyScopedLambda()
+                    OtherScope().differentlyScopedLambda()
                 }
             }
         """
         ).expect(
             """
-src/test/SomeScope.kt:22: Error: Creating an unnecessary lambda to emit a captured lambda [UnnecessaryLambdaCreation]
+src/test/SomeScope.kt:24: Error: Creating an unnecessary lambda to emit a captured lambda [UnnecessaryLambdaCreation]
         scopedLambda()
         ~~~~~~~~~~~~
 1 errors, 0 warnings
@@ -272,6 +284,8 @@
             """
             package test
 
+            import androidx.compose.runtime.Composable
+
             fun uncomposableLambdaFunction(child: () -> Unit) {}
 
             val uncomposableLambda = {}
diff --git a/compose/material/material/benchmark/build.gradle b/compose/material/material/benchmark/build.gradle
index 91478ed..1c2ce1b 100644
--- a/compose/material/material/benchmark/build.gradle
+++ b/compose/material/material/benchmark/build.gradle
@@ -35,7 +35,7 @@
     androidTestImplementation project(":compose:foundation:foundation")
     androidTestImplementation project(":compose:material:material")
     androidTestImplementation project(":compose:runtime:runtime")
-    androidTestImplementation project(":compose:test-utils")
+    androidTestImplementation project(":compose:benchmark-utils")
     androidTestImplementation(ANDROIDX_TEST_RULES)
     androidTestImplementation(JUNIT)
     androidTestImplementation(KOTLIN_STDLIB)
diff --git a/compose/material/material/integration-tests/material-studies/src/main/java/androidx/compose/material/studies/rally/OverviewScreen.kt b/compose/material/material/integration-tests/material-studies/src/main/java/androidx/compose/material/studies/rally/OverviewScreen.kt
index bbd968b..04f9619 100644
--- a/compose/material/material/integration-tests/material-studies/src/main/java/androidx/compose/material/studies/rally/OverviewScreen.kt
+++ b/compose/material/material/integration-tests/material-studies/src/main/java/androidx/compose/material/studies/rally/OverviewScreen.kt
@@ -16,7 +16,6 @@
 
 package androidx.compose.material.studies.rally
 
-import android.annotation.SuppressLint
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
@@ -136,7 +135,6 @@
 /**
  * Base structure for cards in the Overview screen.
  */
-@SuppressLint("UnnecessaryLambdaCreation")
 @Composable
 private fun <T> OverviewScreenCard(
     title: String,
diff --git a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/BackdropScaffoldSamples.kt b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/BackdropScaffoldSamples.kt
index bf22d25..6ce3aef 100644
--- a/compose/material/material/samples/src/main/java/androidx/compose/material/samples/BackdropScaffoldSamples.kt
+++ b/compose/material/material/samples/src/main/java/androidx/compose/material/samples/BackdropScaffoldSamples.kt
@@ -33,6 +33,7 @@
 import androidx.compose.material.icons.filled.Menu
 import androidx.compose.material.rememberBackdropScaffoldState
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
@@ -50,6 +51,9 @@
     val scope = rememberCoroutineScope()
     val selection = remember { mutableStateOf(1) }
     val scaffoldState = rememberBackdropScaffoldState(BackdropValue.Concealed)
+    LaunchedEffect(scaffoldState) {
+        scaffoldState.reveal()
+    }
     BackdropScaffold(
         scaffoldState = scaffoldState,
         appBar = {
@@ -86,7 +90,7 @@
         },
         backLayerContent = {
             LazyColumn {
-                items(5) {
+                items(if (selection.value >= 3) 3 else 5) {
                     ListItem(
                         Modifier.clickable {
                             selection.value = it
diff --git a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/BackdropScaffoldTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/BackdropScaffoldTest.kt
index 12b0e86..9e194c0 100644
--- a/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/BackdropScaffoldTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/BackdropScaffoldTest.kt
@@ -16,13 +16,22 @@
 
 package androidx.compose.material
 
+import androidx.compose.foundation.background
 import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
 import androidx.compose.material.BackdropValue.Concealed
 import androidx.compose.material.BackdropValue.Revealed
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.platform.testTag
@@ -42,6 +51,8 @@
 import androidx.test.filters.LargeTest
 import androidx.test.filters.MediumTest
 import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.runBlocking
 import org.junit.Rule
 import org.junit.Test
@@ -265,6 +276,159 @@
         }
     }
 
+    /**
+     * Tests that the state and offset of [swipeable] are updated when swiping.
+     */
+    @Test
+    fun backdropScaffold_syncThresholdUpdate() {
+        val increasedAnchor = mutableStateOf(false)
+        val scaffoldState = BackdropScaffoldState(Revealed)
+        rule.setContent {
+            BackdropScaffold(
+                scaffoldState = scaffoldState,
+                frontLayerScrimColor = Color.Red,
+                appBar = { },
+                backLayerContent = {
+                    Box(
+                        Modifier
+                            .height(if (increasedAnchor.value) 400.dp else 200.dp)
+                            .background(Color.Blue)
+                    )
+                },
+                frontLayerContent = {
+                    Box(Modifier.height(1000.dp).testTag(frontLayer).background(Color.Yellow))
+                }
+            )
+        }
+
+        val revealedOffset = rule.runOnIdle {
+            assertThat(scaffoldState.currentValue).isEqualTo(BackdropValue.Revealed)
+            // state change changes the anchors, causing the recalculation
+            increasedAnchor.value = true
+            scaffoldState.offset.value
+        }
+
+        rule.runOnIdle {
+            assertThat(scaffoldState.offset.value).isNotEqualTo(revealedOffset)
+            // swap back, causing threshold update during update-caused settle
+            increasedAnchor.value = false
+        }
+
+        rule.runOnIdle {
+            // no crash and assert passes
+            assertThat(scaffoldState.offset.value).isEqualTo(revealedOffset)
+        }
+    }
+
+    @Test
+    fun backdropScaffold_animatesAsSideEffect() {
+
+        val bottomSheetState = ModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
+
+        @Composable
+        fun BottomSheet(message: String?) {
+            Text(
+                text = message ?: "",
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .background(color = MaterialTheme.colors.primary)
+                    .padding(vertical = 50.dp),
+                color = MaterialTheme.colors.onPrimary
+            )
+        }
+
+        @Composable
+        fun BottomSheetScreen(message: String?) {
+
+            LaunchedEffect(bottomSheetState) {
+                bottomSheetState.show()
+            }
+
+            ModalBottomSheetLayout(
+                modifier = Modifier.fillMaxSize(),
+                sheetContent = {
+                    BottomSheet(message = message)
+                },
+                sheetState = bottomSheetState
+            ) {
+                Column(
+                    modifier = Modifier.fillMaxSize(),
+                    verticalArrangement = Arrangement.Center,
+                    horizontalAlignment = Alignment.CenterHorizontally
+                ) {
+                    Text("Should the modal be visible: ${message != null}")
+                }
+            }
+        }
+
+        rule.setContent {
+            BottomSheetScreen(message = "")
+        }
+
+        rule.runOnIdle {
+            assertThat(bottomSheetState.currentValue).isEqualTo(ModalBottomSheetValue.Expanded)
+        }
+    }
+
+    @Test
+    fun backdropScaffold_animatesAsSideEffect_fromNull() {
+
+        @Composable
+        fun BottomSheet(message: String?) {
+            Text(
+                text = message ?: "",
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .background(color = MaterialTheme.colors.primary)
+                    .padding(vertical = 50.dp),
+                color = MaterialTheme.colors.onPrimary
+            )
+        }
+
+        @Composable
+        fun BottomSheetScreen(message: String?) {
+            val bottomSheetState =
+                rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
+
+            LaunchedEffect(bottomSheetState, message != null) {
+                if (message != null) {
+                    try {
+                        bottomSheetState.show()
+                    } catch (ex: CancellationException) {
+                        assertWithMessage("shouldn't cancel").fail()
+                    }
+                }
+            }
+
+            ModalBottomSheetLayout(
+                modifier = Modifier.fillMaxSize(),
+                sheetContent = {
+                    BottomSheet(message = message)
+                },
+                sheetState = bottomSheetState
+            ) {
+                Column(
+                    modifier = Modifier.fillMaxSize(),
+                    verticalArrangement = Arrangement.Center,
+                    horizontalAlignment = Alignment.CenterHorizontally
+                ) {
+                    Text("Should the modal be visible: ${message != null}")
+                }
+            }
+        }
+
+        val stringState = mutableStateOf<String?>(null)
+
+        rule.setContent {
+            BottomSheetScreen(message = stringState.value)
+        }
+
+        rule.runOnIdle {
+            stringState.value = "line 1 \n line2 \n line 3"
+        }
+        rule.waitForIdle()
+    }
+
     @Test
     fun backdropScaffold_concealByTapingOnFrontLayer() {
         lateinit var scaffoldState: BackdropScaffoldState
diff --git a/compose/integration-tests/src/androidTest/java/androidx/ui/integration/test/ObservableThemeTest.kt b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ObservableThemeTest.kt
similarity index 99%
rename from compose/integration-tests/src/androidTest/java/androidx/ui/integration/test/ObservableThemeTest.kt
rename to compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ObservableThemeTest.kt
index 11ecac7..b3ed829 100644
--- a/compose/integration-tests/src/androidTest/java/androidx/ui/integration/test/ObservableThemeTest.kt
+++ b/compose/material/material/src/androidAndroidTest/kotlin/androidx/compose/material/ObservableThemeTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.ui.integration.test
+package androidx.compose.material
 
 import androidx.activity.ComponentActivity
 import androidx.compose.runtime.Composable
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/MaterialTheme.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/MaterialTheme.kt
index e41a07e..2197990 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/MaterialTheme.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/MaterialTheme.kt
@@ -59,11 +59,7 @@
     shapes: Shapes = MaterialTheme.shapes,
     content: @Composable () -> Unit
 ) {
-    val rememberedColors = remember {
-        // TODO: b/162450508 remove the unnecessary .copy() here when it isn't needed to ensure that
-        // we don't skip the updateColorsFrom call
-        colors.copy()
-    }.apply { updateColorsFrom(colors) }
+    val rememberedColors = remember { colors }.apply { updateColorsFrom(colors) }
     val rippleIndication = rememberRipple()
     val selectionColors = rememberTextSelectionColors(rememberedColors)
     CompositionLocalProvider(
diff --git a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
index 8cbec9a..42acda2 100644
--- a/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
+++ b/compose/material/material/src/commonMain/kotlin/androidx/compose/material/Swipeable.kt
@@ -20,9 +20,9 @@
 import androidx.compose.animation.core.AnimationSpec
 import androidx.compose.animation.core.SpringSpec
 import androidx.compose.foundation.gestures.DraggableState
-import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.gestures.draggable
+import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.material.SwipeableDefaults.AnimationSpec
 import androidx.compose.material.SwipeableDefaults.StandardResistanceFactor
 import androidx.compose.material.SwipeableDefaults.VelocityThreshold
@@ -31,7 +31,6 @@
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.Immutable
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.SideEffect
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.State
 import androidx.compose.runtime.getValue
@@ -40,6 +39,7 @@
 import androidx.compose.runtime.saveable.Saver
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshotFlow
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.composed
 import androidx.compose.ui.geometry.Offset
@@ -54,6 +54,10 @@
 import androidx.compose.ui.util.lerp
 import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.take
 import kotlinx.coroutines.launch
 import kotlin.math.PI
 import kotlin.math.abs
@@ -120,6 +124,11 @@
 
     internal var anchors by mutableStateOf(emptyMap<Float, T>())
 
+    private val latestNonEmptyAnchorsFlow: Flow<Map<Float, T>> =
+        snapshotFlow { anchors }
+            .filter { it.isNotEmpty() }
+            .take(1)
+
     internal var minBound = Float.NEGATIVE_INFINITY
     internal var maxBound = Float.POSITIVE_INFINITY
 
@@ -286,16 +295,14 @@
      */
     @ExperimentalMaterialApi
     suspend fun snapTo(targetValue: T) {
-        val targetOffset = anchors.getOffset(targetValue)
-        require(anchors.isNotEmpty()) {
-            "State $this is not attached to a component. Have you passed state object to " +
-                "a component?"
+        latestNonEmptyAnchorsFlow.collect { anchors ->
+            val targetOffset = anchors.getOffset(targetValue)
+            requireNotNull(targetOffset) {
+                "The target value must have an associated anchor."
+            }
+            snapInternalToOffset(targetOffset)
+            currentValue = targetValue
         }
-        requireNotNull(targetOffset) {
-            "The target value must have an associated anchor."
-        }
-        snapInternalToOffset(targetOffset)
-        currentValue = targetValue
     }
 
     /**
@@ -306,23 +313,21 @@
      */
     @ExperimentalMaterialApi
     suspend fun animateTo(targetValue: T, anim: AnimationSpec<Float> = animationSpec) {
-        try {
-            val targetOffset = anchors.getOffset(targetValue)
-            require(anchors.isNotEmpty()) {
-                "State $this is not attached to a component. Have you passed state object to " +
-                    "a component?"
+        latestNonEmptyAnchorsFlow.collect { anchors ->
+            try {
+                val targetOffset = anchors.getOffset(targetValue)
+                requireNotNull(targetOffset) {
+                    "The target value must have an associated anchor."
+                }
+                animateInternalToOffset(targetOffset, anim)
+            } finally {
+                val endOffset = absoluteOffset.value
+                val endValue = anchors
+                    // fighting rounding error once again, anchor should be as close as 0.5 pixels
+                    .filterKeys { anchorOffset -> abs(anchorOffset - endOffset) < 0.5f }
+                    .values.firstOrNull() ?: currentValue
+                currentValue = endValue
             }
-            requireNotNull(targetOffset) {
-                "The target value must have an associated anchor."
-            }
-            return animateInternalToOffset(targetOffset, anim)
-        } finally {
-            val endOffset = absoluteOffset.value
-            val endValue = anchors
-                // fighting rounding error once again, anchor should be as close as 0.5 pixels
-                .filterKeys { anchorOffset -> abs(anchorOffset - endOffset) < 0.5f }
-                .values.firstOrNull() ?: currentValue
-            currentValue = endValue
         }
     }
 
@@ -340,19 +345,21 @@
      * @return the reason fling ended
      */
     suspend fun performFling(velocity: Float) {
-        val lastAnchor = anchors.getOffset(currentValue)!!
-        val targetValue = computeTarget(
-            offset = offset.value,
-            lastValue = lastAnchor,
-            anchors = anchors.keys,
-            thresholds = thresholds,
-            velocity = velocity,
-            velocityThreshold = velocityThreshold
-        )
-        val targetState = anchors[targetValue]
-        if (targetState != null && confirmStateChange(targetState)) animateTo(targetState)
-        // If the user vetoed the state change, rollback to the previous state.
-        else animateInternalToOffset(lastAnchor, animationSpec)
+        latestNonEmptyAnchorsFlow.collect { anchors ->
+            val lastAnchor = anchors.getOffset(currentValue)!!
+            val targetValue = computeTarget(
+                offset = offset.value,
+                lastValue = lastAnchor,
+                anchors = anchors.keys,
+                thresholds = thresholds,
+                velocity = velocity,
+                velocityThreshold = velocityThreshold
+            )
+            val targetState = anchors[targetValue]
+            if (targetState != null && confirmStateChange(targetState)) animateTo(targetState)
+            // If the user vetoed the state change, rollback to the previous state.
+            else animateInternalToOffset(lastAnchor, animationSpec)
+        }
     }
 
     /**
@@ -570,10 +577,10 @@
     }
     val density = LocalDensity.current
     state.ensureInit(anchors)
-    val oldAnchors = state.anchors
-    state.anchors = anchors
     LaunchedEffect(anchors) {
-        state.processNewAnchors(oldAnchors, anchors)
+        val oldAnchors = state.anchors
+        state.anchors = anchors
+        state.resistance = resistance
         state.thresholds = { a, b ->
             val from = anchors.getValue(a)
             val to = anchors.getValue(b)
@@ -582,9 +589,7 @@
         with(density) {
             state.velocityThreshold = velocityThreshold.toPx()
         }
-    }
-    SideEffect {
-        state.resistance = resistance
+        state.processNewAnchors(oldAnchors, anchors)
     }
 
     Modifier.draggable(
diff --git a/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/ComposableLambdaParameterDetector.kt b/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/ComposableLambdaParameterDetector.kt
index 704b120..4e93399 100644
--- a/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/ComposableLambdaParameterDetector.kt
+++ b/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/ComposableLambdaParameterDetector.kt
@@ -32,9 +32,11 @@
 import org.jetbrains.kotlin.psi.KtFunctionType
 import org.jetbrains.kotlin.psi.KtNullableType
 import org.jetbrains.kotlin.psi.KtParameter
+import org.jetbrains.uast.UAnnotation
 import org.jetbrains.uast.UElement
 import org.jetbrains.uast.UMethod
 import org.jetbrains.uast.UParameter
+import org.jetbrains.uast.toUElement
 import java.util.EnumSet
 
 /**
@@ -72,10 +74,11 @@
 
                 val typeReference = ktParameter.typeReference!!
 
-                val hasComposableAnnotationOnType = typeReference.modifierList?.annotationEntries
-                    ?.any {
-                        it.shortName?.identifier == ComposableShortName
-                    }
+                // Ideally this annotation should be available on the PsiType itself
+                // https://youtrack.jetbrains.com/issue/KT-45244
+                val hasComposableAnnotationOnType = typeReference.annotationEntries.any {
+                    (it.toUElement() as UAnnotation).qualifiedName == ComposableFqn
+                }
 
                 val functionType = when (val typeElement = typeReference.typeElement) {
                     is KtFunctionType -> typeElement
@@ -83,7 +86,7 @@
                     else -> null
                 }
 
-                if (functionType != null && hasComposableAnnotationOnType == true) {
+                if (functionType != null && hasComposableAnnotationOnType) {
                     ComposableLambdaParameterInfo(parameter, functionType)
                 } else {
                     null
diff --git a/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/RememberDetector.kt b/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/RememberDetector.kt
index d05d0b1..74ff784e 100644
--- a/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/RememberDetector.kt
+++ b/compose/runtime/runtime-lint/src/main/java/androidx/compose/runtime/lint/RememberDetector.kt
@@ -18,7 +18,6 @@
 
 package androidx.compose.runtime.lint
 
-import com.android.tools.lint.client.api.UElementHandler
 import com.android.tools.lint.detector.api.Category
 import com.android.tools.lint.detector.api.Detector
 import com.android.tools.lint.detector.api.Implementation
@@ -28,6 +27,7 @@
 import com.android.tools.lint.detector.api.Severity
 import com.android.tools.lint.detector.api.SourceCodeScanner
 import com.intellij.psi.PsiJavaFile
+import com.intellij.psi.PsiMethod
 import com.intellij.psi.PsiType
 import org.jetbrains.uast.UCallExpression
 import java.util.EnumSet
@@ -36,22 +36,17 @@
  * [Detector] that checks `remember` calls to make sure they are not returning [Unit].
  */
 class RememberDetector : Detector(), SourceCodeScanner {
-    override fun getApplicableUastTypes() = listOf(UCallExpression::class.java)
+    override fun getApplicableMethodNames(): List<String> = listOf(RememberShortName)
 
-    override fun createUastHandler(context: JavaContext) = object : UElementHandler() {
-        override fun visitCallExpression(node: UCallExpression) {
-            val call = node.resolve() ?: return
-            if (call.name == RememberShortName &&
-                (call.containingFile as? PsiJavaFile)?.packageName == RuntimePackageName
-            ) {
-                if (node.getExpressionType() == PsiType.VOID) {
-                    context.report(
-                        RememberReturnType,
-                        node,
-                        context.getNameLocation(node),
-                        "`remember` calls must not return `Unit`"
-                    )
-                }
+    override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+        if ((method.containingFile as? PsiJavaFile)?.packageName == RuntimePackageName) {
+            if (node.getExpressionType() == PsiType.VOID) {
+                context.report(
+                    RememberReturnType,
+                    node,
+                    context.getNameLocation(node),
+                    "`remember` calls must not return `Unit`"
+                )
             }
         }
     }
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
index f886ebb..9a91f829 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
@@ -21,6 +21,8 @@
 package androidx.compose.runtime
 
 import androidx.compose.runtime.collection.IdentityScopeMap
+import androidx.compose.runtime.snapshots.fastForEach
+import androidx.compose.runtime.snapshots.fastToSet
 import androidx.compose.runtime.tooling.LocalInspectionTables
 import androidx.compose.runtime.tooling.CompositionData
 import kotlinx.collections.immutable.PersistentMap
@@ -1331,7 +1333,8 @@
         fun dispatchRememberObservers() {
             // Send forgets
             if (forgetting.isNotEmpty()) {
-                for (instance in forgetting.reversed()) {
+                for (index in forgetting.indices.reversed()) {
+                    val instance = forgetting[index]
                     if (instance !in abandoning)
                         instance.onForgotten()
                 }
@@ -1339,7 +1342,7 @@
 
             // Send remembers
             if (remembering.isNotEmpty()) {
-                for (instance in remembering) {
+                remembering.fastForEach { instance ->
                     abandoning.remove(instance)
                     instance.onRemembered()
                 }
@@ -1383,7 +1386,7 @@
                 // Apply all changes
                 slotTable.write { slots ->
                     val applier = applier
-                    changes.forEach { change ->
+                    changes.fastForEach { change ->
                         change(applier, slots, manager)
                     }
                     changes.clear()
@@ -2075,7 +2078,7 @@
 
             // usedKeys contains the keys that were used in the new composition, therefore if a key
             // doesn't exist in this set, it needs to be removed.
-            val usedKeys = current.toSet()
+            val usedKeys = current.fastToSet()
 
             val placedKeys = mutableSetOf<KeyInfo>()
             var currentIndex = 0
@@ -2803,7 +2806,7 @@
             val insertTable = insertTable
             recordSlotEditingOperation { applier, slots, rememberManager ->
                 insertTable.write { writer ->
-                    for (fixup in fixups) {
+                    fixups.fastForEach { fixup ->
                         fixup(applier, writer, rememberManager)
                     }
                 }
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt
index 89aa1ecc..ddd647c 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/ListUtils.kt
@@ -21,3 +21,7 @@
         block(this[index])
     }
 }
+
+internal fun <T> List<T>.fastToSet(): Set<T> = HashSet<T>(size).also { set ->
+    fastForEach { item -> set.add(item) }
+}
\ No newline at end of file
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
index 4ae8e9c..2f73c00 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/snapshots/Snapshot.kt
@@ -1427,7 +1427,7 @@
     val modified = previousGlobalSnapshot.modified
     if (modified != null) {
         val observers = sync { applyObservers.toList() }
-        for (observer in observers) {
+        observers.fastForEach { observer ->
             observer(modified, previousGlobalSnapshot)
         }
     }
diff --git a/compose/test-utils/build.gradle b/compose/test-utils/build.gradle
index 6c57480..feae637 100644
--- a/compose/test-utils/build.gradle
+++ b/compose/test-utils/build.gradle
@@ -42,9 +42,9 @@
         api(project(":test-screenshot"))
 
         implementation(KOTLIN_STDLIB_COMMON)
-        implementation(project(":benchmark:benchmark-junit4"))
         implementation(project(":compose:runtime:runtime"))
-        implementation(project(":compose:ui:ui"))
+        implementation(project(":compose:ui:ui-unit"))
+        implementation(project(":compose:ui:ui-graphics"))
         implementation(ANDROIDX_TEST_RULES)
 
         // This has stub APIs for access to legacy Android APIs, so we don't want
@@ -68,9 +68,9 @@
         sourceSets {
             commonMain.dependencies {
                 implementation(KOTLIN_STDLIB_COMMON)
-                implementation(project(":benchmark:benchmark-junit4"))
                 implementation(project(":compose:runtime:runtime"))
-                implementation(project(":compose:ui:ui"))
+                implementation(project(":compose:ui:ui-unit"))
+                implementation(project(":compose:ui:ui-graphics"))
                 implementation(project(":compose:ui:ui-test-junit4"))
             }
 
diff --git a/compose/ui/ui-graphics/benchmark/build.gradle b/compose/ui/ui-graphics/benchmark/build.gradle
new file mode 100644
index 0000000..dcb734b
--- /dev/null
+++ b/compose/ui/ui-graphics/benchmark/build.gradle
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2021 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.Publish
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("AndroidXUiPlugin")
+    id("org.jetbrains.kotlin.android")
+    id("androidx.benchmark")
+}
+
+dependencies {
+    kotlinPlugin project(":compose:compiler:compiler")
+
+    implementation project(":compose:foundation:foundation")
+    implementation project(":compose:runtime:runtime")
+    implementation project(":compose:benchmark-utils")
+    implementation project(":compose:ui:ui")
+    implementation(KOTLIN_STDLIB)
+
+    androidTestImplementation project(":benchmark:benchmark-junit4")
+    androidTestImplementation project(":benchmark:benchmark-macro-junit4")
+    androidTestImplementation(ANDROIDX_TEST_RULES)
+}
diff --git a/compose/ui/ui-graphics/benchmark/src/androidTest/AndroidManifest.xml b/compose/ui/ui-graphics/benchmark/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..b5d6704
--- /dev/null
+++ b/compose/ui/ui-graphics/benchmark/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2021 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"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="androidx.compose.ui.graphics.benchmark">
+
+    <!--
+      ~ Important: disable debuggable for accurate performance results
+      -->
+    <application
+            android:debuggable="false"
+            tools:replace="android:debuggable">
+        <!-- enable profileableByShell for non-intrusive profiling tools -->
+        <!--suppress AndroidElementNotAllowed -->
+        <profileable android:shell="true"/>
+    </application>
+</manifest>
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/VectorBenchmark.kt b/compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/VectorBenchmark.kt
similarity index 92%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/VectorBenchmark.kt
rename to compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/VectorBenchmark.kt
index fb531d0..0938440 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/VectorBenchmark.kt
+++ b/compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/VectorBenchmark.kt
@@ -14,20 +14,18 @@
  * limitations under the License.
  */
 
-package androidx.ui.benchmark.test
+package androidx.compose.ui.graphics.benchmark
 
 import androidx.compose.testutils.benchmark.ComposeBenchmarkRule
 import androidx.compose.testutils.benchmark.benchmarkFirstCompose
 import androidx.compose.testutils.benchmark.benchmarkFirstDraw
 import androidx.compose.testutils.benchmark.benchmarkFirstLayout
 import androidx.compose.testutils.benchmark.benchmarkFirstMeasure
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
-import androidx.ui.integration.test.framework.ProgrammaticVectorTestCase
-import androidx.ui.integration.test.framework.XmlVectorTestCase
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import androidx.test.ext.junit.runners.AndroidJUnit4
 
 /**
  * Benchmark to compare performance of [parsing a vector asset from XML][XmlVectorTestCase] and
@@ -78,4 +76,4 @@
     fun programmatic_draw() {
         benchmarkRule.benchmarkFirstDraw { ProgrammaticVectorTestCase() }
     }
-}
+}
\ No newline at end of file
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/VectorBenchmarkWithTracing.kt b/compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/VectorBenchmarkWithTracing.kt
similarity index 95%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/VectorBenchmarkWithTracing.kt
rename to compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/VectorBenchmarkWithTracing.kt
index aed3bfc..d4e4318 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/VectorBenchmarkWithTracing.kt
+++ b/compose/ui/ui-graphics/benchmark/src/androidTest/java/androidx/compose/ui/graphics/benchmark/VectorBenchmarkWithTracing.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.ui.benchmark.test
+package androidx.compose.ui.graphics.benchmark
 
 import androidx.benchmark.macro.junit4.PerfettoRule
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -33,4 +33,4 @@
 class VectorBenchmarkWithTracing : VectorBenchmark() {
     @get:Rule
     val perfettoRule = PerfettoRule()
-}
+}
\ No newline at end of file
diff --git a/compose/ui/ui-graphics/benchmark/src/main/AndroidManifest.xml b/compose/ui/ui-graphics/benchmark/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..c628c53
--- /dev/null
+++ b/compose/ui/ui-graphics/benchmark/src/main/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2021 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.compose.ui.graphics.benchmark">
+    <application/>
+</manifest>
diff --git a/compose/integration-tests/src/main/java/androidx/ui/integration/test/framework/ImageVectorTestCase.kt b/compose/ui/ui-graphics/benchmark/src/main/java/androidx/compose/ui/graphics/benchmark/ImageVectorTestCase.kt
similarity index 96%
rename from compose/integration-tests/src/main/java/androidx/ui/integration/test/framework/ImageVectorTestCase.kt
rename to compose/ui/ui-graphics/benchmark/src/main/java/androidx/compose/ui/graphics/benchmark/ImageVectorTestCase.kt
index b2240f1..e7e5175 100644
--- a/compose/integration-tests/src/main/java/androidx/ui/integration/test/framework/ImageVectorTestCase.kt
+++ b/compose/ui/ui-graphics/benchmark/src/main/java/androidx/compose/ui/graphics/benchmark/ImageVectorTestCase.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.ui.integration.test.framework
+package androidx.compose.ui.graphics.benchmark
 
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
@@ -66,7 +66,7 @@
     // TODO: should switch to async loading here, and force that to be run synchronously
     @Composable
     override fun getPainter() = painterResource(
-        androidx.ui.integration.test.R.drawable.ic_baseline_menu_24
+        androidx.compose.ui.graphics.benchmark.R.drawable.ic_baseline_menu_24
     )
 
     override val testTag = "Xml"
diff --git a/compose/integration-tests/src/main/res/drawable/ic_baseline_menu_24.xml b/compose/ui/ui-graphics/benchmark/src/main/res/drawable/ic_baseline_menu_24.xml
similarity index 100%
rename from compose/integration-tests/src/main/res/drawable/ic_baseline_menu_24.xml
rename to compose/ui/ui-graphics/benchmark/src/main/res/drawable/ic_baseline_menu_24.xml
diff --git a/compose/integration-tests/src/main/res/drawable/ic_pathfill_sample.xml b/compose/ui/ui-graphics/benchmark/src/main/res/drawable/ic_pathfill_sample.xml
similarity index 100%
rename from compose/integration-tests/src/main/res/drawable/ic_pathfill_sample.xml
rename to compose/ui/ui-graphics/benchmark/src/main/res/drawable/ic_pathfill_sample.xml
diff --git a/compose/ui/ui-graphics/benchmark/test/build.gradle b/compose/ui/ui-graphics/benchmark/test/build.gradle
new file mode 100644
index 0000000..0a40f0d
--- /dev/null
+++ b/compose/ui/ui-graphics/benchmark/test/build.gradle
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 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.Publish
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("AndroidXUiPlugin")
+    id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+    kotlinPlugin project(":compose:compiler:compiler")
+
+    androidTestImplementation project(":compose:foundation:foundation")
+    androidTestImplementation project(":compose:runtime:runtime")
+    androidTestImplementation project(":compose:test-utils")
+    androidTestImplementation project(":compose:ui:ui")
+    androidTestImplementation project(":compose:ui:ui-graphics")
+    androidTestImplementation project(":compose:ui:ui-graphics:ui-graphics-benchmark")
+    androidTestImplementation(KOTLIN_STDLIB)
+    androidTestImplementation(ANDROIDX_TEST_RULES)
+    androidTestImplementation(TRUTH)
+}
diff --git a/compose/ui/ui-graphics/benchmark/test/src/androidTest/AndroidManifest.xml b/compose/ui/ui-graphics/benchmark/test/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..11e4107
--- /dev/null
+++ b/compose/ui/ui-graphics/benchmark/test/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2021 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"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="androidx.compose.ui.graphics.benchmark.test">
+</manifest>
diff --git a/compose/integration-tests/src/androidTest/java/androidx/ui/integration/test/ImageVectorTest.kt b/compose/ui/ui-graphics/benchmark/test/src/androidTest/java/androidx/compose/ui/graphics/benchmark/test/ImageVectorTest.kt
similarity index 90%
rename from compose/integration-tests/src/androidTest/java/androidx/ui/integration/test/ImageVectorTest.kt
rename to compose/ui/ui-graphics/benchmark/test/src/androidTest/java/androidx/compose/ui/graphics/benchmark/test/ImageVectorTest.kt
index 3b9e99e..b052ce0 100644
--- a/compose/integration-tests/src/androidTest/java/androidx/ui/integration/test/ImageVectorTest.kt
+++ b/compose/ui/ui-graphics/benchmark/test/src/androidTest/java/androidx/compose/ui/graphics/benchmark/test/ImageVectorTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.ui.integration.test
+package androidx.compose.ui.graphics.benchmark.test
 
 import android.os.Build
 import androidx.compose.foundation.Image
@@ -22,6 +22,8 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.asAndroidBitmap
+import androidx.compose.ui.graphics.benchmark.ProgrammaticVectorTestCase
+import androidx.compose.ui.graphics.benchmark.XmlVectorTestCase
 import androidx.compose.ui.graphics.toArgb
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.testTag
@@ -32,9 +34,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
-import androidx.ui.integration.test.framework.ProgrammaticVectorTestCase
-import androidx.ui.integration.test.framework.XmlVectorTestCase
-import org.junit.Assert.assertArrayEquals
+import org.junit.Assert
 import org.junit.Assert.assertEquals
 import org.junit.Rule
 import org.junit.Test
@@ -83,7 +83,7 @@
             }
         }
 
-        assertArrayEquals(xmlPixelArray, programmaticBitmapArray)
+        Assert.assertArrayEquals(xmlPixelArray, programmaticBitmapArray)
     }
 
     @Test
@@ -94,7 +94,9 @@
             with(LocalDensity.current) {
                 insetRectSize = (10f * this.density).roundToInt()
             }
-            val imageVector = painterResource(R.drawable.ic_pathfill_sample)
+            val imageVector = painterResource(
+                androidx.compose.ui.graphics.benchmark.R.drawable.ic_pathfill_sample
+            )
             Image(imageVector, null, modifier = Modifier.testTag(testTag))
         }
 
@@ -131,4 +133,4 @@
             )
         }
     }
-}
+}
\ No newline at end of file
diff --git a/compose/ui/ui-graphics/benchmark/test/src/main/AndroidManifest.xml b/compose/ui/ui-graphics/benchmark/test/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a4a839c
--- /dev/null
+++ b/compose/ui/ui-graphics/benchmark/test/src/main/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2021 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.compose.ui.graphics.benchmark.test">
+    <application/>
+</manifest>
diff --git a/compose/ui/ui-graphics/samples/src/main/java/androidx/compose/ui/graphics/samples/DrawScopeSample.kt b/compose/ui/ui-graphics/samples/src/main/java/androidx/compose/ui/graphics/samples/DrawScopeSample.kt
index bfac00f..302414d 100644
--- a/compose/ui/ui-graphics/samples/src/main/java/androidx/compose/ui/graphics/samples/DrawScopeSample.kt
+++ b/compose/ui/ui-graphics/samples/src/main/java/androidx/compose/ui/graphics/samples/DrawScopeSample.kt
@@ -21,6 +21,9 @@
 import androidx.compose.foundation.layout.size
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.drawscope.inset
 import androidx.compose.ui.graphics.drawscope.rotate
@@ -77,4 +80,28 @@
             drawRect(Color.Red, alpha = 0.25f)
         }
     }
+}
+
+@Sampled
+@Composable
+fun DrawScopeOvalBrushSample() {
+    Canvas(Modifier.size(120.dp)) {
+        drawOval(
+            brush = Brush.linearGradient(listOf(Color.Red, Color.Blue)),
+            topLeft = Offset(10f, 10f),
+            size = Size(size.width - 20f, size.height - 20f)
+        )
+    }
+}
+
+@Sampled
+@Composable
+fun DrawScopeOvalColorSample() {
+    Canvas(Modifier.size(120.dp)) {
+        drawOval(
+            color = Color.Cyan,
+            topLeft = Offset(10f, 10f),
+            size = Size(size.width - 20f, size.height - 20f)
+        )
+    }
 }
\ No newline at end of file
diff --git a/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt b/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt
index a858ea2..3ccce26 100644
--- a/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt
+++ b/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/drawscope/DrawScopeTest.kt
@@ -104,6 +104,69 @@
     }
 
     @Test
+    fun testDrawOvalBrush() {
+        val width = 200
+        val height = 200
+
+        // Test that colors are rendered with the correct stroke parameters
+        testDrawScopeAndCanvasAreEquivalent(
+            width,
+            height,
+            {
+                drawOval(
+                    brush = Brush.linearGradient(listOf(Color.Red, Color.Blue)),
+                    topLeft = Offset(10f, 10f),
+                    size = Size(width - 20f, height - 20f)
+                )
+            },
+            { canvas ->
+                canvas.drawOval(
+                    10f,
+                    10f,
+                    width - 10f,
+                    height - 10f,
+                    Paint().apply {
+                        shader =
+                            LinearGradientShader(
+                                Offset.Zero,
+                                Offset(width.toFloat(), height.toFloat()),
+                                listOf(Color.Red, Color.Blue)
+                            )
+                    }
+                )
+            }
+        )
+    }
+
+    @Test
+    fun testDrawOvalColor() {
+        val width = 200
+        val height = 200
+
+        // Test that colors are rendered with the correct stroke parameters
+        testDrawScopeAndCanvasAreEquivalent(
+            width,
+            height,
+            {
+                drawOval(
+                    color = Color.Cyan,
+                    topLeft = Offset(10f, 10f),
+                    size = Size(width - 20f, height - 20f)
+                )
+            },
+            { canvas ->
+                canvas.drawOval(
+                    10f,
+                    10f,
+                    width - 10f,
+                    height - 10f,
+                    Paint().apply { color = Color.Cyan }
+                )
+            }
+        )
+    }
+
+    @Test
     fun testDrawRectColorAlpha() {
         val img = createTestDstImage()
         CanvasDrawScope().draw(Canvas(img), dstSize) {
diff --git a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt
index 18ffa72..98f192d 100644
--- a/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt
+++ b/compose/ui/ui-graphics/src/commonMain/kotlin/androidx/compose/ui/graphics/drawscope/DrawScope.kt
@@ -583,6 +583,8 @@
      * @param style Whether or not the oval is stroked or filled in
      * @param colorFilter ColorFilter to apply to the [brush] when drawn into the destination
      * @param blendMode Blending algorithm to be applied to the brush
+     *
+     * @sample androidx.compose.ui.graphics.samples.DrawScopeOvalBrushSample
      */
     fun drawOval(
         brush: Brush,
@@ -608,6 +610,8 @@
      * @param style Whether or not the oval is stroked or filled in
      * @param colorFilter ColorFilter to apply to the [color] when drawn into the destination
      * @param blendMode Blending algorithm to be applied to the brush
+     *
+     * @sample androidx.compose.ui.graphics.samples.DrawScopeOvalColorSample
      */
     fun drawOval(
         color: Color,
diff --git a/compose/ui/ui-inspection/build.gradle b/compose/ui/ui-inspection/build.gradle
index 63e1254..4d5dab2 100644
--- a/compose/ui/ui-inspection/build.gradle
+++ b/compose/ui/ui-inspection/build.gradle
@@ -35,7 +35,7 @@
     // because compose:ui-inspector can be run only in app with compose:ui:ui
     // thus all its transitive dependencies will be present too.
     compileOnly(KOTLIN_STDLIB)
-    compileOnly(projectOrArtifact(":inspection:inspection"))
+    compileOnly("androidx.inspection:inspection:1.0.0")
     compileOnly(project(":compose:runtime:runtime"))
     compileOnly(project(":compose:ui:ui"))
     // we ignore its transitive dependencies, because ui-inspection should
@@ -101,4 +101,4 @@
 
 inspection {
     name = "compose-ui-inspection.jar"
-}
\ No newline at end of file
+}
diff --git a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/ParametersTest.kt b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/ParametersTest.kt
index f4710d7..3a3b4ce 100644
--- a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/ParametersTest.kt
+++ b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/ParametersTest.kt
@@ -20,6 +20,7 @@
 import androidx.compose.ui.inspection.rules.sendCommand
 import androidx.compose.ui.inspection.testdata.ParametersTestActivity
 import androidx.compose.ui.inspection.util.GetComposablesCommand
+import androidx.compose.ui.inspection.util.GetParameterDetailsCommand
 import androidx.compose.ui.inspection.util.GetParametersCommand
 import androidx.compose.ui.inspection.util.toMap
 import androidx.test.filters.LargeTest
@@ -29,7 +30,7 @@
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.GetComposablesResponse
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.GetParametersResponse
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.Parameter
-import org.junit.Ignore
+import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.StringEntry
 import org.junit.Rule
 import org.junit.Test
 
@@ -54,7 +55,6 @@
         assertThat(resourceValue.name.resolve(params)).isEqualTo("samplefont")
     }
 
-    @Ignore // Will re-enable after platform bug is fixed upstream
     @Test
     fun lambda(): Unit = runBlocking {
         val composables = rule.inspectorTester.sendCommand(GetComposablesCommand(rule.rootId))
@@ -67,13 +67,12 @@
 
         val lambdaValue = params.find("onClick")!!.lambdaValue
         assertThat(lambdaValue.fileName.resolve(params)).isEqualTo("ParametersTestActivity.kt")
-        assertThat(lambdaValue.startLineNumber).isEqualTo(47)
-        assertThat(lambdaValue.endLineNumber).isEqualTo(47)
+        assertThat(lambdaValue.startLineNumber).isEqualTo(48)
+        assertThat(lambdaValue.endLineNumber).isEqualTo(48)
         assertThat(lambdaValue.packageName.resolve(params))
             .isEqualTo("androidx.compose.ui.inspection.testdata")
     }
 
-    @Ignore // Will re-enable after platform bug is fixed upstream
     @Test
     fun functionType(): Unit = runBlocking {
         val composables = rule.inspectorTester.sendCommand(GetComposablesCommand(rule.rootId))
@@ -86,12 +85,47 @@
 
         val lambdaValue = params.find("onClick")!!.lambdaValue
         assertThat(lambdaValue.fileName.resolve(params)).isEqualTo("ParametersTestActivity.kt")
-        assertThat(lambdaValue.startLineNumber).isEqualTo(50)
-        assertThat(lambdaValue.endLineNumber).isEqualTo(50)
+        assertThat(lambdaValue.startLineNumber).isEqualTo(51)
+        assertThat(lambdaValue.endLineNumber).isEqualTo(51)
         assertThat(lambdaValue.functionName.resolve(params)).isEqualTo("testClickHandler")
         assertThat(lambdaValue.packageName.resolve(params))
             .isEqualTo("androidx.compose.ui.inspection.testdata")
     }
+
+    @Test
+    fun intArray(): Unit = runBlocking {
+        val tester = rule.inspectorTester
+        val nodes = tester.sendCommand(GetComposablesCommand(rule.rootId)).getComposablesResponse
+
+        val function = nodes.filter("FunctionWithIntArray").single()
+        val params = tester.sendCommand(GetParametersCommand(rule.rootId, function.id))
+            .getParametersResponse
+
+        val intArray = params.find("intArray")!!
+        var strings = params.stringsList
+        assertThat(intArray.elementsCount).isEqualTo(5)
+        checkParam(strings, intArray.elementsList[0], "[0]", 10)
+        checkParam(strings, intArray.elementsList[1], "[1]", 11)
+        checkParam(strings, intArray.elementsList[2], "[2]", 12)
+        checkParam(strings, intArray.elementsList[3], "[3]", 13)
+        checkParam(strings, intArray.elementsList[4], "[4]", 14)
+
+        val expanded =
+            tester.sendCommand(
+                GetParameterDetailsCommand(
+                    rule.rootId,
+                    intArray.reference,
+                    startIndex = 5,
+                    maxElements = 5
+                )
+            ).getParameterDetailsResponse
+        val intArray2 = expanded.parameter
+        strings = expanded.stringsList
+        assertThat(intArray2.elementsCount).isEqualTo(3)
+        checkParam(strings, intArray2.elementsList[0], "[5]", 15)
+        checkParam(strings, intArray2.elementsList[1], "[6]", 16)
+        checkParam(strings, intArray2.elementsList[2], "[7]", 17)
+    }
 }
 
 private fun Int.resolve(response: GetParametersResponse): String? {
@@ -113,4 +147,16 @@
 }
 
 private fun ComposableNode.flatten(): List<ComposableNode> =
-    listOf(this).plus(this.childrenList.flatMap { it.flatten() })
\ No newline at end of file
+    listOf(this).plus(this.childrenList.flatMap { it.flatten() })
+
+private fun checkParam(
+    stringList: List<StringEntry>,
+    param: Parameter,
+    name: String,
+    value: Int,
+    index: Int = -1
+) {
+    assertThat(stringList.toMap()[param.name]).isEqualTo(name)
+    assertThat(param.int32Value).isEqualTo(value)
+    assertThat(param.index).isEqualTo(index)
+}
diff --git a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt
index 47cb2ae..c98b9a9 100644
--- a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt
+++ b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTreeTest.kt
@@ -71,6 +71,7 @@
 import kotlin.math.roundToInt
 
 private const val DEBUG = false
+private const val ROOT_ID = 3L
 
 @LargeTest
 @RunWith(AndroidJUnit4::class)
@@ -121,6 +122,13 @@
 
         validate(nodes, builder, checkParameters = false) {
             node(
+                name = "Box",
+                isRenderNode = true,
+                children = listOf("Inspectable")
+            )
+            node("Inspectable", children = listOf("CompositionLocalProvider"))
+            node("CompositionLocalProvider", children = listOf("Column"))
+            node(
                 name = "Column",
                 fileName = "LayoutInspectorTreeTest.kt",
                 left = 0.0.dp, top = 0.0.dp, width = 72.0.dp, height = 78.9.dp,
@@ -186,6 +194,21 @@
 
         validate(nodes, builder, checkParameters = false) {
             node(
+                name = "Box",
+                isRenderNode = true,
+                children = listOf("Inspectable")
+            )
+            node(
+                name = "Inspectable",
+                hasTransformations = true,
+                children = listOf("CompositionLocalProvider")
+            )
+            node(
+                name = "CompositionLocalProvider",
+                hasTransformations = true,
+                children = listOf("MaterialTheme")
+            )
+            node(
                 name = "MaterialTheme",
                 hasTransformations = true,
                 fileName = "LayoutInspectorTreeTest.kt",
@@ -434,14 +457,10 @@
             }
 
             if (checkParameters) {
-                val params = builder.convertParameters(node)
+                val params = builder.convertParameters(ROOT_ID, node)
                 val receiver = ParameterValidationReceiver(params.listIterator())
                 receiver.block()
-                if (receiver.parameterIterator.hasNext()) {
-                    val elementNames = mutableListOf<String>()
-                    receiver.parameterIterator.forEachRemaining { elementNames.add(it.name) }
-                    error("$name: has more parameters like: ${elementNames.joinToString()}")
-                }
+                receiver.checkFinished(name)
             }
         }
     }
@@ -504,7 +523,7 @@
         println()
         print(")")
         if (generateParameters && node.parameters.isNotEmpty()) {
-            generateParameters(builder.convertParameters(node), 0)
+            generateParameters(builder.convertParameters(ROOT_ID, node), 0)
         }
         println()
         node.children.forEach { generateValidate(it, builder) }
diff --git a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/ParameterFactoryTest.kt b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/ParameterFactoryTest.kt
index 57f9325..4fc2af8 100644
--- a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/ParameterFactoryTest.kt
+++ b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/inspector/ParameterFactoryTest.kt
@@ -80,6 +80,10 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
+private const val ROOT_ID = 3L
+private const val NODE_ID = -7L
+private const val PARAM_INDEX = 4
+
 @Suppress("unused")
 private fun topLevelFunction() {
 }
@@ -88,9 +92,12 @@
 @RunWith(AndroidJUnit4::class)
 class ParameterFactoryTest {
     private val factory = ParameterFactory(InlineClassConverter())
+    private val originalMaxRecursions = factory.maxRecursions
+    private val originalMaxIterable = factory.maxIterable
     private val node = MutableInspectorNode().apply {
         width = 1000
         height = 500
+        id = NODE_ID
     }.build()
 
     @Before
@@ -101,6 +108,8 @@
 
     @After
     fun after() {
+        factory.maxRecursions = originalMaxRecursions
+        factory.maxIterable = originalMaxIterable
         isDebugInspectorInfoEnabled = false
     }
 
@@ -186,7 +195,7 @@
 
     @Test
     fun testBorder() {
-        validate(factory.create(node, "borderstroke", BorderStroke(2.0.dp, Color.Magenta))!!) {
+        validate(create("borderstroke", BorderStroke(2.0.dp, Color.Magenta))) {
             parameter("borderstroke", ParameterType.String, "BorderStroke") {
                 parameter("brush", ParameterType.Color, Color.Magenta.toArgb())
                 parameter("width", ParameterType.DimensionDp, 2.0f)
@@ -199,24 +208,23 @@
         assertThat(lookup(SolidColor(Color.Red)))
             .isEqualTo(ParameterType.Color to Color.Red.toArgb())
         validate(
-            factory.create(
-                node,
+            create(
                 "brush",
                 Brush.linearGradient(
                     colors = listOf(Color.Red, Color.Blue),
                     start = Offset(0.0f, 0.5f),
                     end = Offset(5.0f, 10.0f)
                 )
-            )!!
+            )
         ) {
             parameter("brush", ParameterType.String, "LinearGradient") {
-                parameter("colors", ParameterType.String, "") {
-                    parameter("0", ParameterType.Color, Color.Red.toArgb())
-                    parameter("1", ParameterType.Color, Color.Blue.toArgb())
+                parameter("colors", ParameterType.Iterable, "") {
+                    parameter("[0]", ParameterType.Color, Color.Red.toArgb())
+                    parameter("[1]", ParameterType.Color, Color.Blue.toArgb())
                 }
                 // Parameters are traversed in alphabetical order through reflection queries.
                 // Validate createdSize exists before validating end parameter
-                parameter("createdSize", ParameterType.String, "Unspecified")
+                parameter("createdSize", ParameterType.String, "Unspecified", index = 5)
                 parameter("end", ParameterType.String, Offset::class.java.simpleName) {
                     parameter("x", ParameterType.DimensionDp, 2.5f)
                     parameter("y", ParameterType.DimensionDp, 5.0f)
@@ -225,7 +233,7 @@
                     parameter("x", ParameterType.DimensionDp, 0.0f)
                     parameter("y", ParameterType.DimensionDp, 0.25f)
                 }
-                parameter("tileMode", ParameterType.String, "Clamp")
+                parameter("tileMode", ParameterType.String, "Clamp", index = 4)
             }
         }
         // TODO: add tests for RadialGradient & ShaderBrush
@@ -243,8 +251,9 @@
     fun testComposableLambda() = runBlocking {
         // capture here to force the lambda to not be created as a singleton.
         val capture = "Hello World"
+        @Suppress("COMPOSABLE_INVOCATION")
         val c: @Composable () -> Unit = { Text(text = capture) }
-        val result = lookup(c as Any) ?: error("Lookup of ComposableLambda failed")
+        val result = lookup(c as Any)
         val array = result.second as Array<*>
         assertThat(result.first).isEqualTo(ParameterType.Lambda)
         assertThat(array).hasLength(1)
@@ -256,12 +265,7 @@
     @Ignore
     @Test
     fun testCornerBasedShape() {
-        validate(
-            factory.create(
-                node, "corner",
-                RoundedCornerShape(2.0.dp, 0.5.dp, 2.5.dp, 0.7.dp)
-            )!!
-        ) {
+        validate(create("corner", RoundedCornerShape(2.0.dp, 0.5.dp, 2.5.dp, 0.7.dp))) {
             parameter("corner", ParameterType.String, RoundedCornerShape::class.java.simpleName) {
                 parameter("bottomEnd", ParameterType.DimensionDp, 2.5f)
                 parameter("bottomStart", ParameterType.DimensionDp, 0.7f)
@@ -269,7 +273,7 @@
                 parameter("topStart", ParameterType.DimensionDp, 2.0f)
             }
         }
-        validate(factory.create(node, "corner", CutCornerShape(2))!!) {
+        validate(create("corner", CutCornerShape(2))) {
             parameter("corner", ParameterType.String, CutCornerShape::class.java.simpleName) {
                 parameter("bottomEnd", ParameterType.DimensionDp, 5.0f)
                 parameter("bottomStart", ParameterType.DimensionDp, 5.0f)
@@ -277,7 +281,7 @@
                 parameter("topStart", ParameterType.DimensionDp, 5.0f)
             }
         }
-        validate(factory.create(node, "corner", RoundedCornerShape(1.0f, 10.0f, 2.0f, 3.5f))!!) {
+        validate(create("corner", RoundedCornerShape(1.0f, 10.0f, 2.0f, 3.5f))) {
             parameter("corner", ParameterType.String, RoundedCornerShape::class.java.simpleName) {
                 parameter("bottomEnd", ParameterType.DimensionDp, 1.0f)
                 parameter("bottomStart", ParameterType.DimensionDp, 1.75f)
@@ -369,12 +373,12 @@
     @Test
     fun testFunctionReference() {
         val ref1 = ::testInt
-        val map1 = lookup(ref1)!!
+        val map1 = lookup(ref1)
         val array1 = map1.second as Array<*>
         assertThat(map1.first).isEqualTo(ParameterType.FunctionReference)
         assertThat(array1.contentEquals(arrayOf(ref1, "testInt"))).isTrue()
         val ref2 = ::topLevelFunction
-        val map2 = lookup(ref2)!!
+        val map2 = lookup(ref2)
         val array2 = map2.second as Array<*>
         assertThat(map2.first).isEqualTo(ParameterType.FunctionReference)
         assertThat(array2.contentEquals(arrayOf(ref2, "topLevelFunction"))).isTrue()
@@ -382,7 +386,7 @@
 
     @Test
     fun testPaddingValues() {
-        validate(factory.create(node, "padding", PaddingValues(2.0.dp, 0.5.dp, 2.5.dp, 0.7.dp))!!) {
+        validate(create("padding", PaddingValues(2.0.dp, 0.5.dp, 2.5.dp, 0.7.dp))) {
             parameter(
                 "padding",
                 ParameterType.String,
@@ -404,7 +408,7 @@
     @Test
     fun testLambda() {
         val a: (Int) -> Int = { it }
-        val map = lookup(a)!!
+        val map = lookup(a)
         val array = map.second as Array<*>
         assertThat(map.first).isEqualTo(ParameterType.Lambda)
         assertThat(array.contentEquals(arrayOf<Any>(a))).isTrue()
@@ -418,10 +422,10 @@
 
     @Test
     fun testLocaleList() {
-        validate(factory.create(node, "locales", LocaleList(Locale("fr-ca"), Locale("fr-be")))!!) {
-            parameter("locales", ParameterType.String, "") {
-                parameter("0", ParameterType.String, "fr-CA")
-                parameter("1", ParameterType.String, "fr-BE")
+        validate(create("locales", LocaleList(Locale("fr-ca"), Locale("fr-be")))) {
+            parameter("locales", ParameterType.Iterable, "") {
+                parameter("[0]", ParameterType.String, "fr-CA")
+                parameter("[1]", ParameterType.String, "fr-BE")
             }
         }
     }
@@ -432,10 +436,80 @@
     }
 
     @Test
+    fun testShortIntArray() {
+        factory.maxIterable = 10
+        val value = intArrayOf(10, 11, 12)
+        val parameter = create("array", value)
+        validate(parameter) {
+            parameter("array", ParameterType.Iterable, "") {
+                parameter("[0]", ParameterType.Int32, 10)
+                parameter("[1]", ParameterType.Int32, 11)
+                parameter("[2]", ParameterType.Int32, 12)
+            }
+        }
+    }
+
+    @Test
+    fun testLongIntArray() {
+        factory.maxIterable = 5
+        val value = intArrayOf(10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23)
+        val refToSelf = ref()
+        val parameter = create("array", value)
+        validate(parameter) {
+            parameter("array", ParameterType.Iterable, "", refToSelf) {
+                parameter("[0]", ParameterType.Int32, 10)
+                parameter("[1]", ParameterType.Int32, 11)
+                parameter("[2]", ParameterType.Int32, 12)
+                parameter("[3]", ParameterType.Int32, 13)
+                parameter("[4]", ParameterType.Int32, 14)
+            }
+        }
+
+        // If we need to retrieve more array elements we call "factory.expand" with the reference:
+        validate(factory.expand(ROOT_ID, node, "array", value, refToSelf, 5, 5)!!) {
+            parameter("array", ParameterType.Iterable, "", refToSelf) {
+                parameter("[5]", ParameterType.Int32, 15)
+                parameter("[6]", ParameterType.Int32, 16)
+                parameter("[7]", ParameterType.Int32, 17)
+                parameter("[8]", ParameterType.Int32, 18)
+                parameter("[9]", ParameterType.Int32, 19)
+            }
+        }
+
+        // Call "factory.expand" again to retrieve more:
+        validate(factory.expand(ROOT_ID, node, "array", value, refToSelf, 10, 5)!!) {
+            // This time we reached the end of the array, and we do not get a reference to get more
+            parameter("array", ParameterType.Iterable, "") {
+                parameter("[10]", ParameterType.Int32, 20)
+                parameter("[11]", ParameterType.Int32, 21)
+                parameter("[12]", ParameterType.Int32, 22)
+                parameter("[13]", ParameterType.Int32, 23)
+            }
+        }
+    }
+
+    @Test
+    fun testListWithNullElement() {
+        factory.maxIterable = 3
+        val value = listOf("Hello", null, "World")
+        val parameter = create("array", value)
+        validate(parameter) {
+            // Here we get all the available elements from the list.
+            // There is no need to go back for more data, and the iterable does not have a
+            // reference for doing so.
+            parameter("array", ParameterType.Iterable, "") {
+                parameter("[0]", ParameterType.String, "Hello")
+                parameter("[2]", ParameterType.String, "World", index = 2)
+            }
+        }
+    }
+
+    @Test
     fun testModifier() {
+        factory.maxRecursions = 4
         validate(
-            factory.create(
-                node, "modifier",
+            create(
+                "modifier",
                 Modifier
                     .background(Color.Blue)
                     .border(width = 5.dp, color = Color.Red)
@@ -444,7 +518,7 @@
                     .wrapContentHeight(Alignment.Bottom)
                     .width(30.0.dp)
                     .paint(TestPainter(10f, 20f))
-            )!!
+            )
         ) {
             parameter("modifier", ParameterType.String, "") {
                 parameter("background", ParameterType.Color, Color.Blue.toArgb()) {
@@ -472,7 +546,7 @@
                     parameter("painter", ParameterType.String, "TestPainter") {
                         parameter("alpha", ParameterType.Float, 1.0f)
                         parameter("color", ParameterType.Color, Color.Red.toArgb())
-                        parameter("drawLambda", ParameterType.Lambda, null)
+                        parameter("drawLambda", ParameterType.Lambda, null, index = 6)
                         parameter("height", ParameterType.Float, 20.0f)
                         parameter("intrinsicSize", ParameterType.String, "Size") {
                             parameter("height", ParameterType.Float, 20.0f)
@@ -481,8 +555,8 @@
                             parameter("packedValue", ParameterType.Int64, 4692750812821061632L)
                             parameter("width", ParameterType.Float, 10.0f)
                         }
-                        parameter("layoutDirection", ParameterType.String, "Ltr")
-                        parameter("useLayer", ParameterType.Boolean, false)
+                        parameter("layoutDirection", ParameterType.String, "Ltr", index = 8)
+                        parameter("useLayer", ParameterType.Boolean, false, index = 9)
                         parameter("width", ParameterType.Float, 10.0f)
                     }
                     parameter("sizeToIntrinsics", ParameterType.Boolean, true)
@@ -493,7 +567,7 @@
 
     @Test
     fun testSingleModifier() {
-        validate(factory.create(node, "modifier", Modifier.padding(2.0.dp))!!) {
+        validate(create("modifier", Modifier.padding(2.0.dp))) {
             parameter("modifier", ParameterType.String, "") {
                 parameter("padding", ParameterType.DimensionDp, 2.0f)
             }
@@ -502,7 +576,7 @@
 
     @Test
     fun testSingleModifierWithParameters() {
-        validate(factory.create(node, "modifier", Modifier.padding(1.dp, 2.dp, 3.dp, 4.dp))!!) {
+        validate(create("modifier", Modifier.padding(1.dp, 2.dp, 3.dp, 4.dp))) {
             parameter("modifier", ParameterType.String, "") {
                 parameter("padding", ParameterType.String, "") {
                     parameter("bottom", ParameterType.DimensionDp, 4.0f)
@@ -516,66 +590,124 @@
 
     @Test
     fun testOffset() {
-        validate(factory.create(node, "offset", Offset(1.0f, 5.0f))!!) {
+        validate(create("offset", Offset(1.0f, 5.0f))) {
             parameter("offset", ParameterType.String, Offset::class.java.simpleName) {
                 parameter("x", ParameterType.DimensionDp, 0.5f)
                 parameter("y", ParameterType.DimensionDp, 2.5f)
             }
         }
-        validate(factory.create(node, "offset", Offset.Zero)!!) {
+        validate(create("offset", Offset.Zero)) {
             parameter("offset", ParameterType.String, "Zero")
         }
     }
 
     @Test
     fun testRecursiveStructure() {
-        val v1 = MyClass()
-        val v2 = MyClass()
+        val v1 = MyClass("v1")
+        val v2 = MyClass("v2")
         v1.other = v2
         v2.other = v1
+        v1.self = v1
+        v2.self = v2
         val name = MyClass::class.java.simpleName
-        validate(factory.create(node, "mine", v1)!!) {
+        validate(create("mine", v1)) {
             parameter("mine", ParameterType.String, name) {
+                parameter("name", ParameterType.String, "v1")
                 parameter("other", ParameterType.String, name) {
-                    parameter("other", ParameterType.String, name) {
-                        parameter("other", ParameterType.String, name) {
-                            parameter("other", ParameterType.String, name) {
-                                parameter("other", ParameterType.String, name) {
-                                    parameter("other", ParameterType.String, name) {
-                                        parameter("other", ParameterType.String, name) {
-                                            parameter("other", ParameterType.String, name) {
-                                                parameter("other", ParameterType.String, name)
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
+                    parameter("name", ParameterType.String, "v2")
+                    // v2.other is expected to reference v1 which is already found
+                    parameter("other", ParameterType.String, name, ref())
+
+                    // v2.self is expected to reference v2 which is already found
+                    parameter("self", ParameterType.String, name, ref(1))
                 }
+                // v1.self is expected to reference v1 which is already found
+                parameter("self", ParameterType.String, name, ref())
             }
         }
     }
 
     @Test
-    fun testDoNotRecurseIntoAndroidAndJavaPackages() {
+    fun testMissingChildParameters() {
+        val v1 = MyClass("v1")
+        val v2 = MyClass("v2")
+        val v3 = MyClass("v3")
+        val v4 = MyClass("v4")
+        val v5 = MyClass("v5")
+        v1.self = v1
+        v1.third = v2
+        v2.other = v3
+        v2.third = v1
+        v3.other = v4
+        v4.other = v5
+        val name = MyClass::class.java.simpleName
+
+        // Limit the recursions for this test to validate parameter nodes with missing children.
+        factory.maxRecursions = 2
+
+        val parameter = create("v1", v1)
+        val v2ref = ref(3, 1)
+        validate(parameter) {
+            parameter("v1", ParameterType.String, name) {
+                parameter("name", ParameterType.String, "v1")
+                parameter("self", ParameterType.String, name, ref(), index = 2)
+                parameter("third", ParameterType.String, name, index = 3) {
+                    parameter("name", ParameterType.String, "v2")
+
+                    // Expect the child elements for v2 to be missing from the parameter tree,
+                    // which is indicated by the reference field being included for "other" here:
+                    parameter("other", ParameterType.String, name, v2ref)
+                    parameter("third", ParameterType.String, name, ref(), index = 3)
+                }
+            }
+        }
+
+        // If we need to retrieve the missing child nodes for v2 from above, we must
+        // call "factory.expand" with the reference:
+        val v4ref = ref(3, 1, 1, 1)
+        validate(factory.expand(ROOT_ID, node, "v1", v1, v2ref)!!) {
+            parameter("other", ParameterType.String, name) {
+                parameter("name", ParameterType.String, "v3")
+                parameter("other", ParameterType.String, name) {
+                    parameter("name", ParameterType.String, "v4")
+
+                    // Expect the child elements for v4 to be missing from the parameter tree,
+                    // which is indicated by the reference field being included for "other" here:
+                    parameter("other", ParameterType.String, name, v4ref)
+                }
+            }
+        }
+
+        // If we need to retrieve the missing child nodes for v4 from above, we must
+        // call "factory.expand" with the reference:
+        validate(factory.expand(ROOT_ID, node, "v1", v1, v4ref)!!) {
+            parameter("other", ParameterType.String, name) {
+                parameter("name", ParameterType.String, "v5")
+            }
+        }
+    }
+
+    @Test
+    fun testDoNotRecurseInto() {
         runBlocking {
-            assertThat(factory.create(node, "v1", java.net.URL("http://domain.com"))).isNull()
-            assertThat(factory.create(node, "v1", android.app.Notification())).isNull()
+            assertThat(lookup(java.net.URL("http://domain.com")))
+                .isEqualTo(ParameterType.String to "")
+            assertThat(lookup(android.app.Notification()))
+                .isEqualTo(ParameterType.String to "")
         }
     }
 
     @Test
     fun testShadow() {
         assertThat(lookup(Shadow.None)).isEqualTo(ParameterType.String to "None")
-        validate(factory.create(node, "shadow", Shadow(Color.Cyan, Offset.Zero, 2.5f))!!) {
+        validate(create("shadow", Shadow(Color.Cyan, Offset.Zero, 2.5f))) {
             parameter("shadow", ParameterType.String, Shadow::class.java.simpleName) {
                 parameter("blurRadius", ParameterType.DimensionDp, 1.25f)
                 parameter("color", ParameterType.Color, Color.Cyan.toArgb())
                 parameter("offset", ParameterType.String, "Zero")
             }
         }
-        validate(factory.create(node, "shadow", Shadow(Color.Blue, Offset(1.0f, 4.0f), 1.5f))!!) {
+        validate(create("shadow", Shadow(Color.Blue, Offset(1.0f, 4.0f), 1.5f))) {
             parameter("shadow", ParameterType.String, Shadow::class.java.simpleName) {
                 parameter("blurRadius", ParameterType.DimensionDp, 0.75f)
                 parameter("color", ParameterType.Color, Color.Blue.toArgb())
@@ -610,7 +742,7 @@
 
     @Test
     fun testTextGeometricTransform() {
-        validate(factory.create(node, "transform", TextGeometricTransform(2.0f, 1.5f))!!) {
+        validate(create("transform", TextGeometricTransform(2.0f, 1.5f))) {
             parameter(
                 "transform", ParameterType.String,
                 TextGeometricTransform::class.java.simpleName
@@ -625,7 +757,7 @@
     fun testTextIndent() {
         assertThat(lookup(TextIndent.None)).isEqualTo(ParameterType.String to "None")
 
-        validate(factory.create(node, "textIndent", TextIndent(4.0.sp, 0.5.sp))!!) {
+        validate(create("textIndent", TextIndent(4.0.sp, 0.5.sp))) {
             parameter("textIndent", ParameterType.String, "TextIndent") {
                 parameter("firstLine", ParameterType.DimensionSp, 4.0f)
                 parameter("restLine", ParameterType.DimensionSp, 0.5f)
@@ -639,14 +771,14 @@
             color = Color.Red,
             textDecoration = TextDecoration.Underline
         )
-        validate(factory.create(node, "style", style)!!) {
+        validate(create("style", style)) {
             parameter("style", ParameterType.String, TextStyle::class.java.simpleName) {
                 parameter("background", ParameterType.String, "Unspecified")
-                parameter("color", ParameterType.Color, Color.Red.toArgb())
-                parameter("fontSize", ParameterType.String, "Unspecified")
-                parameter("letterSpacing", ParameterType.String, "Unspecified")
-                parameter("lineHeight", ParameterType.String, "Unspecified")
-                parameter("textDecoration", ParameterType.String, "Underline")
+                parameter("color", ParameterType.Color, Color.Red.toArgb(), index = 2)
+                parameter("fontSize", ParameterType.String, "Unspecified", index = 5)
+                parameter("letterSpacing", ParameterType.String, "Unspecified", index = 9)
+                parameter("lineHeight", ParameterType.String, "Unspecified", index = 10)
+                parameter("textDecoration", ParameterType.String, "Underline", index = 14)
             }
         }
     }
@@ -670,18 +802,57 @@
         assertThat(lookup(Icons.Rounded.Add)).isEqualTo(ParameterType.String to "Rounded.Add")
     }
 
-    private fun lookup(value: Any): Pair<ParameterType, Any?>? {
-        val parameter = factory.create(node, "property", value) ?: return null
+    private fun create(name: String, value: Any): NodeParameter {
+        val parameter = factory.create(ROOT_ID, node, name, value, PARAM_INDEX)
+
+        // Check that factory.expand will return the exact same information as factory.create
+        // for each parameter and parameter child. Punt if there are references.
+        checkExpand(parameter, parameter.name, value, mutableListOf())
+
+        return parameter
+    }
+
+    private fun lookup(value: Any): Pair<ParameterType, Any?> {
+        val parameter = create("parameter", value)
         assertThat(parameter.elements).isEmpty()
         return Pair(parameter.type, parameter.value)
     }
 
+    private fun ref(vararg reference: Int): NodeParameterReference =
+        NodeParameterReference(NODE_ID, PARAM_INDEX, reference)
+
     private fun validate(
         parameter: NodeParameter,
         expected: ParameterValidationReceiver.() -> Unit = {}
     ) {
         val elements = ParameterValidationReceiver(listOf(parameter).listIterator())
         elements.expected()
+        elements.checkFinished()
+    }
+
+    private fun checkExpand(
+        parameter: NodeParameter,
+        name: String,
+        value: Any,
+        indices: MutableList<Int>
+    ) {
+        factory.clearCacheFor(ROOT_ID)
+        val reference = NodeParameterReference(NODE_ID, PARAM_INDEX, indices)
+        val expanded = factory.expand(ROOT_ID, node, name, value, reference)
+        if (parameter.value == null && indices.isNotEmpty()) {
+            assertThat(expanded).isNull()
+        } else {
+            val hasReferences = expanded!!.checkEquals(parameter)
+            if (!hasReferences) {
+                parameter.elements.forEach { element ->
+                    if (element.index >= 0) {
+                        indices.add(element.index)
+                        checkExpand(element, name, value, indices)
+                        indices.removeLast()
+                    }
+                }
+            }
+        }
     }
 }
 
@@ -705,37 +876,71 @@
     }
 }
 
-class ParameterValidationReceiver(val parameterIterator: Iterator<NodeParameter>) {
+class ParameterValidationReceiver(
+    private val parameterIterator: Iterator<NodeParameter>,
+    private val trace: String = ""
+) {
     fun parameter(
         name: String,
         type: ParameterType,
         value: Any?,
+        ref: NodeParameterReference? = null,
+        index: Int = -1,
         block: ParameterValidationReceiver.() -> Unit = {}
     ) {
         assertWithMessage("No such element found: $name").that(parameterIterator.hasNext()).isTrue()
         val parameter = parameterIterator.next()
         assertThat(parameter.name).isEqualTo(name)
-        assertWithMessage(name).that(parameter.type).isEqualTo(type)
+        val msg = "$trace${parameter.name}"
+        assertWithMessage(msg).that(parameter.type).isEqualTo(type)
+        assertWithMessage(msg).that(parameter.index).isEqualTo(index)
+        assertWithMessage(msg).that(checkEquals(parameter.reference, ref)).isTrue()
         if (type != ParameterType.Lambda || value != null) {
-            assertWithMessage(name).that(parameter.value).isEqualTo(value)
+            assertWithMessage(msg).that(parameter.value).isEqualTo(value)
         }
         var elements: List<NodeParameter> = parameter.elements
-        if (name != "modifier") {
-            // Do not sort modifiers: the order is important
+        if (name != "modifier" && type != ParameterType.Iterable) {
+            // Do not sort modifiers or iterables: the order is important
             elements = elements.sortedBy { it.name }
         }
-        val children = ParameterValidationReceiver(elements.listIterator())
+        val children = ParameterValidationReceiver(elements.listIterator(), "$msg.")
         children.block()
-        if (children.parameterIterator.hasNext()) {
+        children.checkFinished(msg)
+    }
+
+    fun checkFinished(trace: String = "") {
+        if (parameterIterator.hasNext()) {
             val elementNames = mutableListOf<String>()
-            while (children.parameterIterator.hasNext()) {
-                elementNames.add(children.parameterIterator.next().name)
+            while (parameterIterator.hasNext()) {
+                elementNames.add(parameterIterator.next().name)
             }
-            error("$name: has more elements like: ${elementNames.joinToString()}")
+            error("$trace: has more elements like: ${elementNames.joinToString()}")
         }
     }
 }
 
-class MyClass {
+@Suppress("unused")
+class MyClass(private val name: String) {
     var other: MyClass? = null
+    var self: MyClass? = null
+    var third: MyClass? = null
 }
+
+private fun NodeParameter.checkEquals(other: NodeParameter): Boolean {
+    assertThat(other.name).isEqualTo(name)
+    assertThat(other.type).isEqualTo(type)
+    assertThat(other.value).isEqualTo(value)
+    assertThat(checkEquals(reference, other.reference)).isTrue()
+    assertThat(other.elements.size).isEqualTo(elements.size)
+    var hasReferences = reference != null
+    elements.forEachIndexed { i, element ->
+        hasReferences = hasReferences or element.checkEquals(other.elements[i])
+    }
+    return hasReferences
+}
+
+private fun checkEquals(ref1: NodeParameterReference?, ref2: NodeParameterReference?): Boolean =
+    ref1 === ref2 ||
+        ref1?.nodeId == ref2?.nodeId &&
+        ref1?.parameterIndex == ref2?.parameterIndex &&
+        ref1?.indices.contentEquals(ref2?.indices)
diff --git a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/testdata/ParametersTestActivity.kt b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/testdata/ParametersTestActivity.kt
index dc83632..dc2af17 100644
--- a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/testdata/ParametersTestActivity.kt
+++ b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/testdata/ParametersTestActivity.kt
@@ -26,6 +26,7 @@
 import androidx.compose.ui.text.font.FontStyle
 import androidx.compose.ui.text.font.FontWeight
 import androidx.compose.ui.inspection.test.R
+import androidx.compose.runtime.Composable
 
 class ParametersTestActivity : ComponentActivity() {
     private val fontFamily = FontFamily(
@@ -50,8 +51,15 @@
             Button(onClick = ::testClickHandler) {
                 Text("two", fontFamily = fontFamily)
             }
+            FunctionWithIntArray(intArrayOf(10, 11, 12, 13, 14, 15, 16, 17))
         }
     }
 }
 
+@Suppress("UNUSED_PARAMETER")
+@Composable
+fun FunctionWithIntArray(intArray: IntArray) {
+    Text("three")
+}
+
 internal fun testClickHandler() {}
\ No newline at end of file
diff --git a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/util/ProtoExtensions.kt b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/util/ProtoExtensions.kt
index 1b71a61..5cc8b60 100644
--- a/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/util/ProtoExtensions.kt
+++ b/compose/ui/ui-inspection/src/androidTest/java/androidx/compose/ui/inspection/util/ProtoExtensions.kt
@@ -20,6 +20,8 @@
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.Command
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.GetComposablesCommand
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.GetParametersCommand
+import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.GetParameterDetailsCommand
+import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.ParameterReference
 
 fun List<LayoutInspectorComposeProtocol.StringEntry>.toMap() = associate { it.id to it.str }
 
@@ -35,6 +37,26 @@
     }.build()
 }.build()
 
+fun GetParameterDetailsCommand(
+    rootViewId: Long,
+    reference: ParameterReference,
+    startIndex: Int,
+    maxElements: Int,
+    skipSystemComposables: Boolean = true
+) = Command.newBuilder().apply {
+    getParameterDetailsCommand = GetParameterDetailsCommand.newBuilder().apply {
+        this.rootViewId = rootViewId
+        this.skipSystemComposables = skipSystemComposables
+        this.reference = reference
+        if (startIndex >= 0) {
+            this.startIndex = startIndex
+        }
+        if (maxElements >= 0) {
+            this.maxElements = maxElements
+        }
+    }.build()
+}.build()
+
 fun GetComposablesCommand(rootViewId: Long, skipSystemComposables: Boolean = true) =
     Command.newBuilder().apply {
         getComposablesCommand = GetComposablesCommand.newBuilder()
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/ComposeLayoutInspector.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/ComposeLayoutInspector.kt
index 4080ce9..3da3c70 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/ComposeLayoutInspector.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/ComposeLayoutInspector.kt
@@ -24,7 +24,9 @@
 import androidx.compose.ui.inspection.framework.flatten
 import androidx.compose.ui.inspection.inspector.InspectorNode
 import androidx.compose.ui.inspection.inspector.LayoutInspectorTree
+import androidx.compose.ui.inspection.inspector.NodeParameterReference
 import androidx.compose.ui.inspection.proto.StringTable
+import androidx.compose.ui.inspection.proto.convert
 import androidx.compose.ui.inspection.proto.convertAll
 import androidx.compose.ui.inspection.util.ThreadUtils
 import androidx.inspection.Connection
@@ -36,6 +38,8 @@
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.GetAllParametersResponse
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.GetComposablesCommand
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.GetComposablesResponse
+import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.GetParameterDetailsCommand
+import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.GetParameterDetailsResponse
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.GetParametersCommand
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.GetParametersResponse
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.ParameterGroup
@@ -90,6 +94,9 @@
             Command.SpecializedCase.GET_ALL_PARAMETERS_COMMAND -> {
                 handleGetAllParametersCommand(command.getAllParametersCommand, callback)
             }
+            Command.SpecializedCase.GET_PARAMETER_DETAILS_COMMAND -> {
+                handleGetParameterDetailsCommand(command.getParameterDetailsCommand, callback)
+            }
             else -> error("Unexpected compose inspector command case: ${command.specializedCase}")
         }
     }
@@ -137,11 +144,13 @@
                 getParametersCommand.skipSystemComposables
             )[getParametersCommand.composableId]
 
+        val rootId = getParametersCommand.rootViewId
+
         callback.reply {
             getParametersResponse = if (foundComposable != null) {
                 val stringTable = StringTable()
-                val parameters =
-                    foundComposable.convertParameters(layoutInspectorTree).convertAll(stringTable)
+                val parameters = foundComposable.convertParameters(layoutInspectorTree, rootId)
+                    .convertAll(stringTable)
                 GetParametersResponse.newBuilder().apply {
                     parameterGroup = ParameterGroup.newBuilder().apply {
                         composableId = getParametersCommand.composableId
@@ -165,11 +174,13 @@
                 getAllParametersCommand.skipSystemComposables
             ).values
 
+        val rootId = getAllParametersCommand.rootViewId
+
         callback.reply {
             val stringTable = StringTable()
             val parameterGroups = allComposables.map { composable ->
-                val parameters =
-                    composable.convertParameters(layoutInspectorTree).convertAll(stringTable)
+                val parameters = composable.convertParameters(layoutInspectorTree, rootId)
+                    .convertAll(stringTable)
                 ParameterGroup.newBuilder().apply {
                     composableId = composable.id
                     addAllParameter(parameters)
@@ -177,13 +188,50 @@
             }
 
             getAllParametersResponse = GetAllParametersResponse.newBuilder().apply {
-                rootViewId = getAllParametersCommand.rootViewId
+                rootViewId = rootId
                 addAllParameterGroups(parameterGroups)
                 addAllStrings(stringTable.toStringEntries())
             }.build()
         }
     }
 
+    private fun handleGetParameterDetailsCommand(
+        getParameterDetailsCommand: GetParameterDetailsCommand,
+        callback: CommandCallback
+    ) {
+        val composables = getComposableNodes(
+            getParameterDetailsCommand.rootViewId,
+            getParameterDetailsCommand.skipSystemComposables
+        )
+        val reference = NodeParameterReference(
+            getParameterDetailsCommand.reference.composableId,
+            getParameterDetailsCommand.reference.parameterIndex,
+            getParameterDetailsCommand.reference.compositeIndexList
+        )
+        val expanded = composables[reference.nodeId]?.let { composable ->
+            layoutInspectorTree.expandParameter(
+                getParameterDetailsCommand.rootViewId,
+                composable,
+                reference,
+                getParameterDetailsCommand.startIndex,
+                getParameterDetailsCommand.maxElements
+            )
+        }
+
+        callback.reply {
+            getParameterDetailsResponse = if (expanded != null) {
+                val stringTable = StringTable()
+                GetParameterDetailsResponse.newBuilder().apply {
+                    rootViewId = getParameterDetailsCommand.rootViewId
+                    parameter = expanded.convert(stringTable)
+                    addAllStrings(stringTable.toStringEntries())
+                }.build()
+            } else {
+                GetParameterDetailsResponse.getDefaultInstance()
+            }
+        }
+    }
+
     /**
      * Get all [InspectorNode]s found under the layout tree rooted by [rootViewId]. They will be
      * mapped with their ID as the key.
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/compose/ComposeExtensions.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/compose/ComposeExtensions.kt
index a655403..f98479d 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/compose/ComposeExtensions.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/compose/ComposeExtensions.kt
@@ -27,9 +27,12 @@
  * This method can take a long time, especially the first time, and should be called off the main
  * thread.
  */
-fun InspectorNode.convertParameters(layoutInspectorTree: LayoutInspectorTree): List<NodeParameter> {
+fun InspectorNode.convertParameters(
+    layoutInspectorTree: LayoutInspectorTree,
+    rootId: Long
+): List<NodeParameter> {
     ThreadUtils.assertOffMainThread()
-    return layoutInspectorTree.convertParameters(this)
+    return layoutInspectorTree.convertParameters(rootId, this)
 }
 
 /**
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt
index 7138052..43b8e2d 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/LayoutInspectorTree.kt
@@ -110,8 +110,37 @@
     /**
      * Converts the [RawParameter]s of the [node] into displayable parameters.
      */
-    fun convertParameters(node: InspectorNode): List<NodeParameter> {
-        return node.parameters.mapNotNull { parameterFactory.create(node, it.name, it.value) }
+    fun convertParameters(rootId: Long, node: InspectorNode): List<NodeParameter> {
+        return node.parameters.mapIndexed { index, parameter ->
+            parameterFactory.create(rootId, node, parameter.name, parameter.value, index)
+        }
+    }
+
+    /**
+     * Converts a part of the [RawParameter] identified by [reference] into a
+     * displayable parameter. If the parameter is some sort of a collection
+     * then [startIndex] and [maxElements] describes the scope of the data returned.
+     */
+    fun expandParameter(
+        rootId: Long,
+        node: InspectorNode,
+        reference: NodeParameterReference,
+        startIndex: Int,
+        maxElements: Int
+    ): NodeParameter? {
+        if (reference.parameterIndex !in node.parameters.indices) {
+            return null
+        }
+        val parameter = node.parameters[reference.parameterIndex]
+        return parameterFactory.expand(
+            rootId,
+            node,
+            parameter.name,
+            parameter.value,
+            reference,
+            startIndex,
+            maxElements
+        )
     }
 
     /**
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/NodeParameter.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/NodeParameter.kt
index afa1d8a..f9057e6 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/NodeParameter.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/NodeParameter.kt
@@ -39,6 +39,18 @@
      * Sub elements of the parameter.
      */
     val elements = mutableListOf<NodeParameter>()
+
+    /**
+     * Reference to value parameter.
+     */
+    var reference: NodeParameterReference? = null
+
+    /**
+     * The index into the composite parent parameter value.
+     *
+     * If the index is identical to index of the parent element list then this value will be -1.
+     */
+    var index = -1
 }
 
 /**
@@ -58,4 +70,5 @@
     DimensionEm,
     Lambda,
     FunctionReference,
+    Iterable,
 }
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/NodeParameterReference.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/NodeParameterReference.kt
new file mode 100644
index 0000000..de5268d
--- /dev/null
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/NodeParameterReference.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 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.compose.ui.inspection.inspector
+
+import androidx.compose.ui.inspection.util.asIntArray
+
+/**
+ * A reference to a parameter to a [NodeParameter]
+ *
+ * @param nodeId is the id of the node the parameter belongs to
+ * @param parameterIndex is the parameter index among [InspectorNode.parameters]
+ * @param indices are indices into the composite parameter
+ */
+class NodeParameterReference(
+    val nodeId: Long,
+    val parameterIndex: Int,
+    val indices: IntArray
+) {
+    constructor (
+        nodeId: Long,
+        parameterIndex: Int,
+        indices: List<Int>
+    ) : this(nodeId, parameterIndex, indices.asIntArray())
+}
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/ParameterFactory.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/ParameterFactory.kt
index 282b790..4d3d165 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/ParameterFactory.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/inspector/ParameterFactory.kt
@@ -37,18 +37,20 @@
 import androidx.compose.ui.text.font.FontWeight
 import androidx.compose.ui.text.font.ResourceFont
 import androidx.compose.ui.text.intl.Locale
-import androidx.compose.ui.text.intl.LocaleList
 import androidx.compose.ui.text.style.BaselineShift
 import androidx.compose.ui.text.style.TextDecoration
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.TextUnit
 import androidx.compose.ui.unit.TextUnitType
+import org.jetbrains.annotations.TestOnly
 import java.lang.reflect.Field
+import java.util.IdentityHashMap
 import kotlin.jvm.internal.FunctionReference
 import kotlin.jvm.internal.Lambda
 import kotlin.math.abs
 import kotlin.reflect.KClass
+import kotlin.reflect.KProperty
 import kotlin.reflect.KProperty1
 import kotlin.reflect.full.allSuperclasses
 import kotlin.reflect.full.declaredMemberProperties
@@ -57,8 +59,8 @@
 import kotlin.reflect.jvm.javaGetter
 import java.lang.reflect.Modifier as JavaModifier
 
-private const val MAX_RECURSIONS = 10
-private const val MAX_ITERABLE = 25
+private const val MAX_RECURSIONS = 2
+private const val MAX_ITERABLE_SIZE = 5
 
 private val reflectionScope: ReflectionScope = ReflectionScope()
 
@@ -98,6 +100,12 @@
 
     var density = Density(1.0f)
 
+    @set:TestOnly
+    var maxRecursions = MAX_RECURSIONS
+
+    @set:TestOnly
+    var maxIterable = MAX_ITERABLE_SIZE
+
     init {
         val textDecorationCombination = TextDecoration.combine(
             listOf(TextDecoration.LineThrough, TextDecoration.Underline)
@@ -121,17 +129,56 @@
      * Attempt to convert the value to a user readable value.
      * For now: return null when a conversion is not possible/found.
      */
-    fun create(node: InspectorNode, name: String, value: Any?): NodeParameter? {
+    fun create(
+        rootId: Long,
+        node: InspectorNode,
+        name: String,
+        value: Any?,
+        parameterIndex: Int
+    ): NodeParameter {
         val creator = creatorCache ?: ParameterCreator()
         try {
             return reflectionScope.withReflectiveAccess {
-                creator.create(node, name, value)
+                creator.create(rootId, node, name, value, parameterIndex)
             }
         } finally {
             creatorCache = creator
         }
     }
 
+    /**
+     * Create/expand the [NodeParameter] specified by [reference].
+     *
+     * @param node is the [InspectorNode] with the id of [reference].nodeId.
+     * @param name is the name of the [reference].parameterIndex'th parameter of [node].
+     * @param value is the value of the [reference].parameterIndex'th parameter of [node].
+     * @param startIndex is the index of the 1st wanted element of a List/Array.
+     * @param maxElements is the max number of elements wanted from a List/Array.
+     */
+    fun expand(
+        rootId: Long,
+        node: InspectorNode,
+        name: String,
+        value: Any?,
+        reference: NodeParameterReference,
+        startIndex: Int = 0,
+        maxElements: Int = maxIterable
+    ): NodeParameter? {
+        val creator = creatorCache ?: ParameterCreator()
+        try {
+            return reflectionScope.withReflectiveAccess {
+                creator.expand(rootId, node, name, value, reference, startIndex, maxElements)
+            }
+        } finally {
+            creatorCache = creator
+        }
+    }
+
+    fun clearCacheFor(rootId: Long) {
+        val creator = creatorCache ?: return
+        creator.clearCacheFor(rootId)
+    }
+
     private fun loadConstantsFrom(javaClass: Class<*>) {
         if (valuesLoaded.contains(javaClass) ||
             ignoredPackagePrefixes.any { javaClass.name.startsWith(it) }
@@ -253,62 +300,250 @@
      * Convenience class for building [NodeParameter]s.
      */
     private inner class ParameterCreator {
+        private var rootId = 0L
         private var node: InspectorNode? = null
+        private var parameterIndex = 0
         private var recursions = 0
+        private val valueIndex = mutableListOf<Int>()
+        private val valueLazyReferenceMap = IdentityHashMap<Any, MutableList<NodeParameter>>()
+        private val rootValueIndexCache =
+            mutableMapOf<Long, IdentityHashMap<Any, NodeParameterReference>>()
+        private var valueIndexMap = IdentityHashMap<Any, NodeParameterReference>()
 
-        fun create(node: InspectorNode, name: String, value: Any?): NodeParameter? = try {
-            this.node = node
+        fun create(
+            rootId: Long,
+            node: InspectorNode,
+            name: String,
+            value: Any?,
+            parameterIndex: Int
+        ): NodeParameter =
+            try {
+                setup(rootId, node, parameterIndex)
+                create(name, value) ?: createEmptyParameter(name)
+            } finally {
+                setup()
+            }
+
+        fun expand(
+            rootId: Long,
+            node: InspectorNode,
+            name: String,
+            value: Any?,
+            reference: NodeParameterReference,
+            startIndex: Int,
+            maxElements: Int
+        ): NodeParameter? {
+            setup(rootId, node, reference.parameterIndex)
+            var new = Pair(name, value)
+            for (i in reference.indices) {
+                new = find(new.first, new.second, i) ?: return null
+            }
             recursions = 0
-            create(name, value)
-        } finally {
-            this.node = null
+            valueIndex.addAll(reference.indices.asSequence())
+            val parameter = if (startIndex == 0) {
+                create(new.first, new.second)
+            } else {
+                createFromCompositeValue(new.first, new.second, startIndex, maxElements)
+            }
+            if (parameter == null && reference.indices.isEmpty()) {
+                return createEmptyParameter(name)
+            }
+            return parameter
+        }
+
+        fun clearCacheFor(rootId: Long) {
+            rootValueIndexCache.remove(rootId)
+        }
+
+        private fun setup(
+            newRootId: Long = 0,
+            newNode: InspectorNode? = null,
+            newParameterIndex: Int = 0
+        ) {
+            rootId = newRootId
+            node = newNode
+            parameterIndex = newParameterIndex
+            recursions = 0
+            valueIndex.clear()
+            valueLazyReferenceMap.clear()
+            valueIndexMap = rootValueIndexCache.getOrPut(newRootId) {
+                IdentityHashMap()
+            }
         }
 
         private fun create(name: String, value: Any?): NodeParameter? {
-            if (value == null || recursions >= MAX_RECURSIONS) {
+            if (value == null) {
                 return null
             }
-            try {
-                recursions++
-                createFromConstant(name, value)?.let { return it }
-                @OptIn(ComposeCompilerApi::class)
-                return when (value) {
-                    is AnnotatedString -> NodeParameter(name, ParameterType.String, value.text)
-                    is BaselineShift -> createFromBaselineShift(name, value)
-                    is Boolean -> NodeParameter(name, ParameterType.Boolean, value)
-                    is ComposableLambda -> createFromCLambda(name, value)
-                    is Color -> NodeParameter(name, ParameterType.Color, value.toArgb())
-//                    is CornerSize -> createFromCornerSize(name, value)
-                    is Double -> NodeParameter(name, ParameterType.Double, value)
-                    is Dp -> NodeParameter(name, DimensionDp, value.value)
-                    is Enum<*> -> NodeParameter(name, ParameterType.String, value.toString())
-                    is Float -> NodeParameter(name, ParameterType.Float, value)
-                    is FunctionReference -> NodeParameter(
-                        name, ParameterType.FunctionReference, arrayOf<Any>(value, value.name)
-                    )
-                    is FontListFontFamily -> createFromFontListFamily(name, value)
-                    is FontWeight -> NodeParameter(name, ParameterType.Int32, value.weight)
-                    is Modifier -> createFromModifier(name, value)
-                    is InspectableValue -> createFromInspectableValue(name, value)
-                    is Int -> NodeParameter(name, ParameterType.Int32, value)
-                    is Iterable<*> -> createFromIterable(name, value)
-                    is Lambda<*> -> createFromLambda(name, value)
-                    is Locale -> NodeParameter(name, ParameterType.String, value.toString())
-                    is LocaleList ->
-                        NodeParameter(name, ParameterType.String, value.localeList.joinToString())
-                    is Long -> NodeParameter(name, ParameterType.Int64, value)
-                    is Offset -> createFromOffset(name, value)
-                    is Shadow -> createFromShadow(name, value)
-                    is SolidColor -> NodeParameter(name, ParameterType.Color, value.value.toArgb())
-                    is String -> NodeParameter(name, ParameterType.String, value)
-                    is TextUnit -> createFromTextUnit(name, value)
-                    is ImageVector -> createFromImageVector(name, value)
-                    is View -> NodeParameter(name, ParameterType.String, value.javaClass.simpleName)
-                    else -> createFromKotlinReflection(name, value)
-                }
-            } finally {
-                recursions--
+            createFromSimpleValue(name, value)?.let { return it }
+
+            val existing = valueIndexMap[value] ?: return createFromCompositeValue(name, value)
+
+            // Do not decompose an instance we already decomposed.
+            // Instead reference the data that was already decomposed.
+            return createReferenceToExistingValue(name, value, existing)
+        }
+
+        private fun createFromSimpleValue(name: String, value: Any?): NodeParameter? {
+            if (value == null) {
+                return null
             }
+            createFromConstant(name, value)?.let { return it }
+            @OptIn(ComposeCompilerApi::class)
+            return when (value) {
+                is AnnotatedString -> NodeParameter(name, ParameterType.String, value.text)
+                is BaselineShift -> createFromBaselineShift(name, value)
+                is Boolean -> NodeParameter(name, ParameterType.Boolean, value)
+                is ComposableLambda -> createFromCLambda(name, value)
+                is Color -> NodeParameter(name, ParameterType.Color, value.toArgb())
+//              is CornerSize -> createFromCornerSize(name, value)
+                is Double -> NodeParameter(name, ParameterType.Double, value)
+                is Dp -> NodeParameter(name, DimensionDp, value.value)
+                is Enum<*> -> NodeParameter(name, ParameterType.String, value.toString())
+                is Float -> NodeParameter(name, ParameterType.Float, value)
+                is FunctionReference -> createFromFunctionReference(name, value)
+                is FontListFontFamily -> createFromFontListFamily(name, value)
+                is FontWeight -> NodeParameter(name, ParameterType.Int32, value.weight)
+                is Int -> NodeParameter(name, ParameterType.Int32, value)
+                is Lambda<*> -> createFromLambda(name, value)
+                is Locale -> NodeParameter(name, ParameterType.String, value.toString())
+                is Long -> NodeParameter(name, ParameterType.Int64, value)
+                is Offset -> createFromOffset(name, value)
+                is SolidColor -> NodeParameter(name, ParameterType.Color, value.value.toArgb())
+                is String -> NodeParameter(name, ParameterType.String, value)
+                is TextUnit -> createFromTextUnit(name, value)
+                is ImageVector -> createFromImageVector(name, value)
+                is View -> NodeParameter(name, ParameterType.String, value.javaClass.simpleName)
+                else -> null
+            }
+        }
+
+        private fun createFromCompositeValue(
+            name: String,
+            value: Any?,
+            startIndex: Int = 0,
+            maxElements: Int = maxIterable
+        ): NodeParameter? = when {
+            value == null -> null
+            value is Modifier -> createFromModifier(name, value)
+            value is InspectableValue -> createFromInspectableValue(name, value)
+            value is Sequence<*> ->
+                createFromSequence(name, value, value, startIndex, maxElements)
+            value is Iterable<*> ->
+                createFromSequence(name, value, value.asSequence(), startIndex, maxElements)
+            value.javaClass.isArray -> createFromArray(name, value, startIndex, maxElements)
+            value is Shadow -> createFromShadow(name, value)
+            else -> createFromKotlinReflection(name, value)
+        }
+
+        private fun find(name: String, value: Any?, index: Int): Pair<String, Any?>? = when {
+            value == null -> null
+            value is Modifier -> findFromModifier(name, value, index)
+            value is InspectableValue -> findFromInspectableValue(value, index)
+            value is Sequence<*> -> findFromSequence(value, index)
+            value is Iterable<*> -> findFromSequence(value.asSequence(), index)
+            value.javaClass.isArray -> findFromArray(value, index)
+            value is Shadow -> findFromShadow(value, index)
+            else -> findFromKotlinReflection(value, index)
+        }
+
+        private fun createRecursively(
+            name: String,
+            value: Any?,
+            index: Int,
+            elementsIndex: Int
+        ): NodeParameter? {
+            valueIndex.add(index)
+            recursions++
+            val parameter = create(name, value)?.apply {
+                this.index = if (index != elementsIndex) index else -1
+            }
+            recursions--
+            valueIndex.removeLast()
+            return parameter
+        }
+
+        private fun shouldRecurseDeeper(): Boolean =
+            recursions < maxRecursions
+
+        /**
+         * Create a [NodeParameter] as a reference to a previously created parameter.
+         *
+         * Use [createFromCompositeValue] to compute the data type and top value,
+         * however no children will be created. Instead a reference to the previously
+         * created parameter is specified.
+         */
+        private fun createReferenceToExistingValue(
+            name: String,
+            value: Any?,
+            ref: NodeParameterReference
+        ): NodeParameter? {
+            val remember = recursions
+            recursions = maxRecursions
+            val parameter = createFromCompositeValue(name, value)?.apply { reference = ref }
+            recursions = remember
+            return parameter
+        }
+
+        /**
+         * Store the reference of this [NodeParameter] by its [value]
+         *
+         * If the value is seen in other parameter values again, there is
+         * no need to create child parameters a second time.
+         */
+        private fun NodeParameter.store(value: Any?): NodeParameter {
+            if (value != null) {
+                val index = valueIndexToReference()
+                valueIndexMap[value] = index
+                valueLazyReferenceMap.remove(value)?.forEach { it.reference = index }
+            }
+            return this
+        }
+
+        /**
+         * Delay the creation of all child parameters of this composite parameter.
+         *
+         * If the child parameters are omitted because of [maxRecursions], store the
+         * parameter itself such that its reference can be updated if it turns out
+         * that child [NodeParameter]s need to be generated later.
+         */
+        private fun NodeParameter.withChildReference(value: Any): NodeParameter {
+            valueLazyReferenceMap.getOrPut(value, { mutableListOf() }).add(this)
+            reference = valueIndexToReference()
+            return this
+        }
+
+        private fun valueIndexToReference(): NodeParameterReference =
+            NodeParameterReference(node!!.id, parameterIndex, valueIndex)
+
+        private fun createEmptyParameter(name: String): NodeParameter =
+            NodeParameter(name, ParameterType.String, "")
+
+        private fun createFromArray(
+            name: String,
+            value: Any,
+            startIndex: Int,
+            maxElements: Int
+        ): NodeParameter? {
+            val sequence = arrayToSequence(value) ?: return null
+            return createFromSequence(name, value, sequence, startIndex, maxElements)
+        }
+
+        private fun findFromArray(value: Any, index: Int): Pair<String, Any?>? {
+            val sequence = arrayToSequence(value) ?: return null
+            return findFromSequence(sequence, index)
+        }
+
+        private fun arrayToSequence(value: Any): Sequence<*>? = when (value) {
+            is Array<*> -> value.asSequence()
+            is ByteArray -> value.asSequence()
+            is IntArray -> value.asSequence()
+            is LongArray -> value.asSequence()
+            is FloatArray -> value.asSequence()
+            is DoubleArray -> value.asSequence()
+            is BooleanArray -> value.asSequence()
+            is CharArray -> value.asSequence()
+            else -> null
         }
 
         private fun createFromBaselineShift(name: String, value: BaselineShift): NodeParameter {
@@ -351,10 +586,40 @@
                 NodeParameter(name, ParameterType.Resource, it.resId)
             }
 
+        private fun createFromFunctionReference(
+            name: String,
+            value: FunctionReference
+        ): NodeParameter =
+            NodeParameter(name, ParameterType.FunctionReference, arrayOf<Any>(value, value.name))
+
         private fun createFromKotlinReflection(name: String, value: Any): NodeParameter? {
+            val simpleName = value::class.simpleName
+            val properties = lookup(value) ?: return null
+            val parameter = NodeParameter(name, ParameterType.String, simpleName)
+            return when {
+                properties.isEmpty() -> parameter
+                !shouldRecurseDeeper() -> parameter.withChildReference(value)
+                else -> {
+                    val elements = parameter.store(value).elements
+                    properties.values.mapIndexedNotNullTo(elements) { index, part ->
+                        createRecursively(part.name, valueOf(part, value), index, elements.size)
+                    }
+                    parameter
+                }
+            }
+        }
+
+        private fun findFromKotlinReflection(value: Any, index: Int): Pair<String, Any?>? {
+            val properties = lookup(value)?.entries?.iterator()?.asSequence() ?: return null
+            val element = properties.elementAtOrNull(index)?.value ?: return null
+            return Pair(element.name, valueOf(element, value))
+        }
+
+        private fun lookup(value: Any): Map<String, KProperty<*>>? {
             val kClass = value::class
+            val simpleName = kClass.simpleName
             val qualifiedName = kClass.qualifiedName
-            if (kClass.simpleName == null ||
+            if (simpleName == null ||
                 qualifiedName == null ||
                 ignoredPackagePrefixes.any { qualifiedName.startsWith(it) }
             ) {
@@ -363,28 +628,21 @@
                 // - certain android packages
                 return null
             }
-            val parameter = NodeParameter(name, ParameterType.String, kClass.simpleName)
-            val properties = mutableMapOf<String, KProperty1<Any, *>>()
-            try {
+            return try {
                 sequenceOf(kClass).plus(kClass.allSuperclasses.asSequence())
                     .flatMap { it.declaredMemberProperties.asSequence() }
-                    .filterIsInstance<KProperty1<Any, *>>()
-                    .associateByTo(properties) { it.name }
+                    .associateBy { it.name }
             } catch (ex: Throwable) {
                 Log.w("Compose", "Could not decompose ${kClass.simpleName}", ex)
-                return parameter
+                null
             }
-            properties.values.mapNotNullTo(parameter.elements) {
-                create(it.name, valueOf(it, value))
-            }
-            return parameter
         }
 
-        private fun valueOf(property: KProperty1<Any, *>, instance: Any): Any? = try {
+        private fun valueOf(property: KProperty<*>, instance: Any): Any? = try {
             property.isAccessible = true
             // Bug in kotlin reflection API: if the type is a nullable inline type with a null
             // value, we get an IllegalArgumentException in this line:
-            property.get(instance)
+            property.getter.call(instance)
         } catch (ex: Throwable) {
             // TODO: Remove this warning since this is expected with nullable inline types
             Log.w("Compose", "Could not get value of ${property.name}")
@@ -398,39 +656,99 @@
             val tempValue = value.valueOverride ?: ""
             val parameterName = name.ifEmpty { value.nameFallback } ?: "element"
             val parameterValue = if (tempValue is InspectableValue) "" else tempValue
-            val parameter = create(parameterName, parameterValue)
+            val parameter = createFromSimpleValue(parameterName, parameterValue)
                 ?: NodeParameter(parameterName, ParameterType.String, "")
-            val elements = parameter.elements
-            value.inspectableElements.mapNotNullTo(elements) { create(it.name, it.value) }
+            if (!shouldRecurseDeeper()) {
+                return parameter.withChildReference(value)
+            }
+            val elements = parameter.store(value).elements
+            value.inspectableElements.mapIndexedNotNullTo(elements) { index, element ->
+                createRecursively(element.name, element.value, index, elements.size)
+            }
             return parameter
         }
 
-        private fun createFromIterable(name: String, value: Iterable<*>): NodeParameter {
-            val parameter = NodeParameter(name, ParameterType.String, "")
-            val elements = parameter.elements
-            value.asSequence()
-                .mapNotNull { create(elements.size.toString(), it) }
-                .takeWhile { elements.size < MAX_ITERABLE }
-                .toCollection(elements)
-            return parameter
+        private fun findFromInspectableValue(
+            value: InspectableValue,
+            index: Int
+        ): Pair<String, Any?>? {
+            val elements = value.inspectableElements.toList()
+            if (index !in elements.indices) {
+                return null
+            }
+            val element = elements[index]
+            return Pair(element.name, element.value)
+        }
+
+        private fun createFromSequence(
+            name: String,
+            value: Any,
+            sequence: Sequence<*>,
+            startIndex: Int,
+            maxElements: Int
+        ): NodeParameter {
+            val parameter = NodeParameter(name, ParameterType.Iterable, "")
+            return when {
+                !sequence.any() -> parameter
+                !shouldRecurseDeeper() -> parameter.withChildReference(value)
+                else -> {
+                    val elements = parameter.store(value).elements
+                    val rest = sequence.drop(startIndex)
+                    rest.take(maxElements)
+                        .mapIndexedNotNullTo(elements) { i, it ->
+                            val index = startIndex + i
+                            createRecursively("[$index]", it, index, startIndex + elements.size)
+                        }
+                    if (rest.drop(maxElements).any()) {
+                        parameter.withChildReference(value)
+                    }
+                    parameter
+                }
+            }
+        }
+
+        private fun findFromSequence(value: Sequence<*>, index: Int): Pair<String, Any?>? {
+            val element = value.elementAtOrNull(index) ?: return null
+            return Pair("[$index]", element)
         }
 
         private fun createFromLambda(name: String, value: Lambda<*>): NodeParameter =
             NodeParameter(name, ParameterType.Lambda, arrayOf<Any>(value))
 
-        private fun createFromModifier(name: String, value: Modifier): NodeParameter? =
-            when {
-                name.isNotEmpty() -> {
-                    val parameter = NodeParameter(name, ParameterType.String, "")
-                    val elements = parameter.elements
-                    value.foldIn(elements) { acc, m ->
-                        create("", m)?.let { param -> acc.apply { add(param) } } ?: acc
+        private fun createFromModifier(name: String, value: Modifier): NodeParameter? = when {
+            name.isNotEmpty() -> {
+                val parameter = NodeParameter(name, ParameterType.String, "")
+                val modifiers = mutableListOf<Modifier.Element>()
+                value.foldIn(modifiers) { acc, m -> acc.apply { add(m) } }
+                when {
+                    modifiers.isEmpty() -> parameter
+                    !shouldRecurseDeeper() -> parameter.withChildReference(value)
+                    else -> {
+                        val elements = parameter.elements
+                        modifiers.mapIndexedNotNullTo(elements) { index, element ->
+                            createRecursively("", element, index, elements.size)
+                        }
+                        parameter.store(value)
                     }
-                    parameter
                 }
-                value is InspectableValue -> createFromInspectableValue(name, value)
-                else -> null
             }
+            value is InspectableValue -> createFromInspectableValue(name, value)
+            else -> null
+        }
+
+        private fun findFromModifier(
+            name: String,
+            value: Modifier,
+            index: Int
+        ): Pair<String, Any?>? = when {
+            name.isNotEmpty() -> {
+                val modifiers = mutableListOf<Modifier.Element>()
+                value.foldIn(modifiers) { acc, m -> acc.apply { add(m) } }
+                if (index in modifiers.indices) Pair("", modifiers[index]) else null
+            }
+            value is InspectableValue -> findFromInspectableValue(value, index)
+            else -> null
+        }
 
         private fun createFromOffset(name: String, value: Offset): NodeParameter {
             val parameter = NodeParameter(name, ParameterType.String, Offset::class.java.simpleName)
@@ -446,12 +764,22 @@
             val elements = parameter.elements
             val index = elements.indexOfFirst { it.name == "blurRadius" }
             if (index >= 0) {
+                val existing = elements[index]
                 val blurRadius = with(density) { value.blurRadius.toDp().value }
                 elements[index] = NodeParameter("blurRadius", DimensionDp, blurRadius)
+                elements[index].index = existing.index
             }
             return parameter
         }
 
+        private fun findFromShadow(value: Shadow, index: Int): Pair<String, Any?>? {
+            val result = findFromKotlinReflection(value, index)
+            if (result == null || result.first != "blurRadius") {
+                return result
+            }
+            return Pair("blurRadius", with(density) { value.blurRadius.toDp() })
+        }
+
         @Suppress("DEPRECATION")
         private fun createFromTextUnit(name: String, value: TextUnit): NodeParameter =
             when (value.type) {
diff --git a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/proto/ComposeExtensions.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/proto/ComposeExtensions.kt
index a857ff2..49db326 100644
--- a/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/proto/ComposeExtensions.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/proto/ComposeExtensions.kt
@@ -20,11 +20,13 @@
 import androidx.compose.ui.inspection.LambdaLocation
 import androidx.compose.ui.inspection.inspector.InspectorNode
 import androidx.compose.ui.inspection.inspector.NodeParameter
+import androidx.compose.ui.inspection.inspector.NodeParameterReference
 import androidx.compose.ui.inspection.inspector.ParameterType
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.Bounds
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.ComposableNode
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.LambdaValue
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.Parameter
+import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.ParameterReference
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.Quad
 import layoutinspector.compose.inspection.LayoutInspectorComposeProtocol.Rect
 
@@ -84,6 +86,7 @@
         ParameterType.DimensionEm -> Parameter.Type.DIMENSION_EM
         ParameterType.Lambda -> Parameter.Type.LAMBDA
         ParameterType.FunctionReference -> Parameter.Type.FUNCTION_REFERENCE
+        ParameterType.Iterable -> Parameter.Type.ITERABLE
     }
 }
 
@@ -114,6 +117,9 @@
         Parameter.Type.RESOURCE -> setResourceType(value, stringTable)
         Parameter.Type.LAMBDA -> setFunctionType(value, stringTable)
         Parameter.Type.FUNCTION_REFERENCE -> setFunctionType(value, stringTable)
+        Parameter.Type.ITERABLE -> {
+            // TODO: b/181899238 Support size for List and Array types
+        }
         else -> error("Unknown Composable parameter type: $type")
     }
 }
@@ -152,7 +158,20 @@
         name = stringTable.put(nodeParam.name)
         type = nodeParam.type.convert()
         setValue(stringTable, nodeParam.value)
-        addAllElements(nodeParam.elements.map { it.convert(stringTable) })
+        index = nodeParam.index
+        nodeParam.reference?.let { reference = it.convert() }
+        if (nodeParam.elements.isNotEmpty()) {
+            addAllElements(nodeParam.elements.map { it.convert(stringTable) })
+        }
+    }.build()
+}
+
+fun NodeParameterReference.convert(): ParameterReference {
+    val reference = this
+    return ParameterReference.newBuilder().apply {
+        composableId = reference.nodeId
+        parameterIndex = reference.parameterIndex
+        addAllCompositeIndex(reference.indices.asIterable())
     }.build()
 }
 
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/util/IntArray.kt
similarity index 77%
copy from compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
copy to compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/util/IntArray.kt
index 7e01354..bce161e 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
+++ b/compose/ui/ui-inspection/src/main/java/androidx/compose/ui/inspection/util/IntArray.kt
@@ -1,5 +1,3 @@
-// ktlint-disable filename
-
 /*
  * Copyright 2021 The Android Open Source Project
  *
@@ -16,6 +14,9 @@
  * limitations under the License.
  */
 
-package androidx.compose.foundation
+package androidx.compose.ui.inspection.util
 
-internal actual typealias AtomicReference<V> = java.util.concurrent.atomic.AtomicReference<V>
\ No newline at end of file
+private val EMPTY_INT_ARRAY = intArrayOf()
+
+fun List<Int>.asIntArray() =
+    if (isNotEmpty()) toIntArray() else EMPTY_INT_ARRAY
diff --git a/compose/ui/ui-inspection/src/main/proto/compose_layout_inspection.proto b/compose/ui/ui-inspection/src/main/proto/compose_layout_inspection.proto
index 373809d..a323d17 100644
--- a/compose/ui/ui-inspection/src/main/proto/compose_layout_inspection.proto
+++ b/compose/ui/ui-inspection/src/main/proto/compose_layout_inspection.proto
@@ -121,11 +121,24 @@
       DIMENSION_EM = 11;
       LAMBDA = 12;
       FUNCTION_REFERENCE = 13;
+      ITERABLE = 14;
     }
 
     Type type = 1;
     int32 name = 2;
     repeated Parameter elements = 3;
+    ParameterReference reference = 4;
+
+    // If this Parameter appears in the elements of another parameter:
+    // This index is the "natural" index of the value in the agent. If the index
+    // is identical to the elements index we do not need this value and it will
+    // be set to -1.
+    //
+    // However if some of the "sibling" values in the agent are null or cannot be
+    // decomposed, those siblings are omitted from the Parameter.elements.
+    // For all subsequent parameter elements we need to have the original index in
+    // order to find the value again using the GetParameterDetailsCommand.
+    sint32 index = 5;
 
     oneof value {
         int32 int32_value = 11;
@@ -137,6 +150,22 @@
     }
 }
 
+// A reference to a "part" of a parameter value
+message ParameterReference {
+  sint64 composable_id = 1;
+
+  // Identifies an index into a ParameterGroup
+  int32 parameter_index = 2;
+
+  // If the parameter value is a composite value such as:
+  //    List<MyClass>
+  // then:
+  //    composite_index[0] is the index into the List
+  //    composite_index[1] is the index into the fields in MyClass
+  //    composite_index[2] is the index into the field found by [1] etc...
+  repeated int32 composite_index = 3;
+}
+
 // A collection of all parameters associated with a single composable
 message ParameterGroup {
   sint64 composable_id = 1;
@@ -183,11 +212,27 @@
   repeated ParameterGroup parameter_groups = 3;
 }
 
+// Request parameter details for the parameter specified
+message GetParameterDetailsCommand {
+  int64 root_view_id = 1;
+  ParameterReference reference = 2;
+  int32 start_index = 3;
+  int32 max_elements = 4;
+  bool skip_system_composables = 5;
+}
+
+message GetParameterDetailsResponse {
+  int64 root_view_id = 1; // Echoed from GetParameterDetailsCommand
+  repeated StringEntry strings = 2;
+  Parameter parameter = 3;
+}
+
 message Command {
   oneof specialized {
     GetComposablesCommand get_composables_command = 1;
     GetParametersCommand get_parameters_command = 2;
     GetAllParametersCommand get_all_parameters_command = 3;
+    GetParameterDetailsCommand get_parameter_details_command = 4;
   }
 }
 
@@ -196,5 +241,6 @@
     GetComposablesResponse get_composables_response = 1;
     GetParametersResponse get_parameters_response = 2;
     GetAllParametersResponse get_all_parameters_response = 3;
+    GetParameterDetailsResponse get_parameter_details_response = 4;
   }
 }
diff --git a/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/MultipleActivitiesClickTest.kt b/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/MultipleActivitiesClickTest.kt
index 1df07e6..7d191ea 100644
--- a/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/MultipleActivitiesClickTest.kt
+++ b/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/MultipleActivitiesClickTest.kt
@@ -24,13 +24,14 @@
 import androidx.compose.material.Button
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.SemanticsNodeInteractionCollection
 import androidx.compose.ui.test.click
+import androidx.compose.ui.test.onAllNodesWithTag
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.performGesture
 import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry
 import androidx.test.runner.lifecycle.Stage
 import com.google.common.truth.Truth.assertThat
-import org.junit.Ignore
 import org.junit.Rule
 import org.junit.Test
 
@@ -40,11 +41,15 @@
     val rule = createAndroidComposeRule<Activity1>()
 
     @Test
-    @Ignore("b/155774664")
     fun test() {
         lateinit var activity1: Activity1
         rule.activityRule.scenario.onActivity { activity1 = it }
+
         activity1.startNewActivity()
+        rule.waitUntil {
+            rule.onAllNodesWithTag("activity2").isNotEmpty()
+        }
+
         rule.onNodeWithTag("activity2").performGesture { click() }
         val activity2 = getCurrentActivity() as Activity2
 
@@ -54,6 +59,10 @@
         }
     }
 
+    private fun SemanticsNodeInteractionCollection.isNotEmpty(): Boolean {
+        return fetchSemanticsNodes(atLeastOneRootRequired = false).isNotEmpty()
+    }
+
     // In general this method to retrieve the current activity may fail, because the presence of
     // an ActivityLifecycleMonitorRegistry is dependent on the instrumentation used. The
     // instrumentation we use in our test setup supports this though, so it is safe to do here.
diff --git a/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/MultipleActivitiesFindTest.kt b/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/MultipleActivitiesFindTest.kt
index 97099aa..2f0d636 100644
--- a/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/MultipleActivitiesFindTest.kt
+++ b/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/MultipleActivitiesFindTest.kt
@@ -22,6 +22,8 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.SemanticsNodeInteractionCollection
+import androidx.compose.ui.test.onAllNodesWithTag
 import androidx.compose.ui.test.onNodeWithTag
 import org.junit.Rule
 import org.junit.Test
@@ -34,10 +36,18 @@
     @Test
     fun test() {
         rule.activityRule.scenario.onActivity { it.startNewActivity() }
+        rule.waitUntil {
+            rule.onAllNodesWithTag("activity2").isNotEmpty()
+        }
+
         rule.onNodeWithTag("activity1").assertDoesNotExist()
         rule.onNodeWithTag("activity2").assertExists()
     }
 
+    private fun SemanticsNodeInteractionCollection.isNotEmpty(): Boolean {
+        return fetchSemanticsNodes(atLeastOneRootRequired = false).isNotEmpty()
+    }
+
     class Activity1 : TaggedActivity("activity1")
     class Activity2 : TaggedActivity("activity2")
 
diff --git a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Actions.kt b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Actions.kt
index 0d97551..3a329f3 100644
--- a/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Actions.kt
+++ b/compose/ui/ui-test/src/commonMain/kotlin/androidx/compose/ui/test/Actions.kt
@@ -183,7 +183,7 @@
 
     @OptIn(InternalTestApi::class)
     testContext.testOwner.runOnUiThread {
-        node.config[key].action?.let { invocation(it) }
+        node.config[key].action?.let(invocation)
     }
 }
 
diff --git a/compose/ui/ui-text/benchmark/build.gradle b/compose/ui/ui-text/benchmark/build.gradle
index ab0fd49..beae82c 100644
--- a/compose/ui/ui-text/benchmark/build.gradle
+++ b/compose/ui/ui-text/benchmark/build.gradle
@@ -38,7 +38,7 @@
     implementation(JUNIT)
 
     androidTestImplementation project(":compose:runtime:runtime")
-    androidTestImplementation project(":compose:test-utils")
+    androidTestImplementation project(":compose:benchmark-utils")
     androidTestImplementation project(":compose:ui:ui")
     androidTestImplementation(KOTLIN_TEST_COMMON)
     androidTestImplementation(TRUTH)
diff --git a/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopParagraph.desktop.kt b/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopParagraph.desktop.kt
index ecc16cb..6e2e895 100644
--- a/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopParagraph.desktop.kt
+++ b/compose/ui/ui-text/src/desktopMain/kotlin/androidx/compose/ui/text/platform/DesktopParagraph.desktop.kt
@@ -62,7 +62,6 @@
 import org.jetbrains.skija.paragraph.RectWidthMode
 import org.jetbrains.skija.paragraph.TextBox
 import java.lang.UnsupportedOperationException
-import java.nio.charset.Charset
 import java.util.WeakHashMap
 import kotlin.math.floor
 import org.jetbrains.skija.Rect as SkRect
@@ -149,16 +148,21 @@
         get() = paragraphIntrinsics.maxIntrinsicWidth
 
     override val firstBaseline: Float
-        get() = para.getLineMetrics().firstOrNull()?.run { baseline.toFloat() } ?: 0f
+        get() = lineMetrics.firstOrNull()?.run { baseline.toFloat() } ?: 0f
 
     override val lastBaseline: Float
-        get() = para.getLineMetrics().lastOrNull()?.run { baseline.toFloat() } ?: 0f
+        get() = lineMetrics.lastOrNull()?.run { baseline.toFloat() } ?: 0f
 
     override val didExceedMaxLines: Boolean
         get() = para.didExceedMaxLines()
 
     override val lineCount: Int
-        get() = para.lineNumber.toInt()
+        // workaround for https://bugs.chromium.org/p/skia/issues/detail?id=11321
+        get() = if (text == "") {
+            1
+        } else {
+            para.lineNumber.toInt()
+        }
 
     override val placeholderRects: List<Rect?>
         get() =
@@ -188,50 +192,58 @@
             Rect(box.rect.right, box.rect.top, box.rect.right + cursorWidth, box.rect.bottom)
         } ?: Rect(0f, 0f, cursorWidth, paragraphIntrinsics.builder.defaultHeight)
 
-    override fun getLineLeft(lineIndex: Int): Float {
-        println("Paragraph.getLineLeft $lineIndex")
-        return 0.0f
-    }
+    override fun getLineLeft(lineIndex: Int): Float =
+        lineMetrics.getOrNull(lineIndex)?.left?.toFloat() ?: 0f
 
-    override fun getLineRight(lineIndex: Int): Float {
-        println("Paragraph.getLineRight $lineIndex")
-        return 0.0f
-    }
+    override fun getLineRight(lineIndex: Int): Float =
+        lineMetrics.getOrNull(lineIndex)?.right?.toFloat() ?: 0f
 
     override fun getLineTop(lineIndex: Int) =
-        para.lineMetrics.getOrNull(lineIndex)?.let { line ->
+        lineMetrics.getOrNull(lineIndex)?.let { line ->
             floor((line.baseline - line.ascent).toFloat())
         } ?: 0f
 
     override fun getLineBottom(lineIndex: Int) =
-        para.lineMetrics.getOrNull(lineIndex)?.let { line ->
+        lineMetrics.getOrNull(lineIndex)?.let { line ->
             floor((line.baseline + line.descent).toFloat())
         } ?: 0f
 
     private fun lineMetricsForOffset(offset: Int): LineMetrics? {
-        // For some reasons SkParagraph Line metrics use (UTF-8) byte offsets for start and end
-        // indexes
-        val byteOffset = text.substring(0, offset).toByteArray(Charset.forName("UTF-8")).size
-        val metrics = para.lineMetrics
+        val metrics = lineMetrics
         for (line in metrics) {
-            if (byteOffset < line.endIndex) {
+            if (offset < line.endIndex) {
                 return line
             }
         }
+        if (metrics.isEmpty()) {
+            return null
+        }
         return metrics.last()
     }
 
-    override fun getLineHeight(lineIndex: Int) = para.lineMetrics[lineIndex].height.toFloat()
+    override fun getLineHeight(lineIndex: Int) = lineMetrics[lineIndex].height.toFloat()
 
-    override fun getLineWidth(lineIndex: Int) = para.lineMetrics[lineIndex].width.toFloat()
+    override fun getLineWidth(lineIndex: Int) = lineMetrics[lineIndex].width.toFloat()
 
-    override fun getLineStart(lineIndex: Int) = para.lineMetrics[lineIndex].startIndex.toInt()
+    override fun getLineStart(lineIndex: Int) = lineMetrics[lineIndex].startIndex.toInt()
 
     override fun getLineEnd(lineIndex: Int, visibleEnd: Boolean) =
         if (visibleEnd) {
-            para.lineMetrics[lineIndex].endExcludingWhitespaces.toInt()
+            val metrics = lineMetrics[lineIndex]
+            // workarounds for https://bugs.chromium.org/p/skia/issues/detail?id=11321 :(
+            // we are waiting for fixes
+            if (lineIndex > 0 && metrics.startIndex < lineMetrics[lineIndex - 1].endIndex) {
+                metrics.endIndex.toInt()
+            } else if (
+                metrics.startIndex < text.length &&
+                text[metrics.startIndex.toInt()] == '\n'
+            ) {
+                metrics.startIndex.toInt()
+            } else {
+                metrics.endExcludingWhitespaces.toInt()
+            }
         } else {
-            para.lineMetrics[lineIndex].endIndex.toInt()
+            lineMetrics[lineIndex].endIndex.toInt()
         }
 
     override fun isLineEllipsized(lineIndex: Int) = false
@@ -253,6 +265,20 @@
         }
     }
 
+    // workaround for https://bugs.chromium.org/p/skia/issues/detail?id=11321 :(
+    private val lineMetrics: Array<LineMetrics>
+        get() = if (text == "") {
+            val height = paragraphIntrinsics.builder.defaultHeight.toDouble()
+            arrayOf(
+                LineMetrics(
+                    0, 0, 0, 0, true,
+                    height, 0.0, height, height, 0.0, 0.0, height, 0
+                )
+            )
+        } else {
+            para.lineMetrics
+        }
+
     private fun getBoxForwardByOffset(offset: Int): TextBox? {
         var to = offset + 1
         while (to <= text.length) {
@@ -309,8 +335,13 @@
         return box.rect.toComposeRect()
     }
 
-    override fun getWordBoundary(offset: Int) = para.getWordBoundary(offset).let {
-        TextRange(it.start, it.end)
+    override fun getWordBoundary(offset: Int): TextRange {
+        if (text[offset].isWhitespace()) {
+            return TextRange(offset, offset)
+        }
+        para.getWordBoundary(offset).let {
+            return TextRange(it.start, it.end)
+        }
     }
 
     override fun paint(
diff --git a/compose/ui/ui-text/src/desktopTest/kotlin/androidx/compose/ui/text/DesktopParagraphTest.kt b/compose/ui/ui-text/src/desktopTest/kotlin/androidx/compose/ui/text/DesktopParagraphTest.kt
index d76671f..e8d8c27 100644
--- a/compose/ui/ui-text/src/desktopTest/kotlin/androidx/compose/ui/text/DesktopParagraphTest.kt
+++ b/compose/ui/ui-text/src/desktopTest/kotlin/androidx/compose/ui/text/DesktopParagraphTest.kt
@@ -92,6 +92,46 @@
         }
     }
 
+    @Test
+    fun getLineEnd() {
+        with(defaultDensity) {
+            val text = ""
+            val paragraph = simpleParagraph(
+                text = text,
+                style = TextStyle(fontSize = 50.sp)
+            )
+
+            Truth.assertThat(paragraph.getLineEnd(0, true))
+                .isEqualTo(0)
+        }
+        with(defaultDensity) {
+            val text = "ab\n\nc"
+            val paragraph = simpleParagraph(
+                text = text,
+                style = TextStyle(fontSize = 50.sp)
+            )
+
+            Truth.assertThat(paragraph.getLineEnd(0, true))
+                .isEqualTo(2)
+            Truth.assertThat(paragraph.getLineEnd(1, true))
+                .isEqualTo(3)
+            Truth.assertThat(paragraph.getLineEnd(2, true))
+                .isEqualTo(5)
+        }
+        with(defaultDensity) {
+            val text = "ab\n"
+            val paragraph = simpleParagraph(
+                text = text,
+                style = TextStyle(fontSize = 50.sp)
+            )
+
+            Truth.assertThat(paragraph.getLineEnd(0, true))
+                .isEqualTo(2)
+            Truth.assertThat(paragraph.getLineEnd(1, true))
+                .isEqualTo(3)
+        }
+    }
+
     private fun simpleParagraph(
         text: String = "",
         style: TextStyle? = null,
diff --git a/compose/ui/ui-tooling-data/src/androidTest/java/androidx/compose/ui/tooling/data/InspectableTests.kt b/compose/ui/ui-tooling-data/src/androidTest/java/androidx/compose/ui/tooling/data/InspectableTests.kt
index 5c76487..134a6dc 100644
--- a/compose/ui/ui-tooling-data/src/androidTest/java/androidx/compose/ui/tooling/data/InspectableTests.kt
+++ b/compose/ui/ui-tooling-data/src/androidTest/java/androidx/compose/ui/tooling/data/InspectableTests.kt
@@ -147,6 +147,9 @@
             assertFalse(receiver.parameterCursor.hasNext())
         }
 
+        // Skip Inspectable
+        callCursor.next()
+
         // OneParameter(1)
         validate {
             parameter(name = "a", value = 1, fromDefault = false, static = true, compared = false)
@@ -337,7 +340,7 @@
                 it != null && it.sourceFile == "InspectableTests.kt"
             }
         }
-        val names = parameters.first().parameters.map { it.name }
+        val names = parameters.drop(1).first().parameters.map { it.name }
         assertEquals(
             "text, modifier, color, fontSize, fontStyle, fontWeight, fontFamily, " +
                 "letterSpacing, textDecoration, textAlign, lineHeight, overflow, softWrap, " +
diff --git a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTreeTest.kt b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTreeTest.kt
index 88b4989..7a375f3 100644
--- a/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTreeTest.kt
+++ b/compose/ui/ui-tooling/src/androidTest/java/androidx/compose/ui/tooling/inspector/LayoutInspectorTreeTest.kt
@@ -108,6 +108,12 @@
 
         validate(nodes, builder, checkParameters = false) {
             node(
+                name = "Inspectable",
+                fileName = "LayoutInspectorTreeTest.kt",
+                left = 0.0.dp, top = 0.0.dp, width = 72.0.dp, height = 78.9.dp,
+                children = listOf("Column")
+            )
+            node(
                 name = "Column",
                 fileName = "LayoutInspectorTreeTest.kt",
                 left = 0.0.dp, top = 0.0.dp, width = 72.0.dp, height = 78.9.dp,
@@ -173,10 +179,16 @@
 
         validate(nodes, builder, checkParameters = false) {
             node(
+                name = "Inspectable",
+                hasTransformations = true,
+                fileName = "LayoutInspectorTreeTest.kt",
+                children = listOf("MaterialTheme")
+            )
+            node(
                 name = "MaterialTheme",
                 hasTransformations = true,
                 fileName = "LayoutInspectorTreeTest.kt",
-                left = 68.0.dp, top = 49.7.dp, width = 88.6.dp, height = 21.7.dp,
+                left = 65.0.dp, top = 49.7.dp, width = 86.dp, height = 21.7.dp,
                 children = listOf("Text")
             )
             node(
@@ -184,7 +196,7 @@
                 isRenderNode = true,
                 hasTransformations = true,
                 fileName = "LayoutInspectorTreeTest.kt",
-                left = 68.0.dp, top = 49.7.dp, width = 88.6.dp, height = 21.7.dp,
+                left = 65.0.dp, top = 49.7.dp, width = 86.dp, height = 21.7.dp,
             )
         }
     }
@@ -214,6 +226,7 @@
 
         if (DEBUG) {
             validate(nodes, builder, checkParameters = false) {
+                node("Inspectable", children = listOf("Box"))
                 node("Box", children = listOf("ModalDrawer"))
                 node("ModalDrawer", children = listOf("Column", "Text"))
                 node("Column", children = listOf("Text", "Button"))
@@ -253,6 +266,7 @@
 
         if (DEBUG) {
             validate(nodes, builder, checkParameters = false) {
+                node("Inspectable", children = listOf("Box"))
                 node("Box", children = listOf("ModalDrawer"))
                 node("ModalDrawer", children = listOf("WithConstraints"))
                 node("WithConstraints", children = listOf("SubcomposeLayout"))
@@ -405,15 +419,16 @@
                 assertWithMessage(message).that(node.bounds).isEmpty()
             }
             if (left != Dp.Unspecified) {
+                val tolerance = 5.0f
                 with(density) {
                     assertWithMessage(message).that(node.left.toDp().value)
-                        .isWithin(2.0f).of(left.value)
+                        .isWithin(tolerance).of(left.value)
                     assertWithMessage(message).that(node.top.toDp().value)
-                        .isWithin(2.0f).of(top.value)
+                        .isWithin(tolerance).of(top.value)
                     assertWithMessage(message).that(node.width.toDp().value)
-                        .isWithin(2.0f).of(width.value)
+                        .isWithin(tolerance).of(width.value)
                     assertWithMessage(message).that(node.height.toDp().value)
-                        .isWithin(2.0f).of(height.value)
+                        .isWithin(tolerance).of(height.value)
                 }
             }
 
diff --git a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/preview/ComposeViewAdapter.kt b/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/preview/ComposeViewAdapter.kt
index ebcf466..8ed0973 100644
--- a/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/preview/ComposeViewAdapter.kt
+++ b/compose/ui/ui-tooling/src/main/java/androidx/compose/ui/tooling/preview/ComposeViewAdapter.kt
@@ -532,9 +532,7 @@
         this.onDraw = onDraw
 
         previewComposition = @Composable {
-            SideEffect {
-                onCommit()
-            }
+            SideEffect(onCommit)
 
             WrapPreview {
                 val composer = currentComposer
diff --git a/compose/ui/ui/benchmark/build.gradle b/compose/ui/ui/benchmark/build.gradle
new file mode 100644
index 0000000..06ca891
--- /dev/null
+++ b/compose/ui/ui/benchmark/build.gradle
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2021 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.Publish
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("AndroidXUiPlugin")
+    id("org.jetbrains.kotlin.android")
+    id("androidx.benchmark")
+}
+
+dependencies {
+    kotlinPlugin project(":compose:compiler:compiler")
+
+    androidTestImplementation(project(":activity:activity-compose"))
+    androidTestImplementation(project(":benchmark:benchmark-junit4"))
+    androidTestImplementation(project(":compose:foundation:foundation"))
+    androidTestImplementation(project(":compose:foundation:foundation-layout"))
+    androidTestImplementation(project(":compose:runtime:runtime"))
+    androidTestImplementation(project(":compose:benchmark-utils"))
+    androidTestImplementation(project(":compose:ui:ui"))
+    androidTestImplementation(ANDROIDX_TEST_RULES)
+    androidTestImplementation(JUNIT)
+    androidTestImplementation(KOTLIN_STDLIB)
+    androidTestImplementation(KOTLIN_TEST_COMMON)
+    androidTestImplementation(TRUTH)
+}
diff --git a/compose/ui/ui/benchmark/src/androidTest/AndroidManifest.xml b/compose/ui/ui/benchmark/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..7a944bd
--- /dev/null
+++ b/compose/ui/ui/benchmark/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2021 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"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="androidx.compose.ui.benchmark">
+
+    <!--
+      ~ Important: disable debuggable for accurate performance results
+      -->
+    <application
+            android:debuggable="false"
+            tools:replace="android:debuggable">
+        <!-- enable profileableByShell for non-intrusive profiling tools -->
+        <!--suppress AndroidElementNotAllowed -->
+        <profileable android:shell="true"/>
+        <activity android:name="androidx.compose.ui.input.pointer.TestActivity" />
+    </application>
+</manifest>
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/LayoutNodeModifierBenchmark.kt b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/LayoutNodeModifierBenchmark.kt
similarity index 97%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/LayoutNodeModifierBenchmark.kt
rename to compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/LayoutNodeModifierBenchmark.kt
index 2a21cce..e93fc61 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/LayoutNodeModifierBenchmark.kt
+++ b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/LayoutNodeModifierBenchmark.kt
@@ -16,7 +16,7 @@
 
 @file:Suppress("DEPRECATION_ERROR")
 
-package androidx.ui.benchmark.test
+package androidx.compose.ui.benchmark
 
 import androidx.activity.ComponentActivity
 import androidx.activity.compose.setContent
@@ -129,10 +129,9 @@
         val benchmarkRule = BenchmarkRule()
 
         override fun apply(base: Statement, description: Description?): Statement {
-            return RuleChain
-                .outerRule(benchmarkRule)
+            return RuleChain.outerRule(benchmarkRule)
                 .around(activityTestRule)
                 .apply(base, description)
         }
     }
-}
+}
\ No newline at end of file
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/OnPositionedBenchmark.kt b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/OnPositionedBenchmark.kt
similarity index 100%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/compose/ui/OnPositionedBenchmark.kt
rename to compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/OnPositionedBenchmark.kt
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/autofill/AndroidAutofillBenchmark.kt b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/autofill/AndroidAutofillBenchmark.kt
similarity index 97%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/autofill/AndroidAutofillBenchmark.kt
rename to compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/autofill/AndroidAutofillBenchmark.kt
index e234cd3..87cfc77 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/autofill/AndroidAutofillBenchmark.kt
+++ b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/autofill/AndroidAutofillBenchmark.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.ui.benchmark.test.autofill
+package androidx.compose.ui.benchmark.autofill
 
 import android.util.SparseArray
 import android.view.View
@@ -28,15 +28,15 @@
 import androidx.compose.ui.geometry.Rect
 import androidx.compose.ui.platform.LocalAutofillTree
 import androidx.compose.ui.platform.LocalView
+import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.test.annotation.UiThreadTest
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
-import androidx.compose.ui.test.junit4.createComposeRule
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import androidx.test.ext.junit.runners.AndroidJUnit4
 
 @LargeTest
 @OptIn(ExperimentalComposeUiApi::class)
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/pointerinput/AndroidTapIntegrationBenchmark.kt b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/AndroidTapIntegrationBenchmark.kt
similarity index 98%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/pointerinput/AndroidTapIntegrationBenchmark.kt
rename to compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/AndroidTapIntegrationBenchmark.kt
index 4d84c53..c6c0d53 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/pointerinput/AndroidTapIntegrationBenchmark.kt
+++ b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/AndroidTapIntegrationBenchmark.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.ui.pointerinput
+package androidx.compose.ui.benchmark.input.pointer
 
 import android.content.Context
 import android.view.MotionEvent
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/pointerinput/ComposeTapIntegrationBenchmark.kt b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/ComposeTapIntegrationBenchmark.kt
similarity index 96%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/pointerinput/ComposeTapIntegrationBenchmark.kt
rename to compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/ComposeTapIntegrationBenchmark.kt
index b551802..e865c16 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/pointerinput/ComposeTapIntegrationBenchmark.kt
+++ b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/ComposeTapIntegrationBenchmark.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.ui.pointerinput
+package androidx.compose.ui.benchmark.input.pointer
 
 import android.view.View
 import android.view.ViewGroup
@@ -25,7 +25,7 @@
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.requiredHeight
-import androidx.compose.material.Text
+import androidx.compose.foundation.text.BasicText
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.input.pointer.pointerInput
@@ -92,7 +92,7 @@
 
         rootView = activity.findViewById<ViewGroup>(android.R.id.content)
 
-        activityTestRule.runOnUiThreadIR {
+        activityTestRule.runOnUiThread {
             activity.setContent {
                 with(LocalDensity.current) {
                     itemHeightDp = ItemHeightPx.toDp()
@@ -174,7 +174,7 @@
 
     @Composable
     fun Email(label: String) {
-        Text(
+        BasicText(
             text = label,
             modifier = Modifier
                 .pointerInput(label) {
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/pointerinput/TapIntegrationBenchmarkValues.kt b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/TapIntegrationBenchmarkValues.kt
similarity index 85%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/pointerinput/TapIntegrationBenchmarkValues.kt
rename to compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/TapIntegrationBenchmarkValues.kt
index 903c918..796abbc 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/pointerinput/TapIntegrationBenchmarkValues.kt
+++ b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/TapIntegrationBenchmarkValues.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 20201 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.
@@ -14,7 +14,8 @@
  * limitations under the License.
  */
 
-package androidx.ui.pointerinput
+package androidx.compose.ui.benchmark.input.pointer
 
 val ItemHeightPx = 1f
+
 val NumItems = 100
\ No newline at end of file
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/pointerinput/TestActivity.kt b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/TestActivity.kt
similarity index 94%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/pointerinput/TestActivity.kt
rename to compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/TestActivity.kt
index 811b1b8..e8b5f9c 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/pointerinput/TestActivity.kt
+++ b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/TestActivity.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.ui.pointerinput
+package androidx.compose.ui.benchmark.input.pointer
 
 import androidx.activity.ComponentActivity
 import java.util.concurrent.CountDownLatch
diff --git a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/pointerinput/utils.kt b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/utils.kt
similarity index 85%
rename from compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/pointerinput/utils.kt
rename to compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/utils.kt
index aeb62bf..c28a69f 100644
--- a/compose/integration-tests/benchmark/src/androidTest/java/androidx/ui/pointerinput/utils.kt
+++ b/compose/ui/ui/benchmark/src/androidTest/java/androidx/compose/ui/benchmark/input/pointer/utils.kt
@@ -14,22 +14,11 @@
  * limitations under the License.
  */
 
-package androidx.ui.pointerinput
+package androidx.compose.ui.benchmark.input.pointer
 
 import android.view.MotionEvent
 import android.view.View
 
-// We only need this because IR compiler doesn't like converting lambdas to Runnables
-@Suppress("DEPRECATION")
-internal fun androidx.test.rule.ActivityTestRule<*>.runOnUiThreadIR(block: () -> Unit) {
-    val runnable: Runnable = object : Runnable {
-        override fun run() {
-            block()
-        }
-    }
-    runOnUiThread(runnable)
-}
-
 /**
  * Creates a simple [MotionEvent].
  *
diff --git a/compose/ui/ui/benchmark/src/main/AndroidManifest.xml b/compose/ui/ui/benchmark/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d1cfaab
--- /dev/null
+++ b/compose/ui/ui/benchmark/src/main/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2021 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.compose.ui.benchmark">
+    <application/>
+</manifest>
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
index d677d07..24ee32c 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
@@ -416,7 +416,7 @@
 
     @Test
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-    fun testAddExtraDataToAccessibilityNodeInfo() {
+    fun testAddExtraDataToAccessibilityNodeInfo_notMerged() {
         val tag = "TextField"
         lateinit var textLayoutResult: TextLayoutResult
 
@@ -454,6 +454,48 @@
         assertEquals(expectedRect.bottom, rectF.bottom)
     }
 
+    // This test needs to be improved after text merging(b/157474582) is fixed.
+    @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    fun testAddExtraDataToAccessibilityNodeInfo_merged() {
+        val tag = "MergedText"
+        val textOne = "hello"
+        val textTwo = "world"
+        lateinit var textLayoutResult: TextLayoutResult
+
+        container.setContent {
+            Column(modifier = Modifier.testTag(tag).semantics(true) {}) {
+                BasicText(text = textOne, onTextLayout = { textLayoutResult = it })
+                BasicText(text = textTwo)
+            }
+        }
+
+        val textNode = rule.onNodeWithTag(tag)
+            .fetchSemanticsNode("couldn't find node with tag $tag")
+        val info = AccessibilityNodeInfo.obtain()
+        val argument = Bundle()
+        val length = textOne.length + textTwo.length
+        argument.putInt(AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX, 0)
+        argument.putInt(AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH, length)
+        provider.addExtraDataToAccessibilityNodeInfo(
+            textNode.id,
+            info,
+            AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY,
+            argument
+        )
+        val data = info.extras
+            .getParcelableArray(AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY)
+        assertEquals(length, data!!.size)
+        val rectF = data[0] as RectF
+        val expectedRect = textLayoutResult.getBoundingBox(0).translate(
+            textNode.positionInWindow
+        )
+        assertEquals(expectedRect.left, rectF.left)
+        assertEquals(expectedRect.top, rectF.top)
+        assertEquals(expectedRect.right, rectF.right)
+        assertEquals(expectedRect.bottom, rectF.bottom)
+    }
+
     @Test
     fun sendStateChangeEvent_whenClickToggleable() {
         val tag = "Toggleable"
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt
index 7aa4733..dbd0c19 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/DrawModifierTest.kt
@@ -19,11 +19,15 @@
 import android.os.Build
 import androidx.compose.foundation.background
 import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.size
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
+import androidx.compose.testutils.assertPixels
 import androidx.compose.ui.AtLeastSize
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Size
@@ -32,6 +36,7 @@
 import androidx.compose.ui.graphics.Path
 import androidx.compose.ui.graphics.asAndroidBitmap
 import androidx.compose.ui.graphics.drawscope.DrawScope
+import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.graphics.toArgb
 import androidx.compose.ui.platform.InspectableValue
 import androidx.compose.ui.platform.LocalLayoutDirection
@@ -43,6 +48,7 @@
 import androidx.compose.ui.test.onNodeWithTag
 import androidx.compose.ui.test.performClick
 import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
@@ -343,6 +349,63 @@
         }
     }
 
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+    @Test
+    fun testGraphicsLayerCacheInvalidatedAfterStateChange() {
+        // Verify that a state change within the cache block does
+        // require the cache block to be invalidated if a graphicsLayer is also
+        // configured on the composable and the state parameter is configured elsewhere
+        val boxTag = "boxTag"
+        val clickTag = "clickTag"
+
+        var cacheBuildCount = 0
+
+        rule.setContent {
+            val flag = remember { mutableStateOf(false) }
+            Column {
+                AtLeastSize(
+                    size = 50,
+                    modifier = Modifier.testTag(boxTag)
+                        .graphicsLayer()
+                        .drawWithCache {
+                            // State read of flag
+                            val color = if (flag.value) Color.Red else Color.Blue
+                            cacheBuildCount++
+
+                            onDrawBehind {
+                                drawRect(color)
+                            }
+                        }
+                )
+
+                Box(
+                    Modifier.testTag(clickTag)
+                        .size(20.dp)
+                        .clickable {
+                            flag.value = !flag.value
+                        }
+                )
+            }
+        }
+
+        rule.onNodeWithTag(boxTag).apply {
+            // Verify that the cache lambda was invoked once
+            assertEquals(1, cacheBuildCount)
+            captureToImage().assertPixels { Color.Blue }
+        }
+
+        rule.onNodeWithTag(clickTag).performClick()
+
+        rule.waitForIdle()
+
+        rule.onNodeWithTag(boxTag).apply {
+            // Verify the cache lambda was invoked again and the
+            // rect is drawn with the updated color
+            assertEquals(2, cacheBuildCount)
+            captureToImage().assertPixels { Color.Red }
+        }
+    }
+
     // Helper Modifier that uses Modifier.drawWithCache internally. If the color
     // parameter
     private fun Modifier.drawPathHelperModifier(color: Color) =
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/PainterModifierTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/PainterModifierTest.kt
index 841ca95..0f6d405 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/PainterModifierTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/draw/PainterModifierTest.kt
@@ -18,12 +18,16 @@
 
 import android.graphics.Bitmap
 import android.os.Build
+import androidx.compose.foundation.Image
 import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.requiredHeight
 import androidx.compose.foundation.layout.requiredHeightIn
 import androidx.compose.foundation.layout.requiredWidth
 import androidx.compose.foundation.layout.requiredWidthIn
 import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
 import androidx.compose.testutils.assertPixels
@@ -49,6 +53,7 @@
 import androidx.compose.ui.graphics.compositeOver
 import androidx.compose.ui.graphics.drawscope.DrawScope
 import androidx.compose.ui.graphics.painter.BitmapPainter
+import androidx.compose.ui.graphics.painter.ColorPainter
 import androidx.compose.ui.graphics.painter.Painter
 import androidx.compose.ui.graphics.toArgb
 import androidx.compose.ui.graphics.vector.Path
@@ -344,6 +349,23 @@
         }
     }
 
+    @Test
+    fun testUnboundedPainterDoesNotCrash() {
+        rule.setContent {
+            LazyColumn(Modifier.fillMaxSize().padding(16.dp)) {
+                item {
+                    // Lazy column has unbounded height so ensure that the constraints
+                    // provided to Painters without an intrinsic size are with a finite
+                    // range (i.e. don't crash)
+                    Image(
+                        painter = ColorPainter(Color.Black),
+                        contentDescription = ""
+                    )
+                }
+            }
+        }
+    }
+
     @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
     @Test
     fun testPainterNotSizedToIntrinsics() {
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt
index 479ceb7..3c13021 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/semantics/SemanticsTests.kt
@@ -143,6 +143,27 @@
     }
 
     @Test
+    fun nestedMergedSubtree_includeAllMergeableChildren() {
+        val tag1 = "tag1"
+        val tag2 = "tag2"
+        val label1 = "foo"
+        val label2 = "bar"
+        val label3 = "hi"
+        rule.setContent {
+            SimpleTestLayout(Modifier.semantics(mergeDescendants = true) {}.testTag(tag1)) {
+                SimpleTestLayout(Modifier.semantics { contentDescription = label1 }) { }
+                SimpleTestLayout(Modifier.semantics(mergeDescendants = true) {}.testTag(tag2)) {
+                    SimpleTestLayout(Modifier.semantics { contentDescription = label2 }) { }
+                }
+                SimpleTestLayout(Modifier.semantics { contentDescription = label3 }) { }
+            }
+        }
+
+        rule.onNodeWithTag(tag1).assertContentDescriptionEquals("$label1, $label3")
+        rule.onNodeWithTag(tag2).assertContentDescriptionEquals(label2)
+    }
+
+    @Test
     fun clearAndSetSemantics() {
         val tag1 = "tag1"
         val tag2 = "tag2"
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
index 91251f3..a7ebb9e 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
@@ -1093,7 +1093,7 @@
                 return
             }
             val textLayoutResults = mutableListOf<TextLayoutResult>()
-            // Note now it only works for single Text/TextField until we fix the merging issue.
+            // Note now it only works for single Text/TextField until we fix b/157474582.
             val getLayoutResult = node.config[SemanticsActions.GetTextLayoutResult]
                 .action?.invoke(textLayoutResults)
             val textLayoutResult: TextLayoutResult
@@ -1105,6 +1105,11 @@
             val boundingRects = mutableListOf<RectF?>()
             val textNode: SemanticsNode? = node.findNonEmptyTextChild()
             for (i in 0 until positionInfoLength) {
+                // This is a workaround until we fix the merging issue in b/157474582.
+                if (positionInfoStartIndex + i >= textLayoutResult.layoutInput.text.length) {
+                    boundingRects.add(null)
+                    continue
+                }
                 val bounds = textLayoutResult.getBoundingBox(positionInfoStartIndex + i)
                 val screenBounds: Rect?
                 // Only the visible/partial visible locations are used.
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GlobalSnapshotManager.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GlobalSnapshotManager.android.kt
index d49cd6d..3116d17 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GlobalSnapshotManager.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GlobalSnapshotManager.android.kt
@@ -17,10 +17,10 @@
 package androidx.compose.ui.platform
 
 import androidx.compose.runtime.snapshots.Snapshot
-import androidx.compose.runtime.snapshots.ObserverHandle
 import androidx.compose.ui.platform.GlobalSnapshotManager.ensureStarted
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.channels.consumeEach
 import kotlinx.coroutines.launch
 import java.util.concurrent.atomic.AtomicBoolean
 
@@ -37,56 +37,17 @@
  */
 internal object GlobalSnapshotManager {
     private val started = AtomicBoolean(false)
-    private var commitPending = false
-    private var removeWriteObserver: ObserverHandle? = null
-
-    private val scheduleScope = CoroutineScope(AndroidUiDispatcher.Main + SupervisorJob())
 
     fun ensureStarted() {
         if (started.compareAndSet(false, true)) {
-            removeWriteObserver = Snapshot.registerGlobalWriteObserver(globalWriteObserver)
-        }
-    }
-
-    private val globalWriteObserver: (Any) -> Unit = {
-        // Race, but we don't care too much if we end up with multiple calls scheduled.
-        if (!commitPending) {
-            commitPending = true
-            schedule {
-                commitPending = false
-                Snapshot.sendApplyNotifications()
+            val channel = Channel<Unit>(Channel.CONFLATED)
+            CoroutineScope(AndroidUiDispatcher.Main).launch {
+                channel.consumeEach {
+                    Snapshot.sendApplyNotifications()
+                }
             }
-        }
-    }
-
-    /**
-     * List of deferred callbacks to run serially. Guarded by its own monitor lock.
-     */
-    private val scheduledCallbacks = mutableListOf<() -> Unit>()
-
-    /**
-     * Guarded by [scheduledCallbacks]'s monitor lock.
-     */
-    private var isSynchronizeScheduled = false
-
-    /**
-     * Synchronously executes any outstanding callbacks and brings snapshots into a
-     * consistent, updated state.
-     */
-    private fun synchronize() {
-        synchronized(scheduledCallbacks) {
-            scheduledCallbacks.forEach { it.invoke() }
-            scheduledCallbacks.clear()
-            isSynchronizeScheduled = false
-        }
-    }
-
-    private fun schedule(block: () -> Unit) {
-        synchronized(scheduledCallbacks) {
-            scheduledCallbacks.add(block)
-            if (!isSynchronizeScheduled) {
-                isSynchronizeScheduled = true
-                scheduleScope.launch { synchronize() }
+            Snapshot.registerGlobalWriteObserver {
+                channel.offer(Unit)
             }
         }
     }
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/WindowRecomposer.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/WindowRecomposer.android.kt
index 5b381ff..e0d7619 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/WindowRecomposer.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/WindowRecomposer.android.kt
@@ -108,13 +108,15 @@
     )
 
     // Don't expose the actual AtomicReference as @PublishedApi; we might convert to atomicfu later
-    /** @suppress This should be internal @PublishedApi */
-    fun getAndSetFactory(
+    @Suppress("ShowingMemberInHiddenClass")
+    @PublishedApi
+    internal fun getAndSetFactory(
         factory: WindowRecomposerFactory
     ): WindowRecomposerFactory = this.factory.getAndSet(factory)
 
-    /** @suppress This should be internal @PublishedApi */
-    fun compareAndSetFactory(
+    @Suppress("ShowingMemberInHiddenClass")
+    @PublishedApi
+    internal fun compareAndSetFactory(
         expected: WindowRecomposerFactory,
         factory: WindowRecomposerFactory
     ): Boolean = this.factory.compareAndSet(expected, factory)
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/draw/PainterModifier.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/draw/PainterModifier.kt
index 57d134e..f76a069 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/draw/PainterModifier.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/draw/PainterModifier.kt
@@ -199,7 +199,9 @@
     }
 
     private fun modifyConstraints(constraints: Constraints): Constraints {
-        if (!useIntrinsicSize || (constraints.hasFixedWidth && constraints.hasFixedHeight)) {
+        val hasBoundedDimens = constraints.hasBoundedWidth && constraints.hasBoundedHeight
+        val hasFixedDimens = constraints.hasFixedWidth && constraints.hasFixedHeight
+        if ((!useIntrinsicSize && hasBoundedDimens) || hasFixedDimens) {
             // If we have fixed constraints or we are not attempting to size the
             // composable based on the size of the Painter, do not attempt to
             // modify them. Otherwise rely on Alignment and ContentScale
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
index 4710bd0..ea36814 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/LayoutNode.kt
@@ -474,6 +474,7 @@
             if (field != value) {
                 field = value
                 requestRemeasure()
+                invalidateLayer()
             }
         }
 
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ModifiedDrawNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ModifiedDrawNode.kt
index 3f58143..28a685a 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ModifiedDrawNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/ModifiedDrawNode.kt
@@ -119,10 +119,8 @@
         private val onCommitAffectingModifiedDrawNode: (ModifiedDrawNode) -> Unit =
             { modifiedDrawNode ->
                 if (modifiedDrawNode.isValid) {
-                    // Note this intentionally does not invalidate the layer as Owner implementations
-                    // already observe and invalidate the layer on state changes. Instead just
-                    // mark the cache dirty so that it will be re-created on the next draw
                     modifiedDrawNode.invalidateCache = true
+                    modifiedDrawNode.invalidateLayer()
                 }
             }
     }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/InspectableValue.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/InspectableValue.kt
index d89fb63..87c1ac4 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/InspectableValue.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/InspectableValue.kt
@@ -104,7 +104,7 @@
 
     private val values: InspectorInfo
         get() {
-            val valueInfo = _values ?: InspectorInfo().apply { info() }
+            val valueInfo = _values ?: InspectorInfo().apply(info)
             _values = valueInfo
             return valueInfo
         }
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt
index e4836c2..ffac306 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/semantics/SemanticsNode.kt
@@ -163,12 +163,10 @@
             unmergedChildren().fastForEach { child ->
                 // Don't merge children that themselves merge all their descendants (because that
                 // indicates they're independently screen-reader-focusable).
-                if (child.isMergingSemanticsOfDescendants) {
-                    return
+                if (!child.isMergingSemanticsOfDescendants) {
+                    mergedConfig.mergeChild(child.unmergedConfig)
+                    child.mergeConfig(mergedConfig)
                 }
-
-                mergedConfig.mergeChild(child.unmergedConfig)
-                child.mergeConfig(mergedConfig)
             }
         }
     }
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeLayer.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeLayer.desktop.kt
index 130a434..6f3e90e 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeLayer.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/desktop/ComposeLayer.desktop.kt
@@ -188,6 +188,7 @@
                 )
             }
         }
+        wrapped.focusTraversalKeysEnabled = false
         wrapped.addKeyListener(object : KeyAdapter() {
             override fun keyPressed(event: KeyEvent) = events.post {
                 owners.onKeyPressed(event)
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/input/key/Key.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/input/key/Key.desktop.kt
index 7df1276..6693080 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/input/key/Key.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/input/key/Key.desktop.kt
@@ -52,28 +52,28 @@
          *
          * May also be synthesized from trackball motions.
          */
-        actual val DirectionUp = Key(KeyEvent.VK_KP_UP)
+        actual val DirectionUp = Key(KeyEvent.VK_UP)
 
         /**
          * Down Arrow Key / Directional Pad Down key.
          *
          * May also be synthesized from trackball motions.
          */
-        actual val DirectionDown = Key(KeyEvent.VK_KP_DOWN)
+        actual val DirectionDown = Key(KeyEvent.VK_DOWN)
 
         /**
          * Left Arrow Key / Directional Pad Left key.
          *
          * May also be synthesized from trackball motions.
          */
-        actual val DirectionLeft = Key(KeyEvent.VK_KP_LEFT)
+        actual val DirectionLeft = Key(KeyEvent.VK_LEFT)
 
         /**
          * Right Arrow Key / Directional Pad Right key.
          *
          * May also be synthesized from trackball motions.
          */
-        actual val DirectionRight = Key(KeyEvent.VK_KP_RIGHT)
+        actual val DirectionRight = Key(KeyEvent.VK_RIGHT)
 
         /** '0' key. */
         actual val Zero = Key(KeyEvent.VK_0)
@@ -307,7 +307,7 @@
         actual val PageUp = Key(KeyEvent.VK_PAGE_UP)
 
         /** Page Down key. */
-        actual val PageDown = Key(KeyEvent.VK_PAGE_UP)
+        actual val PageDown = Key(KeyEvent.VK_PAGE_DOWN)
 
         /** F1 key. */
         actual val F1 = Key(KeyEvent.VK_F1)
@@ -413,6 +413,9 @@
         /** Numeric keypad ')' key. */
         actual val NumPadRightParenthesis = Key(KeyEvent.VK_RIGHT_PARENTHESIS, KEY_LOCATION_NUMPAD)
 
+        actual val MoveHome = Key(KeyEvent.VK_HOME)
+        actual val MoveEnd = Key(KeyEvent.VK_END)
+
         // Unsupported Keys. These keys will never be sent by the desktop. However we need unique
         // keycodes so that these constants can be used in a when statement without a warning.
         actual val SoftLeft = Key(-1000000001)
@@ -443,8 +446,6 @@
         actual val Envelope = Key(-1000000026)
         actual val Function = Key(-1000000027)
         actual val Break = Key(-1000000028)
-        actual val MoveHome = Key(-1000000029)
-        actual val MoveEnd = Key(-1000000030)
         actual val Number = Key(-1000000031)
         actual val HeadsetHook = Key(-1000000032)
         actual val Focus = Key(-1000000033)
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.desktop.kt
index 934230e..b496be2 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwner.desktop.kt
@@ -19,6 +19,7 @@
 package androidx.compose.ui.platform
 
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.key
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.ExperimentalComposeUiApi
@@ -170,6 +171,13 @@
         get() = container.keyboard
 
     override fun sendKeyEvent(keyEvent: KeyEvent): Boolean {
+        when {
+            keyEvent.nativeKeyEvent.id == java.awt.event.KeyEvent.KEY_TYPED ->
+                container.platformInputService.charKeyPressed = true
+            keyEvent.type == KeyEventType.KeyDown ->
+                container.platformInputService.charKeyPressed = false
+        }
+
         return keyInputModifier.processKeyInput(keyEvent) ||
             keyboard?.processKeyInput(keyEvent) ?: false
     }
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwners.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwners.desktop.kt
index bbb543a..2ab89f4 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwners.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopOwners.desktop.kt
@@ -153,24 +153,15 @@
         lastOwner?.onPointerMove(position)
     }
 
-    private fun consumeKeyEventOr(event: KeyEvent, or: () -> Unit) {
-        val consumed = list.lastOrNull()?.sendKeyEvent(ComposeKeyEvent(event)) ?: false
-        if (!consumed) {
-            or()
-        }
+    private fun consumeKeyEvent(event: KeyEvent) {
+        list.lastOrNull()?.sendKeyEvent(ComposeKeyEvent(event))
     }
 
-    fun onKeyPressed(event: KeyEvent) = consumeKeyEventOr(event) {
-        platformInputService.onKeyPressed(event.keyCode, event.keyChar)
-    }
+    fun onKeyPressed(event: KeyEvent) = consumeKeyEvent(event)
 
-    fun onKeyReleased(event: KeyEvent) = consumeKeyEventOr(event) {
-        platformInputService.onKeyReleased(event.keyCode, event.keyChar)
-    }
+    fun onKeyReleased(event: KeyEvent) = consumeKeyEvent(event)
 
-    fun onKeyTyped(event: KeyEvent) = consumeKeyEventOr(event) {
-        platformInputService.onKeyTyped(event.keyChar)
-    }
+    fun onKeyTyped(event: KeyEvent) = consumeKeyEvent(event)
 
     fun onInputMethodEvent(event: InputMethodEvent) {
         if (!event.isConsumed()) {
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopPlatformInput.desktop.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopPlatformInput.desktop.kt
index e057d3a..9cc2205 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopPlatformInput.desktop.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/DesktopPlatformInput.desktop.kt
@@ -16,13 +16,11 @@
 package androidx.compose.ui.platform
 
 import androidx.compose.ui.geometry.Rect
-import androidx.compose.ui.text.input.BackspaceCommand
 import androidx.compose.ui.text.input.CommitTextCommand
 import androidx.compose.ui.text.input.DeleteSurroundingTextInCodePointsCommand
 import androidx.compose.ui.text.input.EditCommand
 import androidx.compose.ui.text.input.ImeAction
 import androidx.compose.ui.text.input.ImeOptions
-import androidx.compose.ui.text.input.MoveCursorCommand
 import androidx.compose.ui.text.input.PlatformTextInputService
 import androidx.compose.ui.text.input.SetComposingTextCommand
 import androidx.compose.ui.text.input.TextFieldValue
@@ -31,7 +29,6 @@
 import java.awt.Point
 import java.awt.Rectangle
 import java.awt.event.InputMethodEvent
-import java.awt.event.KeyEvent
 import java.awt.font.TextHitInfo
 import java.awt.im.InputMethodRequests
 import java.text.AttributedCharacterIterator
@@ -61,6 +58,10 @@
 
     var currentInput: CurrentInput? = null
 
+    // This is required to support input of accented characters using press-and-hold method (http://support.apple.com/kb/PH11264).
+    // JDK currently properly supports this functionality only for TextComponent/JTextComponent descendants.
+    // For our editor component we need this workaround.
+    // After https://bugs.openjdk.java.net/browse/JDK-8074882 is fixed, this workaround should be replaced with a proper solution.
     var charKeyPressed: Boolean = false
     var needToDeletePreviousChar: Boolean = false
 
@@ -103,57 +104,6 @@
         }
     }
 
-    @Suppress("UNUSED_PARAMETER")
-    fun onKeyPressed(keyCode: Int, char: Char) {
-        if (keyCode >= KeyEvent.VK_A && keyCode <= KeyEvent.VK_Z) {
-            charKeyPressed = true
-        }
-        currentInput?.let { input ->
-            val command = input.onEditCommand
-            when (keyCode) {
-                KeyEvent.VK_LEFT -> {
-                    command.invoke(listOf(MoveCursorCommand(-1)))
-                }
-                KeyEvent.VK_RIGHT -> {
-                    command.invoke(listOf(MoveCursorCommand(1)))
-                }
-                KeyEvent.VK_BACK_SPACE -> {
-                    command.invoke(listOf(BackspaceCommand()))
-                }
-                KeyEvent.VK_ENTER -> {
-                    if (input.imeAction == ImeAction.Default) {
-                        command.invoke(listOf(CommitTextCommand("\n", 1)))
-                    } else {
-                        input.onImeActionPerformed.invoke(input.imeAction)
-                    }
-                }
-                else -> Unit
-            }
-        }
-    }
-
-    @Suppress("UNUSED_PARAMETER")
-    fun onKeyReleased(keyCode: Int, char: Char) {
-        charKeyPressed = false
-    }
-
-    private fun Char.isPrintable(): Boolean {
-        val block = Character.UnicodeBlock.of(this)
-        return (!Character.isISOControl(this)) &&
-            this != KeyEvent.CHAR_UNDEFINED &&
-            block != null &&
-            block != Character.UnicodeBlock.SPECIALS
-    }
-
-    fun onKeyTyped(char: Char) {
-        needToDeletePreviousChar = false
-        currentInput?.onEditCommand?.let {
-            if (char.isPrintable()) {
-                it.invoke(listOf(CommitTextCommand(char.toString(), 1)))
-            }
-        }
-    }
-
     internal fun inputMethodCaretPositionChanged(
         @Suppress("UNUSED_PARAMETER") event: InputMethodEvent
     ) {
@@ -172,10 +122,6 @@
             val ops = mutableListOf<EditCommand>()
 
             if (needToDeletePreviousChar && isMac) {
-                // This is required to support input of accented characters using press-and-hold method (http://support.apple.com/kb/PH11264).
-                // JDK currently properly supports this functionality only for TextComponent/JTextComponent descendants.
-                // For our editor component we need this workaround.
-                // After https://bugs.openjdk.java.net/browse/JDK-8074882 is fixed, this workaround should be replaced with a proper solution.
                 needToDeletePreviousChar = false
                 ops.add(DeleteSurroundingTextInCodePointsCommand(1, 0))
             }
@@ -230,9 +176,7 @@
             override fun getSelectedText(
                 attributes: Array<AttributedCharacterIterator.Attribute>?
             ): AttributedCharacterIterator {
-                if (charKeyPressed) {
-                    needToDeletePreviousChar = true
-                }
+                needToDeletePreviousChar = charKeyPressed
                 val str = input.value.text.substring(input.value.selection)
                 return AttributedString(str).iterator
             }
diff --git a/core/core-ktx/api/1.5.0-beta03.txt b/core/core-ktx/api/1.5.0-beta03.txt
new file mode 100644
index 0000000..ea0fa5f
--- /dev/null
+++ b/core/core-ktx/api/1.5.0-beta03.txt
@@ -0,0 +1,606 @@
+// Signature format: 4.0
+package androidx.core.animation {
+
+  public final class AnimatorKt {
+    method public static inline android.animation.Animator.AnimatorListener addListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onRepeat);
+    method @RequiresApi(19) public static inline android.animation.Animator.AnimatorPauseListener addPauseListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onPause);
+    method public static inline android.animation.Animator.AnimatorListener doOnCancel(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static inline android.animation.Animator.AnimatorListener doOnEnd(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.animation.Animator.AnimatorPauseListener doOnPause(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static inline android.animation.Animator.AnimatorListener doOnRepeat(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.animation.Animator.AnimatorPauseListener doOnResume(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static inline 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 {
+    method public static android.content.ContentValues contentValuesOf(kotlin.Pair<java.lang.String,?>... pairs);
+  }
+
+  public final class ContextKt {
+    method public static inline <reified T> T! getSystemService(android.content.Context);
+    method public static inline void withStyledAttributes(android.content.Context, optional android.util.AttributeSet? set, int[] attrs, optional @AttrRes int defStyleAttr, optional @StyleRes int defStyleRes, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+    method public static inline 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 {
+    method public static inline void edit(android.content.SharedPreferences, optional boolean commit, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action);
+  }
+
+}
+
+package androidx.core.content.res {
+
+  public final class 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 inline <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 {
+    method public static inline byte[]? getBlobOrNull(android.database.Cursor, int index);
+    method public static inline Double? getDoubleOrNull(android.database.Cursor, int index);
+    method public static inline Float? getFloatOrNull(android.database.Cursor, int index);
+    method public static inline Integer? getIntOrNull(android.database.Cursor, int index);
+    method public static inline Long? getLongOrNull(android.database.Cursor, int index);
+    method public static inline Short? getShortOrNull(android.database.Cursor, int index);
+    method public static inline String? getStringOrNull(android.database.Cursor, int index);
+  }
+
+}
+
+package androidx.core.database.sqlite {
+
+  public final class SQLiteDatabaseKt {
+    method public static inline <T> T! transaction(android.database.sqlite.SQLiteDatabase, optional boolean exclusive, kotlin.jvm.functions.Function1<? super android.database.sqlite.SQLiteDatabase,? extends T> body);
+  }
+
+}
+
+package androidx.core.graphics {
+
+  public final class BitmapKt {
+    method public static inline android.graphics.Bitmap applyCanvas(android.graphics.Bitmap, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.Point p);
+    method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.PointF p);
+    method public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config);
+    method @RequiresApi(26) public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config, optional boolean hasAlpha, optional android.graphics.ColorSpace colorSpace);
+    method public static inline operator int get(android.graphics.Bitmap, int x, int y);
+    method public static inline android.graphics.Bitmap scale(android.graphics.Bitmap, int width, int height, optional boolean filter);
+    method public static inline operator void set(android.graphics.Bitmap, int x, int y, @ColorInt int color);
+  }
+
+  public final class CanvasKt {
+    method public static inline void withClip(android.graphics.Canvas, android.graphics.Rect clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withClip(android.graphics.Canvas, android.graphics.RectF clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withClip(android.graphics.Canvas, int left, int top, int right, int bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withClip(android.graphics.Canvas, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withClip(android.graphics.Canvas, android.graphics.Path clipPath, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withMatrix(android.graphics.Canvas, optional android.graphics.Matrix matrix, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withRotation(android.graphics.Canvas, optional float degrees, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withSave(android.graphics.Canvas, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withScale(android.graphics.Canvas, optional float x, optional float y, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withSkew(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withTranslation(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+  }
+
+  public final class ColorKt {
+    method @RequiresApi(26) public static inline operator float component1(android.graphics.Color);
+    method public static inline operator int component1(@ColorInt int);
+    method @RequiresApi(26) public static inline operator float component1(@ColorLong long);
+    method @RequiresApi(26) public static inline operator float component2(android.graphics.Color);
+    method public static inline operator int component2(@ColorInt int);
+    method @RequiresApi(26) public static inline operator float component2(@ColorLong long);
+    method @RequiresApi(26) public static inline operator float component3(android.graphics.Color);
+    method public static inline operator int component3(@ColorInt int);
+    method @RequiresApi(26) public static inline operator float component3(@ColorLong long);
+    method @RequiresApi(26) public static inline operator float component4(android.graphics.Color);
+    method public static inline operator int component4(@ColorInt int);
+    method @RequiresApi(26) public static inline operator float component4(@ColorLong long);
+    method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace.Named colorSpace);
+    method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace colorSpace);
+    method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace.Named colorSpace);
+    method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace colorSpace);
+    method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace.Named colorSpace);
+    method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace colorSpace);
+    method public static inline int getAlpha(int);
+    method @RequiresApi(26) public static inline float getAlpha(long);
+    method public static inline int getBlue(int);
+    method @RequiresApi(26) public static inline float getBlue(long);
+    method @RequiresApi(26) public static inline android.graphics.ColorSpace getColorSpace(long);
+    method public static inline int getGreen(int);
+    method @RequiresApi(26) public static inline float getGreen(long);
+    method @RequiresApi(26) public static inline float getLuminance(int);
+    method @RequiresApi(26) public static inline float getLuminance(long);
+    method public static inline int getRed(int);
+    method @RequiresApi(26) public static inline float getRed(long);
+    method @RequiresApi(26) public static inline boolean isSrgb(long);
+    method @RequiresApi(26) public static inline 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 inline android.graphics.Color toColor(@ColorInt int);
+    method @RequiresApi(26) public static inline android.graphics.Color toColor(@ColorLong long);
+    method @ColorInt @RequiresApi(26) public static inline int toColorInt(@ColorLong long);
+    method @ColorInt public static inline int toColorInt(String);
+    method @ColorLong @RequiresApi(26) public static inline long toColorLong(@ColorInt int);
+  }
+
+  public final class ImageDecoderKt {
+    method @RequiresApi(28) public static inline android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+    method @RequiresApi(28) public static inline android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+  }
+
+  public final class MatrixKt {
+    method public static android.graphics.Matrix rotationMatrix(float degrees, optional float px, optional float py);
+    method public static android.graphics.Matrix scaleMatrix(optional float sx, optional float sy);
+    method public static inline operator android.graphics.Matrix times(android.graphics.Matrix, android.graphics.Matrix m);
+    method public static android.graphics.Matrix translationMatrix(optional float tx, optional float ty);
+    method public static inline float[] values(android.graphics.Matrix);
+  }
+
+  public final class PaintKt {
+    method public static inline boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat? blendModeCompat);
+  }
+
+  public final class PathKt {
+    method @RequiresApi(19) public static inline 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, optional float error);
+    method @RequiresApi(19) public static inline operator android.graphics.Path minus(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static inline infix android.graphics.Path or(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static inline operator android.graphics.Path plus(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static inline infix android.graphics.Path xor(android.graphics.Path, android.graphics.Path p);
+  }
+
+  public final class PictureKt {
+    method public static inline 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 {
+    method public static inline operator int component1(android.graphics.Point);
+    method public static inline operator float component1(android.graphics.PointF);
+    method public static inline operator int component2(android.graphics.Point);
+    method public static inline operator float component2(android.graphics.PointF);
+    method public static inline operator android.graphics.Point minus(android.graphics.Point, android.graphics.Point p);
+    method public static inline operator android.graphics.PointF minus(android.graphics.PointF, android.graphics.PointF p);
+    method public static inline operator android.graphics.Point minus(android.graphics.Point, int xy);
+    method public static inline operator android.graphics.PointF minus(android.graphics.PointF, float xy);
+    method public static inline operator android.graphics.Point plus(android.graphics.Point, android.graphics.Point p);
+    method public static inline operator android.graphics.PointF plus(android.graphics.PointF, android.graphics.PointF p);
+    method public static inline operator android.graphics.Point plus(android.graphics.Point, int xy);
+    method public static inline operator android.graphics.PointF plus(android.graphics.PointF, float xy);
+    method public static inline android.graphics.Point toPoint(android.graphics.PointF);
+    method public static inline android.graphics.PointF toPointF(android.graphics.Point);
+    method public static inline operator android.graphics.Point unaryMinus(android.graphics.Point);
+    method public static inline operator android.graphics.PointF unaryMinus(android.graphics.PointF);
+  }
+
+  public final class PorterDuffKt {
+    method public static inline android.graphics.PorterDuffColorFilter toColorFilter(android.graphics.PorterDuff.Mode, int color);
+    method public static inline android.graphics.PorterDuffXfermode toXfermode(android.graphics.PorterDuff.Mode);
+  }
+
+  public final class RectKt {
+    method public static inline infix android.graphics.Rect and(android.graphics.Rect, android.graphics.Rect r);
+    method public static inline infix android.graphics.RectF and(android.graphics.RectF, android.graphics.RectF r);
+    method public static inline operator int component1(android.graphics.Rect);
+    method public static inline operator float component1(android.graphics.RectF);
+    method public static inline operator int component2(android.graphics.Rect);
+    method public static inline operator float component2(android.graphics.RectF);
+    method public static inline operator int component3(android.graphics.Rect);
+    method public static inline operator float component3(android.graphics.RectF);
+    method public static inline operator int component4(android.graphics.Rect);
+    method public static inline operator float component4(android.graphics.RectF);
+    method public static inline operator boolean contains(android.graphics.Rect, android.graphics.Point p);
+    method public static inline operator boolean contains(android.graphics.RectF, android.graphics.PointF p);
+    method public static inline operator android.graphics.Region minus(android.graphics.Rect, android.graphics.Rect r);
+    method public static inline operator android.graphics.Region minus(android.graphics.RectF, android.graphics.RectF r);
+    method public static inline operator android.graphics.Rect minus(android.graphics.Rect, int xy);
+    method public static inline operator android.graphics.RectF minus(android.graphics.RectF, float xy);
+    method public static inline operator android.graphics.Rect minus(android.graphics.Rect, android.graphics.Point xy);
+    method public static inline operator android.graphics.RectF minus(android.graphics.RectF, android.graphics.PointF xy);
+    method public static inline infix android.graphics.Rect or(android.graphics.Rect, android.graphics.Rect r);
+    method public static inline infix android.graphics.RectF or(android.graphics.RectF, android.graphics.RectF r);
+    method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Rect r);
+    method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.RectF r);
+    method public static inline operator android.graphics.Rect plus(android.graphics.Rect, int xy);
+    method public static inline operator android.graphics.RectF plus(android.graphics.RectF, float xy);
+    method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Point xy);
+    method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.PointF xy);
+    method public static inline operator android.graphics.Rect times(android.graphics.Rect, int factor);
+    method public static inline operator android.graphics.RectF times(android.graphics.RectF, int factor);
+    method public static inline operator android.graphics.RectF times(android.graphics.RectF, float factor);
+    method public static inline android.graphics.Rect toRect(android.graphics.RectF);
+    method public static inline android.graphics.RectF toRectF(android.graphics.Rect);
+    method public static inline android.graphics.Region toRegion(android.graphics.Rect);
+    method public static inline android.graphics.Region toRegion(android.graphics.RectF);
+    method public static inline android.graphics.RectF transform(android.graphics.RectF, android.graphics.Matrix m);
+    method public static inline infix android.graphics.Region xor(android.graphics.Rect, android.graphics.Rect r);
+    method public static inline infix android.graphics.Region xor(android.graphics.RectF, android.graphics.RectF r);
+  }
+
+  public final class RegionKt {
+    method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Rect r);
+    method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Region r);
+    method public static inline operator boolean contains(android.graphics.Region, android.graphics.Point p);
+    method public static inline 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 inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Rect r);
+    method public static inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Region r);
+    method public static inline operator android.graphics.Region not(android.graphics.Region);
+    method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Rect r);
+    method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Region r);
+    method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Rect r);
+    method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Region r);
+    method public static inline operator android.graphics.Region unaryMinus(android.graphics.Region);
+    method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Rect r);
+    method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Region r);
+  }
+
+  public final class ShaderKt {
+    method public static inline 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 {
+    method public static inline android.graphics.drawable.BitmapDrawable toDrawable(android.graphics.Bitmap, android.content.res.Resources resources);
+  }
+
+  public final class ColorDrawableKt {
+    method public static inline android.graphics.drawable.ColorDrawable toDrawable(@ColorInt int);
+    method @RequiresApi(26) public static inline android.graphics.drawable.ColorDrawable toDrawable(android.graphics.Color);
+  }
+
+  public final class DrawableKt {
+    method public static android.graphics.Bitmap toBitmap(android.graphics.drawable.Drawable, optional @Px int width, optional @Px int height, optional android.graphics.Bitmap.Config? config);
+    method public static void updateBounds(android.graphics.drawable.Drawable, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+  }
+
+  public final class IconKt {
+    method @RequiresApi(26) public static inline android.graphics.drawable.Icon toAdaptiveIcon(android.graphics.Bitmap);
+    method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.graphics.Bitmap);
+    method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.net.Uri);
+    method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(byte[]);
+  }
+
+}
+
+package androidx.core.location {
+
+  public final class LocationKt {
+    method public static inline operator double component1(android.location.Location);
+    method public static inline operator double component2(android.location.Location);
+  }
+
+}
+
+package androidx.core.net {
+
+  public final class UriKt {
+    method public static java.io.File toFile(android.net.Uri);
+    method public static inline android.net.Uri toUri(String);
+    method public static inline android.net.Uri toUri(java.io.File);
+  }
+
+}
+
+package androidx.core.os {
+
+  public final class BundleKt {
+    method public static android.os.Bundle bundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+  }
+
+  public final class HandlerKt {
+    method public static inline Runnable postAtTime(android.os.Handler, long uptimeMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method public static inline Runnable postDelayed(android.os.Handler, long delayInMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+  }
+
+  public final class PersistableBundleKt {
+    method @RequiresApi(21) public static android.os.PersistableBundle persistableBundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+  }
+
+  public final class TraceKt {
+    method @Deprecated public static inline <T> T! trace(String sectionName, kotlin.jvm.functions.Function0<? extends T> block);
+  }
+
+}
+
+package androidx.core.text {
+
+  public final class CharSequenceKt {
+    method public static inline boolean isDigitsOnly(CharSequence);
+    method public static inline int trimmedLength(CharSequence);
+  }
+
+  public final class HtmlKt {
+    method public static inline android.text.Spanned parseAsHtml(String, optional int flags, optional android.text.Html.ImageGetter? imageGetter, optional android.text.Html.TagHandler? tagHandler);
+    method public static inline String toHtml(android.text.Spanned, optional int option);
+  }
+
+  public final class LocaleKt {
+    method @RequiresApi(17) public static inline int getLayoutDirection(java.util.Locale);
+  }
+
+  public final class SpannableStringBuilderKt {
+    method public static inline android.text.SpannableStringBuilder backgroundColor(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder bold(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannedString buildSpannedString(kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder color(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object![] spans, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object span, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder italic(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder scale(android.text.SpannableStringBuilder, float proportion, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder strikeThrough(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder subscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder superscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder underline(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+  }
+
+  public final class SpannableStringKt {
+    method public static inline void clearSpans(android.text.Spannable);
+    method public static inline operator void set(android.text.Spannable, int start, int end, Object span);
+    method public static inline operator void set(android.text.Spannable, kotlin.ranges.IntRange range, Object span);
+    method public static inline android.text.Spannable toSpannable(CharSequence);
+  }
+
+  public final class SpannedStringKt {
+    method public static inline <reified T> T![]! getSpans(android.text.Spanned, optional int start, optional int end);
+    method public static inline android.text.Spanned toSpanned(CharSequence);
+  }
+
+  public final class StringKt {
+    method public static inline String htmlEncode(String);
+  }
+
+}
+
+package androidx.core.transition {
+
+  public final class TransitionKt {
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener addListener(android.transition.Transition, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onPause);
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnCancel(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnEnd(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnPause(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnResume(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnStart(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+  }
+
+}
+
+package androidx.core.util {
+
+  public final class AtomicFileKt {
+    method @RequiresApi(17) public static inline byte[] readBytes(android.util.AtomicFile);
+    method @RequiresApi(17) public static String readText(android.util.AtomicFile, optional java.nio.charset.Charset charset);
+    method @RequiresApi(17) public static inline 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, optional java.nio.charset.Charset charset);
+  }
+
+  public final class HalfKt {
+    method @RequiresApi(26) public static inline android.util.Half toHalf(@HalfFloat short);
+    method @RequiresApi(26) public static inline android.util.Half toHalf(float);
+    method @RequiresApi(26) public static inline android.util.Half toHalf(double);
+    method @RequiresApi(26) public static inline android.util.Half toHalf(String);
+  }
+
+  public final class LongSparseArrayKt {
+    method @RequiresApi(16) public static inline operator <T> boolean contains(android.util.LongSparseArray<T>, long key);
+    method @RequiresApi(16) public static inline <T> boolean containsKey(android.util.LongSparseArray<T>, long key);
+    method @RequiresApi(16) public static inline <T> boolean containsValue(android.util.LongSparseArray<T>, T? value);
+    method @RequiresApi(16) public static inline <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 inline <T> T! getOrDefault(android.util.LongSparseArray<T>, long key, T? defaultValue);
+    method @RequiresApi(16) public static inline <T> T! getOrElse(android.util.LongSparseArray<T>, long key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+    method @RequiresApi(16) public static inline <T> int getSize(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static inline <T> boolean isEmpty(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static inline <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 inline 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 {
+    method public static inline <K, V> android.util.LruCache<K,V> lruCache(int maxSize, optional kotlin.jvm.functions.Function2<? super K,? super V,java.lang.Integer> sizeOf, optional kotlin.jvm.functions.Function1<? super K,? extends V> create, optional kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved);
+  }
+
+  public final class PairKt {
+    method public static inline operator <F, S> F! component1(androidx.core.util.Pair<F,S>);
+    method public static inline operator <F, S> F! component1(android.util.Pair<F,S>);
+    method public static inline operator <F, S> S! component2(androidx.core.util.Pair<F,S>);
+    method public static inline operator <F, S> S! component2(android.util.Pair<F,S>);
+    method public static inline <F, S> android.util.Pair<F,S> toAndroidPair(kotlin.Pair<? extends F,? extends S>);
+    method public static inline <F, S> androidx.core.util.Pair<F,S> toAndroidXPair(kotlin.Pair<? extends F,? extends S>);
+    method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(androidx.core.util.Pair<F,S>);
+    method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(android.util.Pair<F,S>);
+  }
+
+  public final class RangeKt {
+    method @RequiresApi(21) public static inline 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 inline operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, T value);
+    method @RequiresApi(21) public static inline 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 inline 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 {
+    method @RequiresApi(21) public static inline operator int component1(android.util.Size);
+    method @RequiresApi(21) public static inline operator float component1(android.util.SizeF);
+    method @RequiresApi(21) public static inline operator int component2(android.util.Size);
+    method @RequiresApi(21) public static inline operator float component2(android.util.SizeF);
+  }
+
+  public final class SparseArrayKt {
+    method public static inline operator <T> boolean contains(android.util.SparseArray<T>, int key);
+    method public static inline <T> boolean containsKey(android.util.SparseArray<T>, int key);
+    method public static inline <T> boolean containsValue(android.util.SparseArray<T>, T? value);
+    method public static inline <T> void forEach(android.util.SparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,kotlin.Unit> action);
+    method public static inline <T> T! getOrDefault(android.util.SparseArray<T>, int key, T? defaultValue);
+    method public static inline <T> T! getOrElse(android.util.SparseArray<T>, int key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+    method public static inline <T> int getSize(android.util.SparseArray<T>);
+    method public static inline <T> boolean isEmpty(android.util.SparseArray<T>);
+    method public static inline <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 inline 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 {
+    method public static inline operator boolean contains(android.util.SparseBooleanArray, int key);
+    method public static inline boolean containsKey(android.util.SparseBooleanArray, int key);
+    method public static inline boolean containsValue(android.util.SparseBooleanArray, boolean value);
+    method public static inline void forEach(android.util.SparseBooleanArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Boolean,kotlin.Unit> action);
+    method public static inline boolean getOrDefault(android.util.SparseBooleanArray, int key, boolean defaultValue);
+    method public static inline boolean getOrElse(android.util.SparseBooleanArray, int key, kotlin.jvm.functions.Function0<java.lang.Boolean> defaultValue);
+    method public static inline int getSize(android.util.SparseBooleanArray);
+    method public static inline boolean isEmpty(android.util.SparseBooleanArray);
+    method public static inline 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 inline operator void set(android.util.SparseBooleanArray, int key, boolean value);
+    method public static kotlin.collections.BooleanIterator valueIterator(android.util.SparseBooleanArray);
+  }
+
+  public final class SparseIntArrayKt {
+    method public static inline operator boolean contains(android.util.SparseIntArray, int key);
+    method public static inline boolean containsKey(android.util.SparseIntArray, int key);
+    method public static inline boolean containsValue(android.util.SparseIntArray, int value);
+    method public static inline void forEach(android.util.SparseIntArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+    method public static inline int getOrDefault(android.util.SparseIntArray, int key, int defaultValue);
+    method public static inline int getOrElse(android.util.SparseIntArray, int key, kotlin.jvm.functions.Function0<java.lang.Integer> defaultValue);
+    method public static inline int getSize(android.util.SparseIntArray);
+    method public static inline boolean isEmpty(android.util.SparseIntArray);
+    method public static inline 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 inline operator void set(android.util.SparseIntArray, int key, int value);
+    method public static kotlin.collections.IntIterator valueIterator(android.util.SparseIntArray);
+  }
+
+  public final class SparseLongArrayKt {
+    method @RequiresApi(18) public static inline operator boolean contains(android.util.SparseLongArray, int key);
+    method @RequiresApi(18) public static inline boolean containsKey(android.util.SparseLongArray, int key);
+    method @RequiresApi(18) public static inline boolean containsValue(android.util.SparseLongArray, long value);
+    method @RequiresApi(18) public static inline 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 inline long getOrDefault(android.util.SparseLongArray, int key, long defaultValue);
+    method @RequiresApi(18) public static inline long getOrElse(android.util.SparseLongArray, int key, kotlin.jvm.functions.Function0<java.lang.Long> defaultValue);
+    method @RequiresApi(18) public static inline int getSize(android.util.SparseLongArray);
+    method @RequiresApi(18) public static inline boolean isEmpty(android.util.SparseLongArray);
+    method @RequiresApi(18) public static inline 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 inline 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 {
+    method public static operator boolean contains(android.view.Menu, android.view.MenuItem item);
+    method public static inline void forEach(android.view.Menu, kotlin.jvm.functions.Function1<? super android.view.MenuItem,kotlin.Unit> action);
+    method public static inline void forEachIndexed(android.view.Menu, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.view.MenuItem,kotlin.Unit> action);
+    method public static inline operator android.view.MenuItem get(android.view.Menu, int index);
+    method public static kotlin.sequences.Sequence<android.view.MenuItem> getChildren(android.view.Menu);
+    method public static inline int getSize(android.view.Menu);
+    method public static inline boolean isEmpty(android.view.Menu);
+    method public static inline boolean isNotEmpty(android.view.Menu);
+    method public static operator java.util.Iterator<android.view.MenuItem> iterator(android.view.Menu);
+    method public static inline operator void minusAssign(android.view.Menu, android.view.MenuItem item);
+  }
+
+  public final class ViewGroupKt {
+    method public static inline operator boolean contains(android.view.ViewGroup, android.view.View view);
+    method public static inline void forEach(android.view.ViewGroup, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static inline 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 kotlin.sequences.Sequence<android.view.View> getDescendants(android.view.ViewGroup);
+    method public static inline int getSize(android.view.ViewGroup);
+    method public static inline boolean isEmpty(android.view.ViewGroup);
+    method public static inline boolean isNotEmpty(android.view.ViewGroup);
+    method public static operator java.util.Iterator<android.view.View> iterator(android.view.ViewGroup);
+    method public static inline operator void minusAssign(android.view.ViewGroup, android.view.View view);
+    method public static inline operator void plusAssign(android.view.ViewGroup, android.view.View view);
+    method public static inline void setMargins(android.view.ViewGroup.MarginLayoutParams, @Px int size);
+    method public static inline void updateMargins(android.view.ViewGroup.MarginLayoutParams, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+    method @RequiresApi(17) public static inline void updateMarginsRelative(android.view.ViewGroup.MarginLayoutParams, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+  }
+
+  public final class ViewKt {
+    method public static inline void doOnAttach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static inline void doOnDetach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static inline void doOnLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static inline void doOnNextLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static inline androidx.core.view.OneShotPreDrawListener doOnPreDraw(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static android.graphics.Bitmap drawToBitmap(android.view.View, optional android.graphics.Bitmap.Config config);
+    method public static kotlin.sequences.Sequence<android.view.View> getAllViews(android.view.View);
+    method public static kotlin.sequences.Sequence<android.view.ViewParent> getAncestors(android.view.View);
+    method public static inline int getMarginBottom(android.view.View);
+    method public static inline int getMarginEnd(android.view.View);
+    method public static inline int getMarginLeft(android.view.View);
+    method public static inline int getMarginRight(android.view.View);
+    method public static inline int getMarginStart(android.view.View);
+    method public static inline int getMarginTop(android.view.View);
+    method public static inline boolean isGone(android.view.View);
+    method public static inline boolean isInvisible(android.view.View);
+    method public static inline boolean isVisible(android.view.View);
+    method public static inline Runnable postDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method @RequiresApi(16) public static inline Runnable postOnAnimationDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method public static inline void setGone(android.view.View, boolean value);
+    method public static inline void setInvisible(android.view.View, boolean value);
+    method public static inline void setPadding(android.view.View, @Px int size);
+    method public static inline void setVisible(android.view.View, boolean value);
+    method public static inline void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super android.view.ViewGroup.LayoutParams,kotlin.Unit> block);
+    method public static inline <reified T extends android.view.ViewGroup.LayoutParams> void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> block);
+    method public static inline void updatePadding(android.view.View, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+    method @RequiresApi(17) public static inline void updatePaddingRelative(android.view.View, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+  }
+
+}
+
+package androidx.core.widget {
+
+  public final class TextViewKt {
+    method public static inline android.text.TextWatcher addTextChangedListener(android.widget.TextView, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> beforeTextChanged, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> onTextChanged, optional kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> afterTextChanged);
+    method public static inline android.text.TextWatcher doAfterTextChanged(android.widget.TextView, kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> action);
+    method public static inline android.text.TextWatcher doBeforeTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+    method public static inline android.text.TextWatcher doOnTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+  }
+
+}
+
diff --git a/core/core-ktx/api/public_plus_experimental_1.5.0-beta03.txt b/core/core-ktx/api/public_plus_experimental_1.5.0-beta03.txt
new file mode 100644
index 0000000..ea0fa5f
--- /dev/null
+++ b/core/core-ktx/api/public_plus_experimental_1.5.0-beta03.txt
@@ -0,0 +1,606 @@
+// Signature format: 4.0
+package androidx.core.animation {
+
+  public final class AnimatorKt {
+    method public static inline android.animation.Animator.AnimatorListener addListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onRepeat);
+    method @RequiresApi(19) public static inline android.animation.Animator.AnimatorPauseListener addPauseListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onPause);
+    method public static inline android.animation.Animator.AnimatorListener doOnCancel(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static inline android.animation.Animator.AnimatorListener doOnEnd(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.animation.Animator.AnimatorPauseListener doOnPause(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static inline android.animation.Animator.AnimatorListener doOnRepeat(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.animation.Animator.AnimatorPauseListener doOnResume(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static inline 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 {
+    method public static android.content.ContentValues contentValuesOf(kotlin.Pair<java.lang.String,?>... pairs);
+  }
+
+  public final class ContextKt {
+    method public static inline <reified T> T! getSystemService(android.content.Context);
+    method public static inline void withStyledAttributes(android.content.Context, optional android.util.AttributeSet? set, int[] attrs, optional @AttrRes int defStyleAttr, optional @StyleRes int defStyleRes, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+    method public static inline 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 {
+    method public static inline void edit(android.content.SharedPreferences, optional boolean commit, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action);
+  }
+
+}
+
+package androidx.core.content.res {
+
+  public final class 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 inline <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 {
+    method public static inline byte[]? getBlobOrNull(android.database.Cursor, int index);
+    method public static inline Double? getDoubleOrNull(android.database.Cursor, int index);
+    method public static inline Float? getFloatOrNull(android.database.Cursor, int index);
+    method public static inline Integer? getIntOrNull(android.database.Cursor, int index);
+    method public static inline Long? getLongOrNull(android.database.Cursor, int index);
+    method public static inline Short? getShortOrNull(android.database.Cursor, int index);
+    method public static inline String? getStringOrNull(android.database.Cursor, int index);
+  }
+
+}
+
+package androidx.core.database.sqlite {
+
+  public final class SQLiteDatabaseKt {
+    method public static inline <T> T! transaction(android.database.sqlite.SQLiteDatabase, optional boolean exclusive, kotlin.jvm.functions.Function1<? super android.database.sqlite.SQLiteDatabase,? extends T> body);
+  }
+
+}
+
+package androidx.core.graphics {
+
+  public final class BitmapKt {
+    method public static inline android.graphics.Bitmap applyCanvas(android.graphics.Bitmap, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.Point p);
+    method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.PointF p);
+    method public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config);
+    method @RequiresApi(26) public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config, optional boolean hasAlpha, optional android.graphics.ColorSpace colorSpace);
+    method public static inline operator int get(android.graphics.Bitmap, int x, int y);
+    method public static inline android.graphics.Bitmap scale(android.graphics.Bitmap, int width, int height, optional boolean filter);
+    method public static inline operator void set(android.graphics.Bitmap, int x, int y, @ColorInt int color);
+  }
+
+  public final class CanvasKt {
+    method public static inline void withClip(android.graphics.Canvas, android.graphics.Rect clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withClip(android.graphics.Canvas, android.graphics.RectF clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withClip(android.graphics.Canvas, int left, int top, int right, int bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withClip(android.graphics.Canvas, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withClip(android.graphics.Canvas, android.graphics.Path clipPath, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withMatrix(android.graphics.Canvas, optional android.graphics.Matrix matrix, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withRotation(android.graphics.Canvas, optional float degrees, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withSave(android.graphics.Canvas, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withScale(android.graphics.Canvas, optional float x, optional float y, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withSkew(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withTranslation(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+  }
+
+  public final class ColorKt {
+    method @RequiresApi(26) public static inline operator float component1(android.graphics.Color);
+    method public static inline operator int component1(@ColorInt int);
+    method @RequiresApi(26) public static inline operator float component1(@ColorLong long);
+    method @RequiresApi(26) public static inline operator float component2(android.graphics.Color);
+    method public static inline operator int component2(@ColorInt int);
+    method @RequiresApi(26) public static inline operator float component2(@ColorLong long);
+    method @RequiresApi(26) public static inline operator float component3(android.graphics.Color);
+    method public static inline operator int component3(@ColorInt int);
+    method @RequiresApi(26) public static inline operator float component3(@ColorLong long);
+    method @RequiresApi(26) public static inline operator float component4(android.graphics.Color);
+    method public static inline operator int component4(@ColorInt int);
+    method @RequiresApi(26) public static inline operator float component4(@ColorLong long);
+    method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace.Named colorSpace);
+    method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace colorSpace);
+    method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace.Named colorSpace);
+    method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace colorSpace);
+    method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace.Named colorSpace);
+    method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace colorSpace);
+    method public static inline int getAlpha(int);
+    method @RequiresApi(26) public static inline float getAlpha(long);
+    method public static inline int getBlue(int);
+    method @RequiresApi(26) public static inline float getBlue(long);
+    method @RequiresApi(26) public static inline android.graphics.ColorSpace getColorSpace(long);
+    method public static inline int getGreen(int);
+    method @RequiresApi(26) public static inline float getGreen(long);
+    method @RequiresApi(26) public static inline float getLuminance(int);
+    method @RequiresApi(26) public static inline float getLuminance(long);
+    method public static inline int getRed(int);
+    method @RequiresApi(26) public static inline float getRed(long);
+    method @RequiresApi(26) public static inline boolean isSrgb(long);
+    method @RequiresApi(26) public static inline 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 inline android.graphics.Color toColor(@ColorInt int);
+    method @RequiresApi(26) public static inline android.graphics.Color toColor(@ColorLong long);
+    method @ColorInt @RequiresApi(26) public static inline int toColorInt(@ColorLong long);
+    method @ColorInt public static inline int toColorInt(String);
+    method @ColorLong @RequiresApi(26) public static inline long toColorLong(@ColorInt int);
+  }
+
+  public final class ImageDecoderKt {
+    method @RequiresApi(28) public static inline android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+    method @RequiresApi(28) public static inline android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+  }
+
+  public final class MatrixKt {
+    method public static android.graphics.Matrix rotationMatrix(float degrees, optional float px, optional float py);
+    method public static android.graphics.Matrix scaleMatrix(optional float sx, optional float sy);
+    method public static inline operator android.graphics.Matrix times(android.graphics.Matrix, android.graphics.Matrix m);
+    method public static android.graphics.Matrix translationMatrix(optional float tx, optional float ty);
+    method public static inline float[] values(android.graphics.Matrix);
+  }
+
+  public final class PaintKt {
+    method public static inline boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat? blendModeCompat);
+  }
+
+  public final class PathKt {
+    method @RequiresApi(19) public static inline 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, optional float error);
+    method @RequiresApi(19) public static inline operator android.graphics.Path minus(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static inline infix android.graphics.Path or(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static inline operator android.graphics.Path plus(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static inline infix android.graphics.Path xor(android.graphics.Path, android.graphics.Path p);
+  }
+
+  public final class PictureKt {
+    method public static inline 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 {
+    method public static inline operator int component1(android.graphics.Point);
+    method public static inline operator float component1(android.graphics.PointF);
+    method public static inline operator int component2(android.graphics.Point);
+    method public static inline operator float component2(android.graphics.PointF);
+    method public static inline operator android.graphics.Point minus(android.graphics.Point, android.graphics.Point p);
+    method public static inline operator android.graphics.PointF minus(android.graphics.PointF, android.graphics.PointF p);
+    method public static inline operator android.graphics.Point minus(android.graphics.Point, int xy);
+    method public static inline operator android.graphics.PointF minus(android.graphics.PointF, float xy);
+    method public static inline operator android.graphics.Point plus(android.graphics.Point, android.graphics.Point p);
+    method public static inline operator android.graphics.PointF plus(android.graphics.PointF, android.graphics.PointF p);
+    method public static inline operator android.graphics.Point plus(android.graphics.Point, int xy);
+    method public static inline operator android.graphics.PointF plus(android.graphics.PointF, float xy);
+    method public static inline android.graphics.Point toPoint(android.graphics.PointF);
+    method public static inline android.graphics.PointF toPointF(android.graphics.Point);
+    method public static inline operator android.graphics.Point unaryMinus(android.graphics.Point);
+    method public static inline operator android.graphics.PointF unaryMinus(android.graphics.PointF);
+  }
+
+  public final class PorterDuffKt {
+    method public static inline android.graphics.PorterDuffColorFilter toColorFilter(android.graphics.PorterDuff.Mode, int color);
+    method public static inline android.graphics.PorterDuffXfermode toXfermode(android.graphics.PorterDuff.Mode);
+  }
+
+  public final class RectKt {
+    method public static inline infix android.graphics.Rect and(android.graphics.Rect, android.graphics.Rect r);
+    method public static inline infix android.graphics.RectF and(android.graphics.RectF, android.graphics.RectF r);
+    method public static inline operator int component1(android.graphics.Rect);
+    method public static inline operator float component1(android.graphics.RectF);
+    method public static inline operator int component2(android.graphics.Rect);
+    method public static inline operator float component2(android.graphics.RectF);
+    method public static inline operator int component3(android.graphics.Rect);
+    method public static inline operator float component3(android.graphics.RectF);
+    method public static inline operator int component4(android.graphics.Rect);
+    method public static inline operator float component4(android.graphics.RectF);
+    method public static inline operator boolean contains(android.graphics.Rect, android.graphics.Point p);
+    method public static inline operator boolean contains(android.graphics.RectF, android.graphics.PointF p);
+    method public static inline operator android.graphics.Region minus(android.graphics.Rect, android.graphics.Rect r);
+    method public static inline operator android.graphics.Region minus(android.graphics.RectF, android.graphics.RectF r);
+    method public static inline operator android.graphics.Rect minus(android.graphics.Rect, int xy);
+    method public static inline operator android.graphics.RectF minus(android.graphics.RectF, float xy);
+    method public static inline operator android.graphics.Rect minus(android.graphics.Rect, android.graphics.Point xy);
+    method public static inline operator android.graphics.RectF minus(android.graphics.RectF, android.graphics.PointF xy);
+    method public static inline infix android.graphics.Rect or(android.graphics.Rect, android.graphics.Rect r);
+    method public static inline infix android.graphics.RectF or(android.graphics.RectF, android.graphics.RectF r);
+    method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Rect r);
+    method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.RectF r);
+    method public static inline operator android.graphics.Rect plus(android.graphics.Rect, int xy);
+    method public static inline operator android.graphics.RectF plus(android.graphics.RectF, float xy);
+    method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Point xy);
+    method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.PointF xy);
+    method public static inline operator android.graphics.Rect times(android.graphics.Rect, int factor);
+    method public static inline operator android.graphics.RectF times(android.graphics.RectF, int factor);
+    method public static inline operator android.graphics.RectF times(android.graphics.RectF, float factor);
+    method public static inline android.graphics.Rect toRect(android.graphics.RectF);
+    method public static inline android.graphics.RectF toRectF(android.graphics.Rect);
+    method public static inline android.graphics.Region toRegion(android.graphics.Rect);
+    method public static inline android.graphics.Region toRegion(android.graphics.RectF);
+    method public static inline android.graphics.RectF transform(android.graphics.RectF, android.graphics.Matrix m);
+    method public static inline infix android.graphics.Region xor(android.graphics.Rect, android.graphics.Rect r);
+    method public static inline infix android.graphics.Region xor(android.graphics.RectF, android.graphics.RectF r);
+  }
+
+  public final class RegionKt {
+    method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Rect r);
+    method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Region r);
+    method public static inline operator boolean contains(android.graphics.Region, android.graphics.Point p);
+    method public static inline 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 inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Rect r);
+    method public static inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Region r);
+    method public static inline operator android.graphics.Region not(android.graphics.Region);
+    method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Rect r);
+    method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Region r);
+    method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Rect r);
+    method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Region r);
+    method public static inline operator android.graphics.Region unaryMinus(android.graphics.Region);
+    method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Rect r);
+    method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Region r);
+  }
+
+  public final class ShaderKt {
+    method public static inline 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 {
+    method public static inline android.graphics.drawable.BitmapDrawable toDrawable(android.graphics.Bitmap, android.content.res.Resources resources);
+  }
+
+  public final class ColorDrawableKt {
+    method public static inline android.graphics.drawable.ColorDrawable toDrawable(@ColorInt int);
+    method @RequiresApi(26) public static inline android.graphics.drawable.ColorDrawable toDrawable(android.graphics.Color);
+  }
+
+  public final class DrawableKt {
+    method public static android.graphics.Bitmap toBitmap(android.graphics.drawable.Drawable, optional @Px int width, optional @Px int height, optional android.graphics.Bitmap.Config? config);
+    method public static void updateBounds(android.graphics.drawable.Drawable, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+  }
+
+  public final class IconKt {
+    method @RequiresApi(26) public static inline android.graphics.drawable.Icon toAdaptiveIcon(android.graphics.Bitmap);
+    method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.graphics.Bitmap);
+    method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.net.Uri);
+    method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(byte[]);
+  }
+
+}
+
+package androidx.core.location {
+
+  public final class LocationKt {
+    method public static inline operator double component1(android.location.Location);
+    method public static inline operator double component2(android.location.Location);
+  }
+
+}
+
+package androidx.core.net {
+
+  public final class UriKt {
+    method public static java.io.File toFile(android.net.Uri);
+    method public static inline android.net.Uri toUri(String);
+    method public static inline android.net.Uri toUri(java.io.File);
+  }
+
+}
+
+package androidx.core.os {
+
+  public final class BundleKt {
+    method public static android.os.Bundle bundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+  }
+
+  public final class HandlerKt {
+    method public static inline Runnable postAtTime(android.os.Handler, long uptimeMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method public static inline Runnable postDelayed(android.os.Handler, long delayInMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+  }
+
+  public final class PersistableBundleKt {
+    method @RequiresApi(21) public static android.os.PersistableBundle persistableBundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+  }
+
+  public final class TraceKt {
+    method @Deprecated public static inline <T> T! trace(String sectionName, kotlin.jvm.functions.Function0<? extends T> block);
+  }
+
+}
+
+package androidx.core.text {
+
+  public final class CharSequenceKt {
+    method public static inline boolean isDigitsOnly(CharSequence);
+    method public static inline int trimmedLength(CharSequence);
+  }
+
+  public final class HtmlKt {
+    method public static inline android.text.Spanned parseAsHtml(String, optional int flags, optional android.text.Html.ImageGetter? imageGetter, optional android.text.Html.TagHandler? tagHandler);
+    method public static inline String toHtml(android.text.Spanned, optional int option);
+  }
+
+  public final class LocaleKt {
+    method @RequiresApi(17) public static inline int getLayoutDirection(java.util.Locale);
+  }
+
+  public final class SpannableStringBuilderKt {
+    method public static inline android.text.SpannableStringBuilder backgroundColor(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder bold(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannedString buildSpannedString(kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder color(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object![] spans, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object span, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder italic(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder scale(android.text.SpannableStringBuilder, float proportion, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder strikeThrough(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder subscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder superscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder underline(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+  }
+
+  public final class SpannableStringKt {
+    method public static inline void clearSpans(android.text.Spannable);
+    method public static inline operator void set(android.text.Spannable, int start, int end, Object span);
+    method public static inline operator void set(android.text.Spannable, kotlin.ranges.IntRange range, Object span);
+    method public static inline android.text.Spannable toSpannable(CharSequence);
+  }
+
+  public final class SpannedStringKt {
+    method public static inline <reified T> T![]! getSpans(android.text.Spanned, optional int start, optional int end);
+    method public static inline android.text.Spanned toSpanned(CharSequence);
+  }
+
+  public final class StringKt {
+    method public static inline String htmlEncode(String);
+  }
+
+}
+
+package androidx.core.transition {
+
+  public final class TransitionKt {
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener addListener(android.transition.Transition, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onPause);
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnCancel(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnEnd(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnPause(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnResume(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnStart(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+  }
+
+}
+
+package androidx.core.util {
+
+  public final class AtomicFileKt {
+    method @RequiresApi(17) public static inline byte[] readBytes(android.util.AtomicFile);
+    method @RequiresApi(17) public static String readText(android.util.AtomicFile, optional java.nio.charset.Charset charset);
+    method @RequiresApi(17) public static inline 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, optional java.nio.charset.Charset charset);
+  }
+
+  public final class HalfKt {
+    method @RequiresApi(26) public static inline android.util.Half toHalf(@HalfFloat short);
+    method @RequiresApi(26) public static inline android.util.Half toHalf(float);
+    method @RequiresApi(26) public static inline android.util.Half toHalf(double);
+    method @RequiresApi(26) public static inline android.util.Half toHalf(String);
+  }
+
+  public final class LongSparseArrayKt {
+    method @RequiresApi(16) public static inline operator <T> boolean contains(android.util.LongSparseArray<T>, long key);
+    method @RequiresApi(16) public static inline <T> boolean containsKey(android.util.LongSparseArray<T>, long key);
+    method @RequiresApi(16) public static inline <T> boolean containsValue(android.util.LongSparseArray<T>, T? value);
+    method @RequiresApi(16) public static inline <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 inline <T> T! getOrDefault(android.util.LongSparseArray<T>, long key, T? defaultValue);
+    method @RequiresApi(16) public static inline <T> T! getOrElse(android.util.LongSparseArray<T>, long key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+    method @RequiresApi(16) public static inline <T> int getSize(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static inline <T> boolean isEmpty(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static inline <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 inline 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 {
+    method public static inline <K, V> android.util.LruCache<K,V> lruCache(int maxSize, optional kotlin.jvm.functions.Function2<? super K,? super V,java.lang.Integer> sizeOf, optional kotlin.jvm.functions.Function1<? super K,? extends V> create, optional kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved);
+  }
+
+  public final class PairKt {
+    method public static inline operator <F, S> F! component1(androidx.core.util.Pair<F,S>);
+    method public static inline operator <F, S> F! component1(android.util.Pair<F,S>);
+    method public static inline operator <F, S> S! component2(androidx.core.util.Pair<F,S>);
+    method public static inline operator <F, S> S! component2(android.util.Pair<F,S>);
+    method public static inline <F, S> android.util.Pair<F,S> toAndroidPair(kotlin.Pair<? extends F,? extends S>);
+    method public static inline <F, S> androidx.core.util.Pair<F,S> toAndroidXPair(kotlin.Pair<? extends F,? extends S>);
+    method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(androidx.core.util.Pair<F,S>);
+    method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(android.util.Pair<F,S>);
+  }
+
+  public final class RangeKt {
+    method @RequiresApi(21) public static inline 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 inline operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, T value);
+    method @RequiresApi(21) public static inline 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 inline 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 {
+    method @RequiresApi(21) public static inline operator int component1(android.util.Size);
+    method @RequiresApi(21) public static inline operator float component1(android.util.SizeF);
+    method @RequiresApi(21) public static inline operator int component2(android.util.Size);
+    method @RequiresApi(21) public static inline operator float component2(android.util.SizeF);
+  }
+
+  public final class SparseArrayKt {
+    method public static inline operator <T> boolean contains(android.util.SparseArray<T>, int key);
+    method public static inline <T> boolean containsKey(android.util.SparseArray<T>, int key);
+    method public static inline <T> boolean containsValue(android.util.SparseArray<T>, T? value);
+    method public static inline <T> void forEach(android.util.SparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,kotlin.Unit> action);
+    method public static inline <T> T! getOrDefault(android.util.SparseArray<T>, int key, T? defaultValue);
+    method public static inline <T> T! getOrElse(android.util.SparseArray<T>, int key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+    method public static inline <T> int getSize(android.util.SparseArray<T>);
+    method public static inline <T> boolean isEmpty(android.util.SparseArray<T>);
+    method public static inline <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 inline 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 {
+    method public static inline operator boolean contains(android.util.SparseBooleanArray, int key);
+    method public static inline boolean containsKey(android.util.SparseBooleanArray, int key);
+    method public static inline boolean containsValue(android.util.SparseBooleanArray, boolean value);
+    method public static inline void forEach(android.util.SparseBooleanArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Boolean,kotlin.Unit> action);
+    method public static inline boolean getOrDefault(android.util.SparseBooleanArray, int key, boolean defaultValue);
+    method public static inline boolean getOrElse(android.util.SparseBooleanArray, int key, kotlin.jvm.functions.Function0<java.lang.Boolean> defaultValue);
+    method public static inline int getSize(android.util.SparseBooleanArray);
+    method public static inline boolean isEmpty(android.util.SparseBooleanArray);
+    method public static inline 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 inline operator void set(android.util.SparseBooleanArray, int key, boolean value);
+    method public static kotlin.collections.BooleanIterator valueIterator(android.util.SparseBooleanArray);
+  }
+
+  public final class SparseIntArrayKt {
+    method public static inline operator boolean contains(android.util.SparseIntArray, int key);
+    method public static inline boolean containsKey(android.util.SparseIntArray, int key);
+    method public static inline boolean containsValue(android.util.SparseIntArray, int value);
+    method public static inline void forEach(android.util.SparseIntArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+    method public static inline int getOrDefault(android.util.SparseIntArray, int key, int defaultValue);
+    method public static inline int getOrElse(android.util.SparseIntArray, int key, kotlin.jvm.functions.Function0<java.lang.Integer> defaultValue);
+    method public static inline int getSize(android.util.SparseIntArray);
+    method public static inline boolean isEmpty(android.util.SparseIntArray);
+    method public static inline 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 inline operator void set(android.util.SparseIntArray, int key, int value);
+    method public static kotlin.collections.IntIterator valueIterator(android.util.SparseIntArray);
+  }
+
+  public final class SparseLongArrayKt {
+    method @RequiresApi(18) public static inline operator boolean contains(android.util.SparseLongArray, int key);
+    method @RequiresApi(18) public static inline boolean containsKey(android.util.SparseLongArray, int key);
+    method @RequiresApi(18) public static inline boolean containsValue(android.util.SparseLongArray, long value);
+    method @RequiresApi(18) public static inline 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 inline long getOrDefault(android.util.SparseLongArray, int key, long defaultValue);
+    method @RequiresApi(18) public static inline long getOrElse(android.util.SparseLongArray, int key, kotlin.jvm.functions.Function0<java.lang.Long> defaultValue);
+    method @RequiresApi(18) public static inline int getSize(android.util.SparseLongArray);
+    method @RequiresApi(18) public static inline boolean isEmpty(android.util.SparseLongArray);
+    method @RequiresApi(18) public static inline 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 inline 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 {
+    method public static operator boolean contains(android.view.Menu, android.view.MenuItem item);
+    method public static inline void forEach(android.view.Menu, kotlin.jvm.functions.Function1<? super android.view.MenuItem,kotlin.Unit> action);
+    method public static inline void forEachIndexed(android.view.Menu, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.view.MenuItem,kotlin.Unit> action);
+    method public static inline operator android.view.MenuItem get(android.view.Menu, int index);
+    method public static kotlin.sequences.Sequence<android.view.MenuItem> getChildren(android.view.Menu);
+    method public static inline int getSize(android.view.Menu);
+    method public static inline boolean isEmpty(android.view.Menu);
+    method public static inline boolean isNotEmpty(android.view.Menu);
+    method public static operator java.util.Iterator<android.view.MenuItem> iterator(android.view.Menu);
+    method public static inline operator void minusAssign(android.view.Menu, android.view.MenuItem item);
+  }
+
+  public final class ViewGroupKt {
+    method public static inline operator boolean contains(android.view.ViewGroup, android.view.View view);
+    method public static inline void forEach(android.view.ViewGroup, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static inline 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 kotlin.sequences.Sequence<android.view.View> getDescendants(android.view.ViewGroup);
+    method public static inline int getSize(android.view.ViewGroup);
+    method public static inline boolean isEmpty(android.view.ViewGroup);
+    method public static inline boolean isNotEmpty(android.view.ViewGroup);
+    method public static operator java.util.Iterator<android.view.View> iterator(android.view.ViewGroup);
+    method public static inline operator void minusAssign(android.view.ViewGroup, android.view.View view);
+    method public static inline operator void plusAssign(android.view.ViewGroup, android.view.View view);
+    method public static inline void setMargins(android.view.ViewGroup.MarginLayoutParams, @Px int size);
+    method public static inline void updateMargins(android.view.ViewGroup.MarginLayoutParams, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+    method @RequiresApi(17) public static inline void updateMarginsRelative(android.view.ViewGroup.MarginLayoutParams, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+  }
+
+  public final class ViewKt {
+    method public static inline void doOnAttach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static inline void doOnDetach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static inline void doOnLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static inline void doOnNextLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static inline androidx.core.view.OneShotPreDrawListener doOnPreDraw(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static android.graphics.Bitmap drawToBitmap(android.view.View, optional android.graphics.Bitmap.Config config);
+    method public static kotlin.sequences.Sequence<android.view.View> getAllViews(android.view.View);
+    method public static kotlin.sequences.Sequence<android.view.ViewParent> getAncestors(android.view.View);
+    method public static inline int getMarginBottom(android.view.View);
+    method public static inline int getMarginEnd(android.view.View);
+    method public static inline int getMarginLeft(android.view.View);
+    method public static inline int getMarginRight(android.view.View);
+    method public static inline int getMarginStart(android.view.View);
+    method public static inline int getMarginTop(android.view.View);
+    method public static inline boolean isGone(android.view.View);
+    method public static inline boolean isInvisible(android.view.View);
+    method public static inline boolean isVisible(android.view.View);
+    method public static inline Runnable postDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method @RequiresApi(16) public static inline Runnable postOnAnimationDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method public static inline void setGone(android.view.View, boolean value);
+    method public static inline void setInvisible(android.view.View, boolean value);
+    method public static inline void setPadding(android.view.View, @Px int size);
+    method public static inline void setVisible(android.view.View, boolean value);
+    method public static inline void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super android.view.ViewGroup.LayoutParams,kotlin.Unit> block);
+    method public static inline <reified T extends android.view.ViewGroup.LayoutParams> void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> block);
+    method public static inline void updatePadding(android.view.View, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+    method @RequiresApi(17) public static inline void updatePaddingRelative(android.view.View, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+  }
+
+}
+
+package androidx.core.widget {
+
+  public final class TextViewKt {
+    method public static inline android.text.TextWatcher addTextChangedListener(android.widget.TextView, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> beforeTextChanged, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> onTextChanged, optional kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> afterTextChanged);
+    method public static inline android.text.TextWatcher doAfterTextChanged(android.widget.TextView, kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> action);
+    method public static inline android.text.TextWatcher doBeforeTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+    method public static inline android.text.TextWatcher doOnTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+  }
+
+}
+
diff --git a/core/core-ktx/api/res-1.5.0-beta03.txt b/core/core-ktx/api/res-1.5.0-beta03.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/core/core-ktx/api/res-1.5.0-beta03.txt
diff --git a/core/core-ktx/api/restricted_1.5.0-beta03.txt b/core/core-ktx/api/restricted_1.5.0-beta03.txt
new file mode 100644
index 0000000..ea0fa5f
--- /dev/null
+++ b/core/core-ktx/api/restricted_1.5.0-beta03.txt
@@ -0,0 +1,606 @@
+// Signature format: 4.0
+package androidx.core.animation {
+
+  public final class AnimatorKt {
+    method public static inline android.animation.Animator.AnimatorListener addListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onRepeat);
+    method @RequiresApi(19) public static inline android.animation.Animator.AnimatorPauseListener addPauseListener(android.animation.Animator, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> onPause);
+    method public static inline android.animation.Animator.AnimatorListener doOnCancel(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static inline android.animation.Animator.AnimatorListener doOnEnd(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.animation.Animator.AnimatorPauseListener doOnPause(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static inline android.animation.Animator.AnimatorListener doOnRepeat(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.animation.Animator.AnimatorPauseListener doOnResume(android.animation.Animator, kotlin.jvm.functions.Function1<? super android.animation.Animator,kotlin.Unit> action);
+    method public static inline 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 {
+    method public static android.content.ContentValues contentValuesOf(kotlin.Pair<java.lang.String,?>... pairs);
+  }
+
+  public final class ContextKt {
+    method public static inline <reified T> T! getSystemService(android.content.Context);
+    method public static inline void withStyledAttributes(android.content.Context, optional android.util.AttributeSet? set, int[] attrs, optional @AttrRes int defStyleAttr, optional @StyleRes int defStyleRes, kotlin.jvm.functions.Function1<? super android.content.res.TypedArray,kotlin.Unit> block);
+    method public static inline 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 {
+    method public static inline void edit(android.content.SharedPreferences, optional boolean commit, kotlin.jvm.functions.Function1<? super android.content.SharedPreferences.Editor,kotlin.Unit> action);
+  }
+
+}
+
+package androidx.core.content.res {
+
+  public final class 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 inline <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 {
+    method public static inline byte[]? getBlobOrNull(android.database.Cursor, int index);
+    method public static inline Double? getDoubleOrNull(android.database.Cursor, int index);
+    method public static inline Float? getFloatOrNull(android.database.Cursor, int index);
+    method public static inline Integer? getIntOrNull(android.database.Cursor, int index);
+    method public static inline Long? getLongOrNull(android.database.Cursor, int index);
+    method public static inline Short? getShortOrNull(android.database.Cursor, int index);
+    method public static inline String? getStringOrNull(android.database.Cursor, int index);
+  }
+
+}
+
+package androidx.core.database.sqlite {
+
+  public final class SQLiteDatabaseKt {
+    method public static inline <T> T! transaction(android.database.sqlite.SQLiteDatabase, optional boolean exclusive, kotlin.jvm.functions.Function1<? super android.database.sqlite.SQLiteDatabase,? extends T> body);
+  }
+
+}
+
+package androidx.core.graphics {
+
+  public final class BitmapKt {
+    method public static inline android.graphics.Bitmap applyCanvas(android.graphics.Bitmap, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.Point p);
+    method public static inline operator boolean contains(android.graphics.Bitmap, android.graphics.PointF p);
+    method public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config);
+    method @RequiresApi(26) public static inline android.graphics.Bitmap createBitmap(int width, int height, optional android.graphics.Bitmap.Config config, optional boolean hasAlpha, optional android.graphics.ColorSpace colorSpace);
+    method public static inline operator int get(android.graphics.Bitmap, int x, int y);
+    method public static inline android.graphics.Bitmap scale(android.graphics.Bitmap, int width, int height, optional boolean filter);
+    method public static inline operator void set(android.graphics.Bitmap, int x, int y, @ColorInt int color);
+  }
+
+  public final class CanvasKt {
+    method public static inline void withClip(android.graphics.Canvas, android.graphics.Rect clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withClip(android.graphics.Canvas, android.graphics.RectF clipRect, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withClip(android.graphics.Canvas, int left, int top, int right, int bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withClip(android.graphics.Canvas, float left, float top, float right, float bottom, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withClip(android.graphics.Canvas, android.graphics.Path clipPath, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withMatrix(android.graphics.Canvas, optional android.graphics.Matrix matrix, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withRotation(android.graphics.Canvas, optional float degrees, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withSave(android.graphics.Canvas, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withScale(android.graphics.Canvas, optional float x, optional float y, optional float pivotX, optional float pivotY, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withSkew(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+    method public static inline void withTranslation(android.graphics.Canvas, optional float x, optional float y, kotlin.jvm.functions.Function1<? super android.graphics.Canvas,kotlin.Unit> block);
+  }
+
+  public final class ColorKt {
+    method @RequiresApi(26) public static inline operator float component1(android.graphics.Color);
+    method public static inline operator int component1(@ColorInt int);
+    method @RequiresApi(26) public static inline operator float component1(@ColorLong long);
+    method @RequiresApi(26) public static inline operator float component2(android.graphics.Color);
+    method public static inline operator int component2(@ColorInt int);
+    method @RequiresApi(26) public static inline operator float component2(@ColorLong long);
+    method @RequiresApi(26) public static inline operator float component3(android.graphics.Color);
+    method public static inline operator int component3(@ColorInt int);
+    method @RequiresApi(26) public static inline operator float component3(@ColorLong long);
+    method @RequiresApi(26) public static inline operator float component4(android.graphics.Color);
+    method public static inline operator int component4(@ColorInt int);
+    method @RequiresApi(26) public static inline operator float component4(@ColorLong long);
+    method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace.Named colorSpace);
+    method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorInt int, android.graphics.ColorSpace colorSpace);
+    method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace.Named colorSpace);
+    method @ColorLong @RequiresApi(26) public static inline infix long convertTo(@ColorLong long, android.graphics.ColorSpace colorSpace);
+    method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace.Named colorSpace);
+    method @RequiresApi(26) public static inline infix android.graphics.Color convertTo(android.graphics.Color, android.graphics.ColorSpace colorSpace);
+    method public static inline int getAlpha(int);
+    method @RequiresApi(26) public static inline float getAlpha(long);
+    method public static inline int getBlue(int);
+    method @RequiresApi(26) public static inline float getBlue(long);
+    method @RequiresApi(26) public static inline android.graphics.ColorSpace getColorSpace(long);
+    method public static inline int getGreen(int);
+    method @RequiresApi(26) public static inline float getGreen(long);
+    method @RequiresApi(26) public static inline float getLuminance(int);
+    method @RequiresApi(26) public static inline float getLuminance(long);
+    method public static inline int getRed(int);
+    method @RequiresApi(26) public static inline float getRed(long);
+    method @RequiresApi(26) public static inline boolean isSrgb(long);
+    method @RequiresApi(26) public static inline 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 inline android.graphics.Color toColor(@ColorInt int);
+    method @RequiresApi(26) public static inline android.graphics.Color toColor(@ColorLong long);
+    method @ColorInt @RequiresApi(26) public static inline int toColorInt(@ColorLong long);
+    method @ColorInt public static inline int toColorInt(String);
+    method @ColorLong @RequiresApi(26) public static inline long toColorLong(@ColorInt int);
+  }
+
+  public final class ImageDecoderKt {
+    method @RequiresApi(28) public static inline android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+    method @RequiresApi(28) public static inline android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, kotlin.jvm.functions.Function3<? super android.graphics.ImageDecoder,? super android.graphics.ImageDecoder.ImageInfo,? super android.graphics.ImageDecoder.Source,kotlin.Unit> action);
+  }
+
+  public final class MatrixKt {
+    method public static android.graphics.Matrix rotationMatrix(float degrees, optional float px, optional float py);
+    method public static android.graphics.Matrix scaleMatrix(optional float sx, optional float sy);
+    method public static inline operator android.graphics.Matrix times(android.graphics.Matrix, android.graphics.Matrix m);
+    method public static android.graphics.Matrix translationMatrix(optional float tx, optional float ty);
+    method public static inline float[] values(android.graphics.Matrix);
+  }
+
+  public final class PaintKt {
+    method public static inline boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat? blendModeCompat);
+  }
+
+  public final class PathKt {
+    method @RequiresApi(19) public static inline 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, optional float error);
+    method @RequiresApi(19) public static inline operator android.graphics.Path minus(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static inline infix android.graphics.Path or(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static inline operator android.graphics.Path plus(android.graphics.Path, android.graphics.Path p);
+    method @RequiresApi(19) public static inline infix android.graphics.Path xor(android.graphics.Path, android.graphics.Path p);
+  }
+
+  public final class PictureKt {
+    method public static inline 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 {
+    method public static inline operator int component1(android.graphics.Point);
+    method public static inline operator float component1(android.graphics.PointF);
+    method public static inline operator int component2(android.graphics.Point);
+    method public static inline operator float component2(android.graphics.PointF);
+    method public static inline operator android.graphics.Point minus(android.graphics.Point, android.graphics.Point p);
+    method public static inline operator android.graphics.PointF minus(android.graphics.PointF, android.graphics.PointF p);
+    method public static inline operator android.graphics.Point minus(android.graphics.Point, int xy);
+    method public static inline operator android.graphics.PointF minus(android.graphics.PointF, float xy);
+    method public static inline operator android.graphics.Point plus(android.graphics.Point, android.graphics.Point p);
+    method public static inline operator android.graphics.PointF plus(android.graphics.PointF, android.graphics.PointF p);
+    method public static inline operator android.graphics.Point plus(android.graphics.Point, int xy);
+    method public static inline operator android.graphics.PointF plus(android.graphics.PointF, float xy);
+    method public static inline android.graphics.Point toPoint(android.graphics.PointF);
+    method public static inline android.graphics.PointF toPointF(android.graphics.Point);
+    method public static inline operator android.graphics.Point unaryMinus(android.graphics.Point);
+    method public static inline operator android.graphics.PointF unaryMinus(android.graphics.PointF);
+  }
+
+  public final class PorterDuffKt {
+    method public static inline android.graphics.PorterDuffColorFilter toColorFilter(android.graphics.PorterDuff.Mode, int color);
+    method public static inline android.graphics.PorterDuffXfermode toXfermode(android.graphics.PorterDuff.Mode);
+  }
+
+  public final class RectKt {
+    method public static inline infix android.graphics.Rect and(android.graphics.Rect, android.graphics.Rect r);
+    method public static inline infix android.graphics.RectF and(android.graphics.RectF, android.graphics.RectF r);
+    method public static inline operator int component1(android.graphics.Rect);
+    method public static inline operator float component1(android.graphics.RectF);
+    method public static inline operator int component2(android.graphics.Rect);
+    method public static inline operator float component2(android.graphics.RectF);
+    method public static inline operator int component3(android.graphics.Rect);
+    method public static inline operator float component3(android.graphics.RectF);
+    method public static inline operator int component4(android.graphics.Rect);
+    method public static inline operator float component4(android.graphics.RectF);
+    method public static inline operator boolean contains(android.graphics.Rect, android.graphics.Point p);
+    method public static inline operator boolean contains(android.graphics.RectF, android.graphics.PointF p);
+    method public static inline operator android.graphics.Region minus(android.graphics.Rect, android.graphics.Rect r);
+    method public static inline operator android.graphics.Region minus(android.graphics.RectF, android.graphics.RectF r);
+    method public static inline operator android.graphics.Rect minus(android.graphics.Rect, int xy);
+    method public static inline operator android.graphics.RectF minus(android.graphics.RectF, float xy);
+    method public static inline operator android.graphics.Rect minus(android.graphics.Rect, android.graphics.Point xy);
+    method public static inline operator android.graphics.RectF minus(android.graphics.RectF, android.graphics.PointF xy);
+    method public static inline infix android.graphics.Rect or(android.graphics.Rect, android.graphics.Rect r);
+    method public static inline infix android.graphics.RectF or(android.graphics.RectF, android.graphics.RectF r);
+    method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Rect r);
+    method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.RectF r);
+    method public static inline operator android.graphics.Rect plus(android.graphics.Rect, int xy);
+    method public static inline operator android.graphics.RectF plus(android.graphics.RectF, float xy);
+    method public static inline operator android.graphics.Rect plus(android.graphics.Rect, android.graphics.Point xy);
+    method public static inline operator android.graphics.RectF plus(android.graphics.RectF, android.graphics.PointF xy);
+    method public static inline operator android.graphics.Rect times(android.graphics.Rect, int factor);
+    method public static inline operator android.graphics.RectF times(android.graphics.RectF, int factor);
+    method public static inline operator android.graphics.RectF times(android.graphics.RectF, float factor);
+    method public static inline android.graphics.Rect toRect(android.graphics.RectF);
+    method public static inline android.graphics.RectF toRectF(android.graphics.Rect);
+    method public static inline android.graphics.Region toRegion(android.graphics.Rect);
+    method public static inline android.graphics.Region toRegion(android.graphics.RectF);
+    method public static inline android.graphics.RectF transform(android.graphics.RectF, android.graphics.Matrix m);
+    method public static inline infix android.graphics.Region xor(android.graphics.Rect, android.graphics.Rect r);
+    method public static inline infix android.graphics.Region xor(android.graphics.RectF, android.graphics.RectF r);
+  }
+
+  public final class RegionKt {
+    method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Rect r);
+    method public static inline infix android.graphics.Region and(android.graphics.Region, android.graphics.Region r);
+    method public static inline operator boolean contains(android.graphics.Region, android.graphics.Point p);
+    method public static inline 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 inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Rect r);
+    method public static inline operator android.graphics.Region minus(android.graphics.Region, android.graphics.Region r);
+    method public static inline operator android.graphics.Region not(android.graphics.Region);
+    method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Rect r);
+    method public static inline infix android.graphics.Region or(android.graphics.Region, android.graphics.Region r);
+    method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Rect r);
+    method public static inline operator android.graphics.Region plus(android.graphics.Region, android.graphics.Region r);
+    method public static inline operator android.graphics.Region unaryMinus(android.graphics.Region);
+    method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Rect r);
+    method public static inline infix android.graphics.Region xor(android.graphics.Region, android.graphics.Region r);
+  }
+
+  public final class ShaderKt {
+    method public static inline 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 {
+    method public static inline android.graphics.drawable.BitmapDrawable toDrawable(android.graphics.Bitmap, android.content.res.Resources resources);
+  }
+
+  public final class ColorDrawableKt {
+    method public static inline android.graphics.drawable.ColorDrawable toDrawable(@ColorInt int);
+    method @RequiresApi(26) public static inline android.graphics.drawable.ColorDrawable toDrawable(android.graphics.Color);
+  }
+
+  public final class DrawableKt {
+    method public static android.graphics.Bitmap toBitmap(android.graphics.drawable.Drawable, optional @Px int width, optional @Px int height, optional android.graphics.Bitmap.Config? config);
+    method public static void updateBounds(android.graphics.drawable.Drawable, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+  }
+
+  public final class IconKt {
+    method @RequiresApi(26) public static inline android.graphics.drawable.Icon toAdaptiveIcon(android.graphics.Bitmap);
+    method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.graphics.Bitmap);
+    method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(android.net.Uri);
+    method @RequiresApi(26) public static inline android.graphics.drawable.Icon toIcon(byte[]);
+  }
+
+}
+
+package androidx.core.location {
+
+  public final class LocationKt {
+    method public static inline operator double component1(android.location.Location);
+    method public static inline operator double component2(android.location.Location);
+  }
+
+}
+
+package androidx.core.net {
+
+  public final class UriKt {
+    method public static java.io.File toFile(android.net.Uri);
+    method public static inline android.net.Uri toUri(String);
+    method public static inline android.net.Uri toUri(java.io.File);
+  }
+
+}
+
+package androidx.core.os {
+
+  public final class BundleKt {
+    method public static android.os.Bundle bundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+  }
+
+  public final class HandlerKt {
+    method public static inline Runnable postAtTime(android.os.Handler, long uptimeMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method public static inline Runnable postDelayed(android.os.Handler, long delayInMillis, optional Object? token, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+  }
+
+  public final class PersistableBundleKt {
+    method @RequiresApi(21) public static android.os.PersistableBundle persistableBundleOf(kotlin.Pair<java.lang.String,?>... pairs);
+  }
+
+  public final class TraceKt {
+    method @Deprecated public static inline <T> T! trace(String sectionName, kotlin.jvm.functions.Function0<? extends T> block);
+  }
+
+}
+
+package androidx.core.text {
+
+  public final class CharSequenceKt {
+    method public static inline boolean isDigitsOnly(CharSequence);
+    method public static inline int trimmedLength(CharSequence);
+  }
+
+  public final class HtmlKt {
+    method public static inline android.text.Spanned parseAsHtml(String, optional int flags, optional android.text.Html.ImageGetter? imageGetter, optional android.text.Html.TagHandler? tagHandler);
+    method public static inline String toHtml(android.text.Spanned, optional int option);
+  }
+
+  public final class LocaleKt {
+    method @RequiresApi(17) public static inline int getLayoutDirection(java.util.Locale);
+  }
+
+  public final class SpannableStringBuilderKt {
+    method public static inline android.text.SpannableStringBuilder backgroundColor(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder bold(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannedString buildSpannedString(kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder color(android.text.SpannableStringBuilder, @ColorInt int color, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object![] spans, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder inSpans(android.text.SpannableStringBuilder, Object span, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder italic(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder scale(android.text.SpannableStringBuilder, float proportion, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder strikeThrough(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder subscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder superscript(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+    method public static inline android.text.SpannableStringBuilder underline(android.text.SpannableStringBuilder, kotlin.jvm.functions.Function1<? super android.text.SpannableStringBuilder,kotlin.Unit> builderAction);
+  }
+
+  public final class SpannableStringKt {
+    method public static inline void clearSpans(android.text.Spannable);
+    method public static inline operator void set(android.text.Spannable, int start, int end, Object span);
+    method public static inline operator void set(android.text.Spannable, kotlin.ranges.IntRange range, Object span);
+    method public static inline android.text.Spannable toSpannable(CharSequence);
+  }
+
+  public final class SpannedStringKt {
+    method public static inline <reified T> T![]! getSpans(android.text.Spanned, optional int start, optional int end);
+    method public static inline android.text.Spanned toSpanned(CharSequence);
+  }
+
+  public final class StringKt {
+    method public static inline String htmlEncode(String);
+  }
+
+}
+
+package androidx.core.transition {
+
+  public final class TransitionKt {
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener addListener(android.transition.Transition, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onEnd, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onStart, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onCancel, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onResume, optional kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> onPause);
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnCancel(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnEnd(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnPause(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnResume(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+    method @RequiresApi(19) public static inline android.transition.Transition.TransitionListener doOnStart(android.transition.Transition, kotlin.jvm.functions.Function1<? super android.transition.Transition,kotlin.Unit> action);
+  }
+
+}
+
+package androidx.core.util {
+
+  public final class AtomicFileKt {
+    method @RequiresApi(17) public static inline byte[] readBytes(android.util.AtomicFile);
+    method @RequiresApi(17) public static String readText(android.util.AtomicFile, optional java.nio.charset.Charset charset);
+    method @RequiresApi(17) public static inline 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, optional java.nio.charset.Charset charset);
+  }
+
+  public final class HalfKt {
+    method @RequiresApi(26) public static inline android.util.Half toHalf(@HalfFloat short);
+    method @RequiresApi(26) public static inline android.util.Half toHalf(float);
+    method @RequiresApi(26) public static inline android.util.Half toHalf(double);
+    method @RequiresApi(26) public static inline android.util.Half toHalf(String);
+  }
+
+  public final class LongSparseArrayKt {
+    method @RequiresApi(16) public static inline operator <T> boolean contains(android.util.LongSparseArray<T>, long key);
+    method @RequiresApi(16) public static inline <T> boolean containsKey(android.util.LongSparseArray<T>, long key);
+    method @RequiresApi(16) public static inline <T> boolean containsValue(android.util.LongSparseArray<T>, T? value);
+    method @RequiresApi(16) public static inline <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 inline <T> T! getOrDefault(android.util.LongSparseArray<T>, long key, T? defaultValue);
+    method @RequiresApi(16) public static inline <T> T! getOrElse(android.util.LongSparseArray<T>, long key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+    method @RequiresApi(16) public static inline <T> int getSize(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static inline <T> boolean isEmpty(android.util.LongSparseArray<T>);
+    method @RequiresApi(16) public static inline <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 inline 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 {
+    method public static inline <K, V> android.util.LruCache<K,V> lruCache(int maxSize, optional kotlin.jvm.functions.Function2<? super K,? super V,java.lang.Integer> sizeOf, optional kotlin.jvm.functions.Function1<? super K,? extends V> create, optional kotlin.jvm.functions.Function4<? super java.lang.Boolean,? super K,? super V,? super V,kotlin.Unit> onEntryRemoved);
+  }
+
+  public final class PairKt {
+    method public static inline operator <F, S> F! component1(androidx.core.util.Pair<F,S>);
+    method public static inline operator <F, S> F! component1(android.util.Pair<F,S>);
+    method public static inline operator <F, S> S! component2(androidx.core.util.Pair<F,S>);
+    method public static inline operator <F, S> S! component2(android.util.Pair<F,S>);
+    method public static inline <F, S> android.util.Pair<F,S> toAndroidPair(kotlin.Pair<? extends F,? extends S>);
+    method public static inline <F, S> androidx.core.util.Pair<F,S> toAndroidXPair(kotlin.Pair<? extends F,? extends S>);
+    method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(androidx.core.util.Pair<F,S>);
+    method public static inline <F, S> kotlin.Pair<F,S> toKotlinPair(android.util.Pair<F,S>);
+  }
+
+  public final class RangeKt {
+    method @RequiresApi(21) public static inline 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 inline operator <T extends java.lang.Comparable<? super T>> android.util.Range<T> plus(android.util.Range<T>, T value);
+    method @RequiresApi(21) public static inline 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 inline 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 {
+    method @RequiresApi(21) public static inline operator int component1(android.util.Size);
+    method @RequiresApi(21) public static inline operator float component1(android.util.SizeF);
+    method @RequiresApi(21) public static inline operator int component2(android.util.Size);
+    method @RequiresApi(21) public static inline operator float component2(android.util.SizeF);
+  }
+
+  public final class SparseArrayKt {
+    method public static inline operator <T> boolean contains(android.util.SparseArray<T>, int key);
+    method public static inline <T> boolean containsKey(android.util.SparseArray<T>, int key);
+    method public static inline <T> boolean containsValue(android.util.SparseArray<T>, T? value);
+    method public static inline <T> void forEach(android.util.SparseArray<T>, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super T,kotlin.Unit> action);
+    method public static inline <T> T! getOrDefault(android.util.SparseArray<T>, int key, T? defaultValue);
+    method public static inline <T> T! getOrElse(android.util.SparseArray<T>, int key, kotlin.jvm.functions.Function0<? extends T> defaultValue);
+    method public static inline <T> int getSize(android.util.SparseArray<T>);
+    method public static inline <T> boolean isEmpty(android.util.SparseArray<T>);
+    method public static inline <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 inline 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 {
+    method public static inline operator boolean contains(android.util.SparseBooleanArray, int key);
+    method public static inline boolean containsKey(android.util.SparseBooleanArray, int key);
+    method public static inline boolean containsValue(android.util.SparseBooleanArray, boolean value);
+    method public static inline void forEach(android.util.SparseBooleanArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Boolean,kotlin.Unit> action);
+    method public static inline boolean getOrDefault(android.util.SparseBooleanArray, int key, boolean defaultValue);
+    method public static inline boolean getOrElse(android.util.SparseBooleanArray, int key, kotlin.jvm.functions.Function0<java.lang.Boolean> defaultValue);
+    method public static inline int getSize(android.util.SparseBooleanArray);
+    method public static inline boolean isEmpty(android.util.SparseBooleanArray);
+    method public static inline 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 inline operator void set(android.util.SparseBooleanArray, int key, boolean value);
+    method public static kotlin.collections.BooleanIterator valueIterator(android.util.SparseBooleanArray);
+  }
+
+  public final class SparseIntArrayKt {
+    method public static inline operator boolean contains(android.util.SparseIntArray, int key);
+    method public static inline boolean containsKey(android.util.SparseIntArray, int key);
+    method public static inline boolean containsValue(android.util.SparseIntArray, int value);
+    method public static inline void forEach(android.util.SparseIntArray, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+    method public static inline int getOrDefault(android.util.SparseIntArray, int key, int defaultValue);
+    method public static inline int getOrElse(android.util.SparseIntArray, int key, kotlin.jvm.functions.Function0<java.lang.Integer> defaultValue);
+    method public static inline int getSize(android.util.SparseIntArray);
+    method public static inline boolean isEmpty(android.util.SparseIntArray);
+    method public static inline 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 inline operator void set(android.util.SparseIntArray, int key, int value);
+    method public static kotlin.collections.IntIterator valueIterator(android.util.SparseIntArray);
+  }
+
+  public final class SparseLongArrayKt {
+    method @RequiresApi(18) public static inline operator boolean contains(android.util.SparseLongArray, int key);
+    method @RequiresApi(18) public static inline boolean containsKey(android.util.SparseLongArray, int key);
+    method @RequiresApi(18) public static inline boolean containsValue(android.util.SparseLongArray, long value);
+    method @RequiresApi(18) public static inline 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 inline long getOrDefault(android.util.SparseLongArray, int key, long defaultValue);
+    method @RequiresApi(18) public static inline long getOrElse(android.util.SparseLongArray, int key, kotlin.jvm.functions.Function0<java.lang.Long> defaultValue);
+    method @RequiresApi(18) public static inline int getSize(android.util.SparseLongArray);
+    method @RequiresApi(18) public static inline boolean isEmpty(android.util.SparseLongArray);
+    method @RequiresApi(18) public static inline 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 inline 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 {
+    method public static operator boolean contains(android.view.Menu, android.view.MenuItem item);
+    method public static inline void forEach(android.view.Menu, kotlin.jvm.functions.Function1<? super android.view.MenuItem,kotlin.Unit> action);
+    method public static inline void forEachIndexed(android.view.Menu, kotlin.jvm.functions.Function2<? super java.lang.Integer,? super android.view.MenuItem,kotlin.Unit> action);
+    method public static inline operator android.view.MenuItem get(android.view.Menu, int index);
+    method public static kotlin.sequences.Sequence<android.view.MenuItem> getChildren(android.view.Menu);
+    method public static inline int getSize(android.view.Menu);
+    method public static inline boolean isEmpty(android.view.Menu);
+    method public static inline boolean isNotEmpty(android.view.Menu);
+    method public static operator java.util.Iterator<android.view.MenuItem> iterator(android.view.Menu);
+    method public static inline operator void minusAssign(android.view.Menu, android.view.MenuItem item);
+  }
+
+  public final class ViewGroupKt {
+    method public static inline operator boolean contains(android.view.ViewGroup, android.view.View view);
+    method public static inline void forEach(android.view.ViewGroup, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static inline 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 kotlin.sequences.Sequence<android.view.View> getDescendants(android.view.ViewGroup);
+    method public static inline int getSize(android.view.ViewGroup);
+    method public static inline boolean isEmpty(android.view.ViewGroup);
+    method public static inline boolean isNotEmpty(android.view.ViewGroup);
+    method public static operator java.util.Iterator<android.view.View> iterator(android.view.ViewGroup);
+    method public static inline operator void minusAssign(android.view.ViewGroup, android.view.View view);
+    method public static inline operator void plusAssign(android.view.ViewGroup, android.view.View view);
+    method public static inline void setMargins(android.view.ViewGroup.MarginLayoutParams, @Px int size);
+    method public static inline void updateMargins(android.view.ViewGroup.MarginLayoutParams, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+    method @RequiresApi(17) public static inline void updateMarginsRelative(android.view.ViewGroup.MarginLayoutParams, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+  }
+
+  public final class ViewKt {
+    method public static inline void doOnAttach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static inline void doOnDetach(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static inline void doOnLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static inline void doOnNextLayout(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static inline androidx.core.view.OneShotPreDrawListener doOnPreDraw(android.view.View, kotlin.jvm.functions.Function1<? super android.view.View,kotlin.Unit> action);
+    method public static android.graphics.Bitmap drawToBitmap(android.view.View, optional android.graphics.Bitmap.Config config);
+    method public static kotlin.sequences.Sequence<android.view.View> getAllViews(android.view.View);
+    method public static kotlin.sequences.Sequence<android.view.ViewParent> getAncestors(android.view.View);
+    method public static inline int getMarginBottom(android.view.View);
+    method public static inline int getMarginEnd(android.view.View);
+    method public static inline int getMarginLeft(android.view.View);
+    method public static inline int getMarginRight(android.view.View);
+    method public static inline int getMarginStart(android.view.View);
+    method public static inline int getMarginTop(android.view.View);
+    method public static inline boolean isGone(android.view.View);
+    method public static inline boolean isInvisible(android.view.View);
+    method public static inline boolean isVisible(android.view.View);
+    method public static inline Runnable postDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method @RequiresApi(16) public static inline Runnable postOnAnimationDelayed(android.view.View, long delayInMillis, kotlin.jvm.functions.Function0<kotlin.Unit> action);
+    method public static inline void setGone(android.view.View, boolean value);
+    method public static inline void setInvisible(android.view.View, boolean value);
+    method public static inline void setPadding(android.view.View, @Px int size);
+    method public static inline void setVisible(android.view.View, boolean value);
+    method public static inline void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super android.view.ViewGroup.LayoutParams,kotlin.Unit> block);
+    method public static inline <reified T extends android.view.ViewGroup.LayoutParams> void updateLayoutParams(android.view.View, kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> block);
+    method public static inline void updatePadding(android.view.View, optional @Px int left, optional @Px int top, optional @Px int right, optional @Px int bottom);
+    method @RequiresApi(17) public static inline void updatePaddingRelative(android.view.View, optional @Px int start, optional @Px int top, optional @Px int end, optional @Px int bottom);
+  }
+
+}
+
+package androidx.core.widget {
+
+  public final class TextViewKt {
+    method public static inline android.text.TextWatcher addTextChangedListener(android.widget.TextView, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> beforeTextChanged, optional kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> onTextChanged, optional kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> afterTextChanged);
+    method public static inline android.text.TextWatcher doAfterTextChanged(android.widget.TextView, kotlin.jvm.functions.Function1<? super android.text.Editable,kotlin.Unit> action);
+    method public static inline android.text.TextWatcher doBeforeTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+    method public static inline android.text.TextWatcher doOnTextChanged(android.widget.TextView, kotlin.jvm.functions.Function4<? super java.lang.CharSequence,? super java.lang.Integer,? super java.lang.Integer,? super java.lang.Integer,kotlin.Unit> action);
+  }
+
+}
+
diff --git a/core/core/api/1.5.0-beta03.txt b/core/core/api/1.5.0-beta03.txt
new file mode 100644
index 0000000..b7ab56a
--- /dev/null
+++ b/core/core/api/1.5.0-beta03.txt
@@ -0,0 +1,3504 @@
+// Signature format: 4.0
+package androidx.core.accessibilityservice {
+
+  public final class AccessibilityServiceInfoCompat {
+    method public static String capabilityToString(int);
+    method public static String feedbackTypeToString(int);
+    method public static String? flagToString(int);
+    method public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static String? loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager);
+    field public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 8; // 0x8
+    field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+    field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
+    field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
+    field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
+    field public static final int FEEDBACK_BRAILLE = 32; // 0x20
+    field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
+    field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+    field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+    field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
+    field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
+  }
+
+}
+
+package androidx.core.app {
+
+  public class ActivityCompat extends androidx.core.content.ContextCompat {
+    ctor protected ActivityCompat();
+    method public static void finishAffinity(android.app.Activity);
+    method public static void finishAfterTransition(android.app.Activity);
+    method public static android.net.Uri? getReferrer(android.app.Activity);
+    method @Deprecated public static boolean invalidateOptionsMenu(android.app.Activity!);
+    method public static void postponeEnterTransition(android.app.Activity);
+    method public static void recreate(android.app.Activity);
+    method public static androidx.core.view.DragAndDropPermissionsCompat? requestDragAndDropPermissions(android.app.Activity!, android.view.DragEvent!);
+    method public static void requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+    method public static <T extends android.view.View> T requireViewById(android.app.Activity, @IdRes int);
+    method public static void setEnterSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+    method public static void setExitSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+    method public static void setLocusContext(android.app.Activity, androidx.core.content.LocusIdCompat?, android.os.Bundle?);
+    method public static void setPermissionCompatDelegate(androidx.core.app.ActivityCompat.PermissionCompatDelegate?);
+    method public static boolean shouldShowRequestPermissionRationale(android.app.Activity, String);
+    method public static void startActivityForResult(android.app.Activity, android.content.Intent, int, android.os.Bundle?);
+    method public static void startIntentSenderForResult(android.app.Activity, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public static void startPostponedEnterTransition(android.app.Activity);
+  }
+
+  public static interface ActivityCompat.OnRequestPermissionsResultCallback {
+    method public void onRequestPermissionsResult(int, String![], int[]);
+  }
+
+  public static interface ActivityCompat.PermissionCompatDelegate {
+    method public boolean onActivityResult(android.app.Activity, @IntRange(from=0) int, int, android.content.Intent?);
+    method public boolean requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+  }
+
+  public final class ActivityManagerCompat {
+    method public static boolean isLowRamDevice(android.app.ActivityManager);
+  }
+
+  public class ActivityOptionsCompat {
+    ctor protected ActivityOptionsCompat();
+    method public android.graphics.Rect? getLaunchBounds();
+    method public static androidx.core.app.ActivityOptionsCompat makeBasic();
+    method public static androidx.core.app.ActivityOptionsCompat makeClipRevealAnimation(android.view.View, int, int, int, int);
+    method public static androidx.core.app.ActivityOptionsCompat makeCustomAnimation(android.content.Context, int, int);
+    method public static androidx.core.app.ActivityOptionsCompat makeScaleUpAnimation(android.view.View, int, int, int, int);
+    method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.view.View, String);
+    method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, androidx.core.util.Pair<android.view.View!,java.lang.String!>!...);
+    method public static androidx.core.app.ActivityOptionsCompat makeTaskLaunchBehind();
+    method public static androidx.core.app.ActivityOptionsCompat makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
+    method public void requestUsageTimeReport(android.app.PendingIntent);
+    method public androidx.core.app.ActivityOptionsCompat setLaunchBounds(android.graphics.Rect?);
+    method public android.os.Bundle? toBundle();
+    method public void update(androidx.core.app.ActivityOptionsCompat);
+    field public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
+    field public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
+  }
+
+  public final class AlarmManagerCompat {
+    method public static void setAlarmClock(android.app.AlarmManager, long, android.app.PendingIntent, android.app.PendingIntent);
+    method public static void setAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+    method public static void setExact(android.app.AlarmManager, int, long, android.app.PendingIntent);
+    method public static void setExactAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+  }
+
+  @RequiresApi(28) public class AppComponentFactory extends android.app.AppComponentFactory {
+    ctor public AppComponentFactory();
+    method public final android.app.Activity instantiateActivity(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.app.Activity instantiateActivityCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public final android.app.Application instantiateApplication(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.app.Application instantiateApplicationCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public final android.content.ContentProvider instantiateProvider(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.content.ContentProvider instantiateProviderCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public final android.content.BroadcastReceiver instantiateReceiver(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.content.BroadcastReceiver instantiateReceiverCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public final android.app.Service instantiateService(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.app.Service instantiateServiceCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+  }
+
+  public class AppLaunchChecker {
+    ctor @Deprecated public AppLaunchChecker();
+    method public static boolean hasStartedFromLauncher(android.content.Context);
+    method public static void onActivityCreate(android.app.Activity);
+  }
+
+  public final class AppOpsManagerCompat {
+    method public static int noteOp(android.content.Context, String, int, String);
+    method public static int noteOpNoThrow(android.content.Context, String, int, String);
+    method public static int noteProxyOp(android.content.Context, String, String);
+    method public static int noteProxyOpNoThrow(android.content.Context, String, String);
+    method public static String? permissionToOp(String);
+    field public static final int MODE_ALLOWED = 0; // 0x0
+    field public static final int MODE_DEFAULT = 3; // 0x3
+    field public static final int MODE_ERRORED = 2; // 0x2
+    field public static final int MODE_IGNORED = 1; // 0x1
+  }
+
+  public final class BundleCompat {
+    method public static android.os.IBinder? getBinder(android.os.Bundle, String?);
+    method public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
+  }
+
+  public class DialogCompat {
+    method public static android.view.View requireViewById(android.app.Dialog, int);
+  }
+
+  public class FrameMetricsAggregator {
+    ctor public FrameMetricsAggregator();
+    ctor public FrameMetricsAggregator(int);
+    method public void add(android.app.Activity);
+    method public android.util.SparseIntArray![]? getMetrics();
+    method public android.util.SparseIntArray![]? remove(android.app.Activity);
+    method public android.util.SparseIntArray![]? reset();
+    method public android.util.SparseIntArray![]? stop();
+    field public static final int ANIMATION_DURATION = 256; // 0x100
+    field public static final int ANIMATION_INDEX = 8; // 0x8
+    field public static final int COMMAND_DURATION = 32; // 0x20
+    field public static final int COMMAND_INDEX = 5; // 0x5
+    field public static final int DELAY_DURATION = 128; // 0x80
+    field public static final int DELAY_INDEX = 7; // 0x7
+    field public static final int DRAW_DURATION = 8; // 0x8
+    field public static final int DRAW_INDEX = 3; // 0x3
+    field public static final int EVERY_DURATION = 511; // 0x1ff
+    field public static final int INPUT_DURATION = 2; // 0x2
+    field public static final int INPUT_INDEX = 1; // 0x1
+    field public static final int LAYOUT_MEASURE_DURATION = 4; // 0x4
+    field public static final int LAYOUT_MEASURE_INDEX = 2; // 0x2
+    field public static final int SWAP_DURATION = 64; // 0x40
+    field public static final int SWAP_INDEX = 6; // 0x6
+    field public static final int SYNC_DURATION = 16; // 0x10
+    field public static final int SYNC_INDEX = 4; // 0x4
+    field public static final int TOTAL_DURATION = 1; // 0x1
+    field public static final int TOTAL_INDEX = 0; // 0x0
+  }
+
+  public abstract class JobIntentService extends android.app.Service {
+    ctor public JobIntentService();
+    method public static void enqueueWork(android.content.Context, Class<?>, int, android.content.Intent);
+    method public static void enqueueWork(android.content.Context, android.content.ComponentName, int, android.content.Intent);
+    method public boolean isStopped();
+    method public android.os.IBinder! onBind(android.content.Intent);
+    method protected abstract void onHandleWork(android.content.Intent);
+    method public boolean onStopCurrentWork();
+    method public void setInterruptIfStopped(boolean);
+  }
+
+  public final class NavUtils {
+    method public static android.content.Intent? getParentActivityIntent(android.app.Activity);
+    method public static android.content.Intent? getParentActivityIntent(android.content.Context, Class<?>) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static android.content.Intent? getParentActivityIntent(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static String? getParentActivityName(android.app.Activity);
+    method public static String? getParentActivityName(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static void navigateUpFromSameTask(android.app.Activity);
+    method public static void navigateUpTo(android.app.Activity, android.content.Intent);
+    method public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
+    field public static final String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
+  }
+
+  public class NotificationChannelCompat {
+    method public boolean canBubble();
+    method public boolean canBypassDnd();
+    method public boolean canShowBadge();
+    method public android.media.AudioAttributes? getAudioAttributes();
+    method public String? getConversationId();
+    method public String? getDescription();
+    method public String? getGroup();
+    method public String getId();
+    method public int getImportance();
+    method public int getLightColor();
+    method public int getLockscreenVisibility();
+    method public CharSequence? getName();
+    method public String? getParentChannelId();
+    method public android.net.Uri? getSound();
+    method public long[]? getVibrationPattern();
+    method public boolean isImportantConversation();
+    method public boolean shouldShowLights();
+    method public boolean shouldVibrate();
+    method public androidx.core.app.NotificationChannelCompat.Builder toBuilder();
+    field public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
+  }
+
+  public static class NotificationChannelCompat.Builder {
+    ctor public NotificationChannelCompat.Builder(String, int);
+    method public androidx.core.app.NotificationChannelCompat build();
+    method public androidx.core.app.NotificationChannelCompat.Builder setConversationId(String, String);
+    method public androidx.core.app.NotificationChannelCompat.Builder setDescription(String?);
+    method public androidx.core.app.NotificationChannelCompat.Builder setGroup(String?);
+    method public androidx.core.app.NotificationChannelCompat.Builder setImportance(int);
+    method public androidx.core.app.NotificationChannelCompat.Builder setLightColor(int);
+    method public androidx.core.app.NotificationChannelCompat.Builder setLightsEnabled(boolean);
+    method public androidx.core.app.NotificationChannelCompat.Builder setName(CharSequence?);
+    method public androidx.core.app.NotificationChannelCompat.Builder setShowBadge(boolean);
+    method public androidx.core.app.NotificationChannelCompat.Builder setSound(android.net.Uri?, android.media.AudioAttributes?);
+    method public androidx.core.app.NotificationChannelCompat.Builder setVibrationEnabled(boolean);
+    method public androidx.core.app.NotificationChannelCompat.Builder setVibrationPattern(long[]?);
+  }
+
+  public class NotificationChannelGroupCompat {
+    method public java.util.List<androidx.core.app.NotificationChannelCompat!> getChannels();
+    method public String? getDescription();
+    method public String getId();
+    method public CharSequence? getName();
+    method public boolean isBlocked();
+    method public androidx.core.app.NotificationChannelGroupCompat.Builder toBuilder();
+  }
+
+  public static class NotificationChannelGroupCompat.Builder {
+    ctor public NotificationChannelGroupCompat.Builder(String);
+    method public androidx.core.app.NotificationChannelGroupCompat build();
+    method public androidx.core.app.NotificationChannelGroupCompat.Builder setDescription(String?);
+    method public androidx.core.app.NotificationChannelGroupCompat.Builder setName(CharSequence?);
+  }
+
+  public class NotificationCompat {
+    ctor @Deprecated public NotificationCompat();
+    method public static androidx.core.app.NotificationCompat.Action? getAction(android.app.Notification, int);
+    method public static int getActionCount(android.app.Notification);
+    method public static boolean getAllowSystemGeneratedContextualActions(android.app.Notification);
+    method public static boolean getAutoCancel(android.app.Notification);
+    method public static int getBadgeIconType(android.app.Notification);
+    method public static androidx.core.app.NotificationCompat.BubbleMetadata? getBubbleMetadata(android.app.Notification);
+    method public static String? getCategory(android.app.Notification);
+    method public static String? getChannelId(android.app.Notification);
+    method public static int getColor(android.app.Notification);
+    method @RequiresApi(19) public static CharSequence? getContentInfo(android.app.Notification);
+    method @RequiresApi(19) public static CharSequence? getContentText(android.app.Notification);
+    method @RequiresApi(19) public static CharSequence? getContentTitle(android.app.Notification);
+    method public static android.os.Bundle? getExtras(android.app.Notification);
+    method public static String? getGroup(android.app.Notification);
+    method public static int getGroupAlertBehavior(android.app.Notification);
+    method @RequiresApi(21) public static java.util.List<androidx.core.app.NotificationCompat.Action!> getInvisibleActions(android.app.Notification);
+    method public static boolean getLocalOnly(android.app.Notification);
+    method public static androidx.core.content.LocusIdCompat? getLocusId(android.app.Notification);
+    method public static boolean getOngoing(android.app.Notification);
+    method public static boolean getOnlyAlertOnce(android.app.Notification);
+    method public static java.util.List<androidx.core.app.Person!> getPeople(android.app.Notification);
+    method public static android.app.Notification? getPublicVersion(android.app.Notification);
+    method public static CharSequence? getSettingsText(android.app.Notification);
+    method public static String? getShortcutId(android.app.Notification);
+    method @RequiresApi(19) public static boolean getShowWhen(android.app.Notification);
+    method public static String? getSortKey(android.app.Notification);
+    method @RequiresApi(19) public static CharSequence? getSubText(android.app.Notification);
+    method public static long getTimeoutAfter(android.app.Notification);
+    method @RequiresApi(19) public static boolean getUsesChronometer(android.app.Notification);
+    method public static int getVisibility(android.app.Notification);
+    method public static boolean isGroupSummary(android.app.Notification);
+    field public static final int BADGE_ICON_LARGE = 2; // 0x2
+    field public static final int BADGE_ICON_NONE = 0; // 0x0
+    field public static final int BADGE_ICON_SMALL = 1; // 0x1
+    field public static final String CATEGORY_ALARM = "alarm";
+    field public static final String CATEGORY_CALL = "call";
+    field public static final String CATEGORY_EMAIL = "email";
+    field public static final String CATEGORY_ERROR = "err";
+    field public static final String CATEGORY_EVENT = "event";
+    field public static final String CATEGORY_LOCATION_SHARING = "location_sharing";
+    field public static final String CATEGORY_MESSAGE = "msg";
+    field public static final String CATEGORY_MISSED_CALL = "missed_call";
+    field public static final String CATEGORY_NAVIGATION = "navigation";
+    field public static final String CATEGORY_PROGRESS = "progress";
+    field public static final String CATEGORY_PROMO = "promo";
+    field public static final String CATEGORY_RECOMMENDATION = "recommendation";
+    field public static final String CATEGORY_REMINDER = "reminder";
+    field public static final String CATEGORY_SERVICE = "service";
+    field public static final String CATEGORY_SOCIAL = "social";
+    field public static final String CATEGORY_STATUS = "status";
+    field public static final String CATEGORY_STOPWATCH = "stopwatch";
+    field public static final String CATEGORY_SYSTEM = "sys";
+    field public static final String CATEGORY_TRANSPORT = "transport";
+    field public static final String CATEGORY_WORKOUT = "workout";
+    field @ColorInt public static final int COLOR_DEFAULT = 0; // 0x0
+    field public static final int DEFAULT_ALL = -1; // 0xffffffff
+    field public static final int DEFAULT_LIGHTS = 4; // 0x4
+    field public static final int DEFAULT_SOUND = 1; // 0x1
+    field public static final int DEFAULT_VIBRATE = 2; // 0x2
+    field public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
+    field public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
+    field public static final String EXTRA_BIG_TEXT = "android.bigText";
+    field public static final String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
+    field public static final String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID";
+    field public static final String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
+    field public static final String EXTRA_COLORIZED = "android.colorized";
+    field public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+    field public static final String EXTRA_COMPAT_TEMPLATE = "androidx.core.app.extra.COMPAT_TEMPLATE";
+    field public static final String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+    field public static final String EXTRA_HIDDEN_CONVERSATION_TITLE = "android.hiddenConversationTitle";
+    field public static final String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
+    field public static final String EXTRA_INFO_TEXT = "android.infoText";
+    field public static final String EXTRA_IS_GROUP_CONVERSATION = "android.isGroupConversation";
+    field public static final String EXTRA_LARGE_ICON = "android.largeIcon";
+    field public static final String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
+    field public static final String EXTRA_MEDIA_SESSION = "android.mediaSession";
+    field public static final String EXTRA_MESSAGES = "android.messages";
+    field public static final String EXTRA_MESSAGING_STYLE_USER = "android.messagingStyleUser";
+    field public static final String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID";
+    field public static final String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG";
+    field @Deprecated public static final String EXTRA_PEOPLE = "android.people";
+    field public static final String EXTRA_PEOPLE_LIST = "android.people.list";
+    field public static final String EXTRA_PICTURE = "android.picture";
+    field public static final String EXTRA_PROGRESS = "android.progress";
+    field public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+    field public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
+    field public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
+    field public static final String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
+    field public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+    field public static final String EXTRA_SHOW_WHEN = "android.showWhen";
+    field public static final String EXTRA_SMALL_ICON = "android.icon";
+    field public static final String EXTRA_SUB_TEXT = "android.subText";
+    field public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
+    field public static final String EXTRA_TEMPLATE = "android.template";
+    field public static final String EXTRA_TEXT = "android.text";
+    field public static final String EXTRA_TEXT_LINES = "android.textLines";
+    field public static final String EXTRA_TITLE = "android.title";
+    field public static final String EXTRA_TITLE_BIG = "android.title.big";
+    field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
+    field public static final int FLAG_BUBBLE = 4096; // 0x1000
+    field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
+    field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
+    field @Deprecated public static final int FLAG_HIGH_PRIORITY = 128; // 0x80
+    field public static final int FLAG_INSISTENT = 4; // 0x4
+    field public static final int FLAG_LOCAL_ONLY = 256; // 0x100
+    field public static final int FLAG_NO_CLEAR = 32; // 0x20
+    field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
+    field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
+    field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+    field public static final int GROUP_ALERT_ALL = 0; // 0x0
+    field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
+    field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
+    field public static final String GROUP_KEY_SILENT = "silent";
+    field public static final String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
+    field public static final int PRIORITY_DEFAULT = 0; // 0x0
+    field public static final int PRIORITY_HIGH = 1; // 0x1
+    field public static final int PRIORITY_LOW = -1; // 0xffffffff
+    field public static final int PRIORITY_MAX = 2; // 0x2
+    field public static final int PRIORITY_MIN = -2; // 0xfffffffe
+    field public static final int STREAM_DEFAULT = -1; // 0xffffffff
+    field public static final int VISIBILITY_PRIVATE = 0; // 0x0
+    field public static final int VISIBILITY_PUBLIC = 1; // 0x1
+    field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
+  }
+
+  public static class NotificationCompat.Action {
+    ctor public NotificationCompat.Action(int, CharSequence?, android.app.PendingIntent?);
+    ctor public NotificationCompat.Action(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+    method public android.app.PendingIntent? getActionIntent();
+    method public boolean getAllowGeneratedReplies();
+    method public androidx.core.app.RemoteInput![]? getDataOnlyRemoteInputs();
+    method public android.os.Bundle getExtras();
+    method @Deprecated public int getIcon();
+    method public androidx.core.graphics.drawable.IconCompat? getIconCompat();
+    method public androidx.core.app.RemoteInput![]? getRemoteInputs();
+    method @androidx.core.app.NotificationCompat.Action.SemanticAction public int getSemanticAction();
+    method public boolean getShowsUserInterface();
+    method public CharSequence? getTitle();
+    method public boolean isContextual();
+    field public static final int SEMANTIC_ACTION_ARCHIVE = 5; // 0x5
+    field public static final int SEMANTIC_ACTION_CALL = 10; // 0xa
+    field public static final int SEMANTIC_ACTION_DELETE = 4; // 0x4
+    field public static final int SEMANTIC_ACTION_MARK_AS_READ = 2; // 0x2
+    field public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3; // 0x3
+    field public static final int SEMANTIC_ACTION_MUTE = 6; // 0x6
+    field public static final int SEMANTIC_ACTION_NONE = 0; // 0x0
+    field public static final int SEMANTIC_ACTION_REPLY = 1; // 0x1
+    field public static final int SEMANTIC_ACTION_THUMBS_DOWN = 9; // 0x9
+    field public static final int SEMANTIC_ACTION_THUMBS_UP = 8; // 0x8
+    field public static final int SEMANTIC_ACTION_UNMUTE = 7; // 0x7
+    field public android.app.PendingIntent! actionIntent;
+    field @Deprecated public int icon;
+    field public CharSequence! title;
+  }
+
+  public static final class NotificationCompat.Action.Builder {
+    ctor public NotificationCompat.Action.Builder(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+    ctor public NotificationCompat.Action.Builder(int, CharSequence?, android.app.PendingIntent?);
+    ctor public NotificationCompat.Action.Builder(androidx.core.app.NotificationCompat.Action);
+    method public androidx.core.app.NotificationCompat.Action.Builder addExtras(android.os.Bundle?);
+    method public androidx.core.app.NotificationCompat.Action.Builder addRemoteInput(androidx.core.app.RemoteInput?);
+    method public androidx.core.app.NotificationCompat.Action build();
+    method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Extender);
+    method public android.os.Bundle getExtras();
+    method public androidx.core.app.NotificationCompat.Action.Builder setAllowGeneratedReplies(boolean);
+    method public androidx.core.app.NotificationCompat.Action.Builder setContextual(boolean);
+    method public androidx.core.app.NotificationCompat.Action.Builder setSemanticAction(@androidx.core.app.NotificationCompat.Action.SemanticAction int);
+    method public androidx.core.app.NotificationCompat.Action.Builder setShowsUserInterface(boolean);
+  }
+
+  public static interface NotificationCompat.Action.Extender {
+    method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+  }
+
+  @IntDef({androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_NONE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_REPLY, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_UNREAD, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_DELETE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_ARCHIVE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_UNMUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_UP, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_DOWN, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_CALL}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.Action.SemanticAction {
+  }
+
+  public static final class NotificationCompat.Action.WearableExtender implements androidx.core.app.NotificationCompat.Action.Extender {
+    ctor public NotificationCompat.Action.WearableExtender();
+    ctor public NotificationCompat.Action.WearableExtender(androidx.core.app.NotificationCompat.Action);
+    method public androidx.core.app.NotificationCompat.Action.WearableExtender clone();
+    method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+    method @Deprecated public CharSequence? getCancelLabel();
+    method @Deprecated public CharSequence? getConfirmLabel();
+    method public boolean getHintDisplayActionInline();
+    method public boolean getHintLaunchesActivity();
+    method @Deprecated public CharSequence? getInProgressLabel();
+    method public boolean isAvailableOffline();
+    method public androidx.core.app.NotificationCompat.Action.WearableExtender setAvailableOffline(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setCancelLabel(CharSequence?);
+    method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setConfirmLabel(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintDisplayActionInline(boolean);
+    method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintLaunchesActivity(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setInProgressLabel(CharSequence?);
+  }
+
+  public static class NotificationCompat.BigPictureStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor public NotificationCompat.BigPictureStyle();
+    ctor public NotificationCompat.BigPictureStyle(androidx.core.app.NotificationCompat.Builder?);
+    method public androidx.core.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.Bitmap?);
+    method public androidx.core.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.Bitmap?);
+    method public androidx.core.app.NotificationCompat.BigPictureStyle setBigContentTitle(CharSequence?);
+    method public androidx.core.app.NotificationCompat.BigPictureStyle setSummaryText(CharSequence?);
+  }
+
+  public static class NotificationCompat.BigTextStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor public NotificationCompat.BigTextStyle();
+    ctor public NotificationCompat.BigTextStyle(androidx.core.app.NotificationCompat.Builder?);
+    method public androidx.core.app.NotificationCompat.BigTextStyle bigText(CharSequence?);
+    method public androidx.core.app.NotificationCompat.BigTextStyle setBigContentTitle(CharSequence?);
+    method public androidx.core.app.NotificationCompat.BigTextStyle setSummaryText(CharSequence?);
+  }
+
+  public static final class NotificationCompat.BubbleMetadata {
+    method public static androidx.core.app.NotificationCompat.BubbleMetadata? fromPlatform(android.app.Notification.BubbleMetadata?);
+    method public boolean getAutoExpandBubble();
+    method public android.app.PendingIntent? getDeleteIntent();
+    method @Dimension(unit=androidx.annotation.Dimension.DP) public int getDesiredHeight();
+    method @DimenRes public int getDesiredHeightResId();
+    method public androidx.core.graphics.drawable.IconCompat? getIcon();
+    method public android.app.PendingIntent? getIntent();
+    method public String? getShortcutId();
+    method public boolean isNotificationSuppressed();
+    method public static android.app.Notification.BubbleMetadata? toPlatform(androidx.core.app.NotificationCompat.BubbleMetadata?);
+  }
+
+  public static final class NotificationCompat.BubbleMetadata.Builder {
+    ctor @Deprecated public NotificationCompat.BubbleMetadata.Builder();
+    ctor @RequiresApi(30) public NotificationCompat.BubbleMetadata.Builder(String);
+    ctor public NotificationCompat.BubbleMetadata.Builder(android.app.PendingIntent, androidx.core.graphics.drawable.IconCompat);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata build();
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setAutoExpandBubble(boolean);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDeleteIntent(android.app.PendingIntent?);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeight(@Dimension(unit=androidx.annotation.Dimension.DP) int);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIcon(androidx.core.graphics.drawable.IconCompat);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIntent(android.app.PendingIntent);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setSuppressNotification(boolean);
+  }
+
+  public static class NotificationCompat.Builder {
+    ctor @RequiresApi(19) public NotificationCompat.Builder(android.content.Context, android.app.Notification);
+    ctor public NotificationCompat.Builder(android.content.Context, String);
+    ctor @Deprecated public NotificationCompat.Builder(android.content.Context);
+    method public androidx.core.app.NotificationCompat.Builder addAction(int, CharSequence?, android.app.PendingIntent?);
+    method public androidx.core.app.NotificationCompat.Builder addAction(androidx.core.app.NotificationCompat.Action?);
+    method public androidx.core.app.NotificationCompat.Builder addExtras(android.os.Bundle?);
+    method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(int, CharSequence?, android.app.PendingIntent?);
+    method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(androidx.core.app.NotificationCompat.Action?);
+    method @Deprecated public androidx.core.app.NotificationCompat.Builder addPerson(String?);
+    method public androidx.core.app.NotificationCompat.Builder addPerson(androidx.core.app.Person?);
+    method public android.app.Notification build();
+    method public androidx.core.app.NotificationCompat.Builder clearActions();
+    method public androidx.core.app.NotificationCompat.Builder clearInvisibleActions();
+    method public androidx.core.app.NotificationCompat.Builder clearPeople();
+    method public android.widget.RemoteViews? createBigContentView();
+    method public android.widget.RemoteViews? createContentView();
+    method public android.widget.RemoteViews? createHeadsUpContentView();
+    method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Extender);
+    method public android.os.Bundle getExtras();
+    method @Deprecated public android.app.Notification getNotification();
+    method protected static CharSequence? limitCharSequenceLength(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setAllowSystemGeneratedContextualActions(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setAutoCancel(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setBadgeIconType(int);
+    method public androidx.core.app.NotificationCompat.Builder setBubbleMetadata(androidx.core.app.NotificationCompat.BubbleMetadata?);
+    method public androidx.core.app.NotificationCompat.Builder setCategory(String?);
+    method public androidx.core.app.NotificationCompat.Builder setChannelId(String);
+    method @RequiresApi(24) public androidx.core.app.NotificationCompat.Builder setChronometerCountDown(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setColor(@ColorInt int);
+    method public androidx.core.app.NotificationCompat.Builder setColorized(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setContent(android.widget.RemoteViews?);
+    method public androidx.core.app.NotificationCompat.Builder setContentInfo(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setContentIntent(android.app.PendingIntent?);
+    method public androidx.core.app.NotificationCompat.Builder setContentText(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setContentTitle(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setCustomBigContentView(android.widget.RemoteViews?);
+    method public androidx.core.app.NotificationCompat.Builder setCustomContentView(android.widget.RemoteViews?);
+    method public androidx.core.app.NotificationCompat.Builder setCustomHeadsUpContentView(android.widget.RemoteViews?);
+    method public androidx.core.app.NotificationCompat.Builder setDefaults(int);
+    method public androidx.core.app.NotificationCompat.Builder setDeleteIntent(android.app.PendingIntent?);
+    method public androidx.core.app.NotificationCompat.Builder setExtras(android.os.Bundle?);
+    method public androidx.core.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent?, boolean);
+    method public androidx.core.app.NotificationCompat.Builder setGroup(String?);
+    method public androidx.core.app.NotificationCompat.Builder setGroupAlertBehavior(int);
+    method public androidx.core.app.NotificationCompat.Builder setGroupSummary(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setLargeIcon(android.graphics.Bitmap?);
+    method public androidx.core.app.NotificationCompat.Builder setLights(@ColorInt int, int, int);
+    method public androidx.core.app.NotificationCompat.Builder setLocalOnly(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+    method @Deprecated public androidx.core.app.NotificationCompat.Builder setNotificationSilent();
+    method public androidx.core.app.NotificationCompat.Builder setNumber(int);
+    method public androidx.core.app.NotificationCompat.Builder setOngoing(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setOnlyAlertOnce(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setPriority(int);
+    method public androidx.core.app.NotificationCompat.Builder setProgress(int, int, boolean);
+    method public androidx.core.app.NotificationCompat.Builder setPublicVersion(android.app.Notification?);
+    method public androidx.core.app.NotificationCompat.Builder setRemoteInputHistory(CharSequence![]?);
+    method public androidx.core.app.NotificationCompat.Builder setSettingsText(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setShortcutId(String?);
+    method public androidx.core.app.NotificationCompat.Builder setShortcutInfo(androidx.core.content.pm.ShortcutInfoCompat?);
+    method public androidx.core.app.NotificationCompat.Builder setShowWhen(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setSilent(boolean);
+    method @RequiresApi(23) public androidx.core.app.NotificationCompat.Builder setSmallIcon(androidx.core.graphics.drawable.IconCompat);
+    method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int);
+    method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int, int);
+    method public androidx.core.app.NotificationCompat.Builder setSortKey(String?);
+    method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?);
+    method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?, int);
+    method public androidx.core.app.NotificationCompat.Builder setStyle(androidx.core.app.NotificationCompat.Style?);
+    method public androidx.core.app.NotificationCompat.Builder setSubText(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?);
+    method @Deprecated public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?, android.widget.RemoteViews?);
+    method public androidx.core.app.NotificationCompat.Builder setTimeoutAfter(long);
+    method public androidx.core.app.NotificationCompat.Builder setUsesChronometer(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setVibrate(long[]?);
+    method public androidx.core.app.NotificationCompat.Builder setVisibility(int);
+    method public androidx.core.app.NotificationCompat.Builder setWhen(long);
+    field @Deprecated public java.util.ArrayList<java.lang.String!>! mPeople;
+  }
+
+  public static final class NotificationCompat.CarExtender implements androidx.core.app.NotificationCompat.Extender {
+    ctor public NotificationCompat.CarExtender();
+    ctor public NotificationCompat.CarExtender(android.app.Notification);
+    method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+    method @ColorInt public int getColor();
+    method public android.graphics.Bitmap? getLargeIcon();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation? getUnreadConversation();
+    method public androidx.core.app.NotificationCompat.CarExtender setColor(@ColorInt int);
+    method public androidx.core.app.NotificationCompat.CarExtender setLargeIcon(android.graphics.Bitmap?);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation?);
+  }
+
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+    method @Deprecated public long getLatestTimestamp();
+    method @Deprecated public String![]? getMessages();
+    method @Deprecated public String? getParticipant();
+    method @Deprecated public String![]? getParticipants();
+    method @Deprecated public android.app.PendingIntent? getReadPendingIntent();
+    method @Deprecated public androidx.core.app.RemoteInput? getRemoteInput();
+    method @Deprecated public android.app.PendingIntent? getReplyPendingIntent();
+  }
+
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+    ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder addMessage(String?);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation build();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setLatestTimestamp(long);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReadPendingIntent(android.app.PendingIntent?);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReplyAction(android.app.PendingIntent?, androidx.core.app.RemoteInput?);
+  }
+
+  public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor public NotificationCompat.DecoratedCustomViewStyle();
+  }
+
+  public static interface NotificationCompat.Extender {
+    method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+  }
+
+  public static class NotificationCompat.InboxStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor public NotificationCompat.InboxStyle();
+    ctor public NotificationCompat.InboxStyle(androidx.core.app.NotificationCompat.Builder?);
+    method public androidx.core.app.NotificationCompat.InboxStyle addLine(CharSequence?);
+    method public androidx.core.app.NotificationCompat.InboxStyle setBigContentTitle(CharSequence?);
+    method public androidx.core.app.NotificationCompat.InboxStyle setSummaryText(CharSequence?);
+  }
+
+  public static class NotificationCompat.MessagingStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor @Deprecated public NotificationCompat.MessagingStyle(CharSequence);
+    ctor public NotificationCompat.MessagingStyle(androidx.core.app.Person);
+    method public void addCompatExtras(android.os.Bundle);
+    method public androidx.core.app.NotificationCompat.MessagingStyle addHistoricMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+    method @Deprecated public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, CharSequence?);
+    method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, androidx.core.app.Person?);
+    method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+    method public static androidx.core.app.NotificationCompat.MessagingStyle? extractMessagingStyleFromNotification(android.app.Notification);
+    method public CharSequence? getConversationTitle();
+    method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getHistoricMessages();
+    method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getMessages();
+    method public androidx.core.app.Person getUser();
+    method @Deprecated public CharSequence? getUserDisplayName();
+    method public boolean isGroupConversation();
+    method public androidx.core.app.NotificationCompat.MessagingStyle setConversationTitle(CharSequence?);
+    method public androidx.core.app.NotificationCompat.MessagingStyle setGroupConversation(boolean);
+    field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19
+  }
+
+  public static final class NotificationCompat.MessagingStyle.Message {
+    ctor public NotificationCompat.MessagingStyle.Message(CharSequence?, long, androidx.core.app.Person?);
+    ctor @Deprecated public NotificationCompat.MessagingStyle.Message(CharSequence?, long, CharSequence?);
+    method public String? getDataMimeType();
+    method public android.net.Uri? getDataUri();
+    method public android.os.Bundle getExtras();
+    method public androidx.core.app.Person? getPerson();
+    method @Deprecated public CharSequence? getSender();
+    method public CharSequence? getText();
+    method public long getTimestamp();
+    method public androidx.core.app.NotificationCompat.MessagingStyle.Message setData(String?, android.net.Uri?);
+  }
+
+  public abstract static class NotificationCompat.Style {
+    ctor public NotificationCompat.Style();
+    method public android.app.Notification? build();
+    method public void setBuilder(androidx.core.app.NotificationCompat.Builder?);
+  }
+
+  public static final class NotificationCompat.WearableExtender implements androidx.core.app.NotificationCompat.Extender {
+    ctor public NotificationCompat.WearableExtender();
+    ctor public NotificationCompat.WearableExtender(android.app.Notification);
+    method public androidx.core.app.NotificationCompat.WearableExtender addAction(androidx.core.app.NotificationCompat.Action);
+    method public androidx.core.app.NotificationCompat.WearableExtender addActions(java.util.List<androidx.core.app.NotificationCompat.Action!>);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPage(android.app.Notification);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPages(java.util.List<android.app.Notification!>);
+    method public androidx.core.app.NotificationCompat.WearableExtender clearActions();
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender clearPages();
+    method public androidx.core.app.NotificationCompat.WearableExtender clone();
+    method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+    method public java.util.List<androidx.core.app.NotificationCompat.Action!> getActions();
+    method @Deprecated public android.graphics.Bitmap? getBackground();
+    method public String? getBridgeTag();
+    method public int getContentAction();
+    method @Deprecated public int getContentIcon();
+    method @Deprecated public int getContentIconGravity();
+    method public boolean getContentIntentAvailableOffline();
+    method @Deprecated public int getCustomContentHeight();
+    method @Deprecated public int getCustomSizePreset();
+    method public String? getDismissalId();
+    method @Deprecated public android.app.PendingIntent? getDisplayIntent();
+    method @Deprecated public int getGravity();
+    method @Deprecated public boolean getHintAmbientBigPicture();
+    method @Deprecated public boolean getHintAvoidBackgroundClipping();
+    method public boolean getHintContentIntentLaunchesActivity();
+    method @Deprecated public boolean getHintHideIcon();
+    method @Deprecated public int getHintScreenTimeout();
+    method @Deprecated public boolean getHintShowBackgroundOnly();
+    method @Deprecated public java.util.List<android.app.Notification!> getPages();
+    method public boolean getStartScrollBottom();
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setBackground(android.graphics.Bitmap?);
+    method public androidx.core.app.NotificationCompat.WearableExtender setBridgeTag(String?);
+    method public androidx.core.app.NotificationCompat.WearableExtender setContentAction(int);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIcon(int);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIconGravity(int);
+    method public androidx.core.app.NotificationCompat.WearableExtender setContentIntentAvailableOffline(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomContentHeight(int);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomSizePreset(int);
+    method public androidx.core.app.NotificationCompat.WearableExtender setDismissalId(String?);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setDisplayIntent(android.app.PendingIntent?);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setGravity(int);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAmbientBigPicture(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAvoidBackgroundClipping(boolean);
+    method public androidx.core.app.NotificationCompat.WearableExtender setHintContentIntentLaunchesActivity(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintHideIcon(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintScreenTimeout(int);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintShowBackgroundOnly(boolean);
+    method public androidx.core.app.NotificationCompat.WearableExtender setStartScrollBottom(boolean);
+    field @Deprecated public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+    field @Deprecated public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
+    field @Deprecated public static final int SIZE_DEFAULT = 0; // 0x0
+    field @Deprecated public static final int SIZE_FULL_SCREEN = 5; // 0x5
+    field @Deprecated public static final int SIZE_LARGE = 4; // 0x4
+    field @Deprecated public static final int SIZE_MEDIUM = 3; // 0x3
+    field @Deprecated public static final int SIZE_SMALL = 2; // 0x2
+    field @Deprecated public static final int SIZE_XSMALL = 1; // 0x1
+    field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
+  }
+
+  public final class NotificationCompatExtras {
+    field public static final String EXTRA_ACTION_EXTRAS = "android.support.actionExtras";
+    field public static final String EXTRA_GROUP_KEY = "android.support.groupKey";
+    field public static final String EXTRA_GROUP_SUMMARY = "android.support.isGroupSummary";
+    field public static final String EXTRA_LOCAL_ONLY = "android.support.localOnly";
+    field public static final String EXTRA_REMOTE_INPUTS = "android.support.remoteInputs";
+    field public static final String EXTRA_SORT_KEY = "android.support.sortKey";
+  }
+
+  public abstract class NotificationCompatSideChannelService extends android.app.Service {
+    ctor public NotificationCompatSideChannelService();
+    method public abstract void cancel(String!, int, String!);
+    method public abstract void cancelAll(String!);
+    method public abstract void notify(String!, int, String!, android.app.Notification!);
+    method public android.os.IBinder! onBind(android.content.Intent!);
+  }
+
+  public final class NotificationManagerCompat {
+    method public boolean areNotificationsEnabled();
+    method public void cancel(int);
+    method public void cancel(String?, int);
+    method public void cancelAll();
+    method public void createNotificationChannel(android.app.NotificationChannel);
+    method public void createNotificationChannel(androidx.core.app.NotificationChannelCompat);
+    method public void createNotificationChannelGroup(android.app.NotificationChannelGroup);
+    method public void createNotificationChannelGroup(androidx.core.app.NotificationChannelGroupCompat);
+    method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup!>);
+    method public void createNotificationChannelGroupsCompat(java.util.List<androidx.core.app.NotificationChannelGroupCompat!>);
+    method public void createNotificationChannels(java.util.List<android.app.NotificationChannel!>);
+    method public void createNotificationChannelsCompat(java.util.List<androidx.core.app.NotificationChannelCompat!>);
+    method public void deleteNotificationChannel(String);
+    method public void deleteNotificationChannelGroup(String);
+    method public void deleteUnlistedNotificationChannels(java.util.Collection<java.lang.String!>);
+    method public static androidx.core.app.NotificationManagerCompat from(android.content.Context);
+    method public static java.util.Set<java.lang.String!> getEnabledListenerPackages(android.content.Context);
+    method public int getImportance();
+    method public android.app.NotificationChannel? getNotificationChannel(String);
+    method public android.app.NotificationChannel? getNotificationChannel(String, String);
+    method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String);
+    method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String, String);
+    method public android.app.NotificationChannelGroup? getNotificationChannelGroup(String);
+    method public androidx.core.app.NotificationChannelGroupCompat? getNotificationChannelGroupCompat(String);
+    method public java.util.List<android.app.NotificationChannelGroup!> getNotificationChannelGroups();
+    method public java.util.List<androidx.core.app.NotificationChannelGroupCompat!> getNotificationChannelGroupsCompat();
+    method public java.util.List<android.app.NotificationChannel!> getNotificationChannels();
+    method public java.util.List<androidx.core.app.NotificationChannelCompat!> getNotificationChannelsCompat();
+    method public void notify(int, android.app.Notification);
+    method public void notify(String?, int, android.app.Notification);
+    field public static final String ACTION_BIND_SIDE_CHANNEL = "android.support.BIND_NOTIFICATION_SIDE_CHANNEL";
+    field public static final String EXTRA_USE_SIDE_CHANNEL = "android.support.useSideChannel";
+    field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+    field public static final int IMPORTANCE_HIGH = 4; // 0x4
+    field public static final int IMPORTANCE_LOW = 2; // 0x2
+    field public static final int IMPORTANCE_MAX = 5; // 0x5
+    field public static final int IMPORTANCE_MIN = 1; // 0x1
+    field public static final int IMPORTANCE_NONE = 0; // 0x0
+    field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
+  }
+
+  public class Person {
+    method public static androidx.core.app.Person fromBundle(android.os.Bundle);
+    method public androidx.core.graphics.drawable.IconCompat? getIcon();
+    method public String? getKey();
+    method public CharSequence? getName();
+    method public String? getUri();
+    method public boolean isBot();
+    method public boolean isImportant();
+    method public androidx.core.app.Person.Builder toBuilder();
+    method public android.os.Bundle toBundle();
+  }
+
+  public static class Person.Builder {
+    ctor public Person.Builder();
+    method public androidx.core.app.Person build();
+    method public androidx.core.app.Person.Builder setBot(boolean);
+    method public androidx.core.app.Person.Builder setIcon(androidx.core.graphics.drawable.IconCompat?);
+    method public androidx.core.app.Person.Builder setImportant(boolean);
+    method public androidx.core.app.Person.Builder setKey(String?);
+    method public androidx.core.app.Person.Builder setName(CharSequence?);
+    method public androidx.core.app.Person.Builder setUri(String?);
+  }
+
+  public final class RemoteActionCompat implements androidx.versionedparcelable.VersionedParcelable {
+    ctor public RemoteActionCompat(androidx.core.graphics.drawable.IconCompat, CharSequence, CharSequence, android.app.PendingIntent);
+    ctor public RemoteActionCompat(androidx.core.app.RemoteActionCompat);
+    method @RequiresApi(26) public static androidx.core.app.RemoteActionCompat createFromRemoteAction(android.app.RemoteAction);
+    method public android.app.PendingIntent getActionIntent();
+    method public CharSequence getContentDescription();
+    method public androidx.core.graphics.drawable.IconCompat getIcon();
+    method public CharSequence getTitle();
+    method public boolean isEnabled();
+    method public void setEnabled(boolean);
+    method public void setShouldShowIcon(boolean);
+    method public boolean shouldShowIcon();
+    method @RequiresApi(26) public android.app.RemoteAction toRemoteAction();
+  }
+
+  public final class RemoteInput {
+    method public static void addDataResultToIntent(androidx.core.app.RemoteInput!, android.content.Intent!, java.util.Map<java.lang.String!,android.net.Uri!>!);
+    method public static void addResultsToIntent(androidx.core.app.RemoteInput![]!, android.content.Intent!, android.os.Bundle!);
+    method public boolean getAllowFreeFormInput();
+    method public java.util.Set<java.lang.String!>! getAllowedDataTypes();
+    method public CharSequence![]! getChoices();
+    method public static java.util.Map<java.lang.String!,android.net.Uri!>! getDataResultsFromIntent(android.content.Intent!, String!);
+    method public int getEditChoicesBeforeSending();
+    method public android.os.Bundle! getExtras();
+    method public CharSequence! getLabel();
+    method public String! getResultKey();
+    method public static android.os.Bundle! getResultsFromIntent(android.content.Intent!);
+    method public static int getResultsSource(android.content.Intent);
+    method public boolean isDataOnly();
+    method public static void setResultsSource(android.content.Intent, int);
+    field public static final int EDIT_CHOICES_BEFORE_SENDING_AUTO = 0; // 0x0
+    field public static final int EDIT_CHOICES_BEFORE_SENDING_DISABLED = 1; // 0x1
+    field public static final int EDIT_CHOICES_BEFORE_SENDING_ENABLED = 2; // 0x2
+    field public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+    field public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+    field public static final int SOURCE_CHOICE = 1; // 0x1
+    field public static final int SOURCE_FREE_FORM_INPUT = 0; // 0x0
+  }
+
+  public static final class RemoteInput.Builder {
+    ctor public RemoteInput.Builder(String);
+    method public androidx.core.app.RemoteInput.Builder addExtras(android.os.Bundle);
+    method public androidx.core.app.RemoteInput build();
+    method public android.os.Bundle getExtras();
+    method public androidx.core.app.RemoteInput.Builder setAllowDataType(String, boolean);
+    method public androidx.core.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
+    method public androidx.core.app.RemoteInput.Builder setChoices(CharSequence![]?);
+    method public androidx.core.app.RemoteInput.Builder setEditChoicesBeforeSending(int);
+    method public androidx.core.app.RemoteInput.Builder setLabel(CharSequence?);
+  }
+
+  public final class ServiceCompat {
+    method public static void stopForeground(android.app.Service, int);
+    field public static final int START_STICKY = 1; // 0x1
+    field public static final int STOP_FOREGROUND_DETACH = 2; // 0x2
+    field public static final int STOP_FOREGROUND_REMOVE = 1; // 0x1
+  }
+
+  public final class ShareCompat {
+    method @Deprecated public static void configureMenuItem(android.view.MenuItem, androidx.core.app.ShareCompat.IntentBuilder);
+    method @Deprecated public static void configureMenuItem(android.view.Menu, @IdRes int, androidx.core.app.ShareCompat.IntentBuilder);
+    method public static android.content.ComponentName? getCallingActivity(android.app.Activity);
+    method public static String? getCallingPackage(android.app.Activity);
+    field public static final String EXTRA_CALLING_ACTIVITY = "androidx.core.app.EXTRA_CALLING_ACTIVITY";
+    field public static final String EXTRA_CALLING_ACTIVITY_INTEROP = "android.support.v4.app.EXTRA_CALLING_ACTIVITY";
+    field public static final String EXTRA_CALLING_PACKAGE = "androidx.core.app.EXTRA_CALLING_PACKAGE";
+    field public static final String EXTRA_CALLING_PACKAGE_INTEROP = "android.support.v4.app.EXTRA_CALLING_PACKAGE";
+  }
+
+  public static class ShareCompat.IntentBuilder {
+    ctor public ShareCompat.IntentBuilder(android.content.Context);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String![]);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String![]);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String![]);
+    method public androidx.core.app.ShareCompat.IntentBuilder addStream(android.net.Uri);
+    method public android.content.Intent createChooserIntent();
+    method @Deprecated public static androidx.core.app.ShareCompat.IntentBuilder from(android.app.Activity);
+    method public android.content.Intent getIntent();
+    method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(CharSequence?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(@StringRes int);
+    method public androidx.core.app.ShareCompat.IntentBuilder setEmailBcc(String![]?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setEmailCc(String![]?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setEmailTo(String![]?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setHtmlText(String?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setStream(android.net.Uri?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setSubject(String?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setText(CharSequence?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setType(String?);
+    method public void startChooser();
+  }
+
+  public static class ShareCompat.IntentReader {
+    ctor public ShareCompat.IntentReader(android.app.Activity);
+    ctor public ShareCompat.IntentReader(android.content.Context, android.content.Intent);
+    method @Deprecated public static androidx.core.app.ShareCompat.IntentReader from(android.app.Activity);
+    method public android.content.ComponentName? getCallingActivity();
+    method public android.graphics.drawable.Drawable? getCallingActivityIcon();
+    method public android.graphics.drawable.Drawable? getCallingApplicationIcon();
+    method public CharSequence? getCallingApplicationLabel();
+    method public String? getCallingPackage();
+    method public String![]? getEmailBcc();
+    method public String![]? getEmailCc();
+    method public String![]? getEmailTo();
+    method public String? getHtmlText();
+    method public android.net.Uri? getStream();
+    method public android.net.Uri? getStream(int);
+    method public int getStreamCount();
+    method public String? getSubject();
+    method public CharSequence? getText();
+    method public String? getType();
+    method public boolean isMultipleShare();
+    method public boolean isShareIntent();
+    method public boolean isSingleShare();
+  }
+
+  public abstract class SharedElementCallback {
+    ctor public SharedElementCallback();
+    method public android.os.Parcelable! onCaptureSharedElementSnapshot(android.view.View!, android.graphics.Matrix!, android.graphics.RectF!);
+    method public android.view.View! onCreateSnapshotView(android.content.Context!, android.os.Parcelable!);
+    method public void onMapSharedElements(java.util.List<java.lang.String!>!, java.util.Map<java.lang.String!,android.view.View!>!);
+    method public void onRejectSharedElements(java.util.List<android.view.View!>!);
+    method public void onSharedElementEnd(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+    method public void onSharedElementStart(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+    method public void onSharedElementsArrived(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, androidx.core.app.SharedElementCallback.OnSharedElementsReadyListener!);
+  }
+
+  public static interface SharedElementCallback.OnSharedElementsReadyListener {
+    method public void onSharedElementsReady();
+  }
+
+  public final class TaskStackBuilder implements java.lang.Iterable<android.content.Intent> {
+    method public androidx.core.app.TaskStackBuilder addNextIntent(android.content.Intent);
+    method public androidx.core.app.TaskStackBuilder addNextIntentWithParentStack(android.content.Intent);
+    method public androidx.core.app.TaskStackBuilder addParentStack(android.app.Activity);
+    method public androidx.core.app.TaskStackBuilder addParentStack(Class<?>);
+    method public androidx.core.app.TaskStackBuilder! addParentStack(android.content.ComponentName!);
+    method public static androidx.core.app.TaskStackBuilder create(android.content.Context);
+    method public android.content.Intent? editIntentAt(int);
+    method @Deprecated public static androidx.core.app.TaskStackBuilder! from(android.content.Context!);
+    method @Deprecated public android.content.Intent! getIntent(int);
+    method public int getIntentCount();
+    method public android.content.Intent![] getIntents();
+    method public android.app.PendingIntent? getPendingIntent(int, int);
+    method public android.app.PendingIntent? getPendingIntent(int, int, android.os.Bundle?);
+    method @Deprecated public java.util.Iterator<android.content.Intent!>! iterator();
+    method public void startActivities();
+    method public void startActivities(android.os.Bundle?);
+  }
+
+  public static interface TaskStackBuilder.SupportParentable {
+    method public android.content.Intent? getSupportParentActivityIntent();
+  }
+
+}
+
+package androidx.core.content {
+
+  public final class ContentProviderCompat {
+    method public static android.content.Context requireContext(android.content.ContentProvider);
+  }
+
+  public final class ContentResolverCompat {
+    method public static android.database.Cursor! query(android.content.ContentResolver!, android.net.Uri!, String![]!, String!, String![]!, String!, androidx.core.os.CancellationSignal!);
+  }
+
+  public class ContextCompat {
+    ctor protected ContextCompat();
+    method public static int checkSelfPermission(android.content.Context, String);
+    method public static android.content.Context? createDeviceProtectedStorageContext(android.content.Context);
+    method public static java.io.File! getCodeCacheDir(android.content.Context);
+    method @ColorInt public static int getColor(android.content.Context, @ColorRes int);
+    method public static android.content.res.ColorStateList? getColorStateList(android.content.Context, @ColorRes int);
+    method public static java.io.File? getDataDir(android.content.Context);
+    method public static android.graphics.drawable.Drawable? getDrawable(android.content.Context, @DrawableRes int);
+    method public static java.io.File![] getExternalCacheDirs(android.content.Context);
+    method public static java.io.File![] getExternalFilesDirs(android.content.Context, String?);
+    method public static java.util.concurrent.Executor! getMainExecutor(android.content.Context!);
+    method public static java.io.File? getNoBackupFilesDir(android.content.Context);
+    method public static java.io.File![] getObbDirs(android.content.Context);
+    method public static <T> T? getSystemService(android.content.Context, Class<T!>);
+    method public static String? getSystemServiceName(android.content.Context, Class<?>);
+    method public static boolean isDeviceProtectedStorage(android.content.Context);
+    method public static boolean startActivities(android.content.Context, android.content.Intent![]);
+    method public static boolean startActivities(android.content.Context, android.content.Intent![], android.os.Bundle?);
+    method public static void startActivity(android.content.Context, android.content.Intent, android.os.Bundle?);
+    method public static void startForegroundService(android.content.Context, android.content.Intent);
+  }
+
+  public class FileProvider extends android.content.ContentProvider {
+    ctor public FileProvider();
+    method public int delete(android.net.Uri, String?, String![]?);
+    method public String! getType(android.net.Uri);
+    method public static android.net.Uri! getUriForFile(android.content.Context, String, java.io.File);
+    method public static android.net.Uri getUriForFile(android.content.Context, String, java.io.File, String);
+    method public android.net.Uri! insert(android.net.Uri, android.content.ContentValues!);
+    method public boolean onCreate();
+    method public android.database.Cursor! query(android.net.Uri, String![]?, String?, String![]?, String?);
+    method public int update(android.net.Uri, android.content.ContentValues!, String?, String![]?);
+  }
+
+  public final class IntentCompat {
+    method public static android.content.Intent makeMainSelectorActivity(String, String);
+    field public static final String ACTION_CREATE_REMINDER = "android.intent.action.CREATE_REMINDER";
+    field public static final String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
+    field public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+    field public static final String EXTRA_START_PLAYBACK = "android.intent.extra.START_PLAYBACK";
+    field public static final String EXTRA_TIME = "android.intent.extra.TIME";
+  }
+
+  public final class LocusIdCompat {
+    ctor public LocusIdCompat(String);
+    method public String getId();
+    method @RequiresApi(29) public android.content.LocusId toLocusId();
+    method @RequiresApi(29) public static androidx.core.content.LocusIdCompat toLocusIdCompat(android.content.LocusId);
+  }
+
+  public final class MimeTypeFilter {
+    method public static boolean matches(String?, String);
+    method public static String? matches(String?, String![]);
+    method public static String? matches(String![]?, String);
+    method public static String![] matchesMany(String![]?, String);
+  }
+
+  public final class PermissionChecker {
+    method public static int checkCallingOrSelfPermission(android.content.Context, String);
+    method public static int checkCallingPermission(android.content.Context, String, String?);
+    method public static int checkPermission(android.content.Context, String, int, int, String?);
+    method public static int checkSelfPermission(android.content.Context, String);
+    field public static final int PERMISSION_DENIED = -1; // 0xffffffff
+    field public static final int PERMISSION_DENIED_APP_OP = -2; // 0xfffffffe
+    field public static final int PERMISSION_GRANTED = 0; // 0x0
+  }
+
+  @Deprecated public final class SharedPreferencesCompat {
+  }
+
+  @Deprecated public static final class SharedPreferencesCompat.EditorCompat {
+    method @Deprecated public void apply(android.content.SharedPreferences.Editor);
+    method @Deprecated public static androidx.core.content.SharedPreferencesCompat.EditorCompat! getInstance();
+  }
+
+}
+
+package androidx.core.content.pm {
+
+  @Deprecated public final class ActivityInfoCompat {
+    field @Deprecated public static final int CONFIG_UI_MODE = 512; // 0x200
+  }
+
+  public final class PackageInfoCompat {
+    method public static long getLongVersionCode(android.content.pm.PackageInfo);
+    method public static java.util.List<android.content.pm.Signature!> getSignatures(android.content.pm.PackageManager, String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static boolean hasSignatures(android.content.pm.PackageManager, String, @Size(min=1) java.util.Map<byte[]!,java.lang.Integer!>, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
+  }
+
+  public final class PermissionInfoCompat {
+    method public static int getProtection(android.content.pm.PermissionInfo);
+    method public static int getProtectionFlags(android.content.pm.PermissionInfo);
+  }
+
+  public class ShortcutInfoCompat {
+    method public android.content.ComponentName? getActivity();
+    method public java.util.Set<java.lang.String!>? getCategories();
+    method public CharSequence? getDisabledMessage();
+    method public int getDisabledReason();
+    method public android.os.PersistableBundle? getExtras();
+    method public String getId();
+    method public android.content.Intent getIntent();
+    method public android.content.Intent![] getIntents();
+    method public long getLastChangedTimestamp();
+    method public androidx.core.content.LocusIdCompat? getLocusId();
+    method public CharSequence? getLongLabel();
+    method public String getPackage();
+    method public int getRank();
+    method public CharSequence getShortLabel();
+    method public android.os.UserHandle? getUserHandle();
+    method public boolean hasKeyFieldsOnly();
+    method public boolean isCached();
+    method public boolean isDeclaredInManifest();
+    method public boolean isDynamic();
+    method public boolean isEnabled();
+    method public boolean isImmutable();
+    method public boolean isPinned();
+    method @RequiresApi(25) public android.content.pm.ShortcutInfo! toShortcutInfo();
+  }
+
+  public static class ShortcutInfoCompat.Builder {
+    ctor public ShortcutInfoCompat.Builder(android.content.Context, String);
+    method public androidx.core.content.pm.ShortcutInfoCompat build();
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setActivity(android.content.ComponentName);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setAlwaysBadged();
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setCategories(java.util.Set<java.lang.String!>);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setDisabledMessage(CharSequence);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setExtras(android.os.PersistableBundle);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIcon(androidx.core.graphics.drawable.IconCompat!);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntent(android.content.Intent);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntents(android.content.Intent![]);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIsConversation();
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLabel(CharSequence);
+    method @Deprecated public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived();
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived(boolean);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPerson(androidx.core.app.Person);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPersons(androidx.core.app.Person![]);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setRank(int);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setShortLabel(CharSequence);
+  }
+
+  public class ShortcutManagerCompat {
+    method public static boolean addDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+    method public static android.content.Intent createShortcutResultIntent(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+    method public static void disableShortcuts(android.content.Context, java.util.List<java.lang.String!>, CharSequence?);
+    method public static void enableShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+    method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getDynamicShortcuts(android.content.Context);
+    method public static int getIconMaxHeight(android.content.Context);
+    method public static int getIconMaxWidth(android.content.Context);
+    method public static int getMaxShortcutCountPerActivity(android.content.Context);
+    method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getShortcuts(android.content.Context, int);
+    method public static boolean isRateLimitingActive(android.content.Context);
+    method public static boolean isRequestPinShortcutSupported(android.content.Context);
+    method public static boolean pushDynamicShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+    method public static void removeAllDynamicShortcuts(android.content.Context);
+    method public static void removeDynamicShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+    method public static void removeLongLivedShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+    method public static void reportShortcutUsed(android.content.Context, String);
+    method public static boolean requestPinShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat, android.content.IntentSender?);
+    method public static boolean setDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+    method public static boolean updateShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+    field public static final String EXTRA_SHORTCUT_ID = "android.intent.extra.shortcut.ID";
+    field public static final int FLAG_MATCH_CACHED = 8; // 0x8
+    field public static final int FLAG_MATCH_DYNAMIC = 2; // 0x2
+    field public static final int FLAG_MATCH_MANIFEST = 1; // 0x1
+    field public static final int FLAG_MATCH_PINNED = 4; // 0x4
+  }
+
+}
+
+package androidx.core.content.res {
+
+  public final class ConfigurationHelper {
+    method public static int getDensityDpi(android.content.res.Resources);
+  }
+
+  public final class ResourcesCompat {
+    method public static android.graphics.Typeface? getCachedFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+    method @ColorInt public static int getColor(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+    method public static android.content.res.ColorStateList? getColorStateList(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+    method public static android.graphics.drawable.Drawable? getDrawable(android.content.res.Resources, @DrawableRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+    method public static android.graphics.drawable.Drawable? getDrawableForDensity(android.content.res.Resources, @DrawableRes int, int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+    method public static float getFloat(android.content.res.Resources, @DimenRes int);
+    method public static android.graphics.Typeface? getFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+    method public static void getFont(android.content.Context, @FontRes int, androidx.core.content.res.ResourcesCompat.FontCallback, android.os.Handler?) throws android.content.res.Resources.NotFoundException;
+    field @AnyRes public static final int ID_NULL = 0; // 0x0
+  }
+
+  public abstract static class ResourcesCompat.FontCallback {
+    ctor public ResourcesCompat.FontCallback();
+    method public abstract void onFontRetrievalFailed(int);
+    method public abstract void onFontRetrieved(android.graphics.Typeface);
+  }
+
+  public static final class ResourcesCompat.ThemeCompat {
+    method public static void rebase(android.content.res.Resources.Theme);
+  }
+
+}
+
+package androidx.core.database {
+
+  public final class CursorWindowCompat {
+    method public static android.database.CursorWindow create(String?, long);
+  }
+
+  @Deprecated public final class DatabaseUtilsCompat {
+    method @Deprecated public static String![]! appendSelectionArgs(String![]!, String![]!);
+    method @Deprecated public static String! concatenateWhere(String!, String!);
+  }
+
+}
+
+package androidx.core.database.sqlite {
+
+  public final class SQLiteCursorCompat {
+    method public static void setFillWindowForwardOnly(android.database.sqlite.SQLiteCursor, boolean);
+  }
+
+}
+
+package androidx.core.graphics {
+
+  public final class BitmapCompat {
+    method public static int getAllocationByteCount(android.graphics.Bitmap);
+    method public static boolean hasMipMap(android.graphics.Bitmap);
+    method public static void setHasMipMap(android.graphics.Bitmap, boolean);
+  }
+
+  public class BlendModeColorFilterCompat {
+    method public static android.graphics.ColorFilter? createBlendModeColorFilterCompat(int, androidx.core.graphics.BlendModeCompat);
+  }
+
+  public enum BlendModeCompat {
+    enum_constant public static final androidx.core.graphics.BlendModeCompat CLEAR;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_BURN;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_DODGE;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DARKEN;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat DIFFERENCE;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DST;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DST_ATOP;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DST_IN;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OUT;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OVER;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat EXCLUSION;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HARD_LIGHT;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HUE;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat LIGHTEN;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat LUMINOSITY;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat MODULATE;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat MULTIPLY;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat OVERLAY;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat PLUS;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SATURATION;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SCREEN;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SOFT_LIGHT;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SRC;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_ATOP;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_IN;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OUT;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OVER;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat XOR;
+  }
+
+  public final class ColorUtils {
+    method @ColorInt public static int HSLToColor(float[]);
+    method @ColorInt public static int LABToColor(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double);
+    method public static void LABToXYZ(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double, double[]);
+    method public static void RGBToHSL(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, float[]);
+    method public static void RGBToLAB(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+    method public static void RGBToXYZ(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+    method @ColorInt public static int XYZToColor(@FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_X) double, @FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_Y) double, @FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_Z) double);
+    method public static void XYZToLAB(@FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_X) double, @FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_Y) double, @FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_Z) double, double[]);
+    method @ColorInt public static int blendARGB(@ColorInt int, @ColorInt int, @FloatRange(from=0.0, to=1.0) float);
+    method public static void blendHSL(float[], float[], @FloatRange(from=0.0, to=1.0) float, float[]);
+    method public static void blendLAB(double[], double[], @FloatRange(from=0.0, to=1.0) double, double[]);
+    method public static double calculateContrast(@ColorInt int, @ColorInt int);
+    method @FloatRange(from=0.0, to=1.0) public static double calculateLuminance(@ColorInt int);
+    method public static int calculateMinimumAlpha(@ColorInt int, @ColorInt int, float);
+    method public static void colorToHSL(@ColorInt int, float[]);
+    method public static void colorToLAB(@ColorInt int, double[]);
+    method public static void colorToXYZ(@ColorInt int, double[]);
+    method public static int compositeColors(@ColorInt int, @ColorInt int);
+    method @RequiresApi(26) public static android.graphics.Color compositeColors(android.graphics.Color, android.graphics.Color);
+    method public static double distanceEuclidean(double[], double[]);
+    method @ColorInt public static int setAlphaComponent(@ColorInt int, @IntRange(from=0, to=255) int);
+  }
+
+  public final class Insets {
+    method public static androidx.core.graphics.Insets add(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+    method public static androidx.core.graphics.Insets max(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+    method public static androidx.core.graphics.Insets min(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+    method public static androidx.core.graphics.Insets of(int, int, int, int);
+    method public static androidx.core.graphics.Insets of(android.graphics.Rect);
+    method public static androidx.core.graphics.Insets subtract(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+    method @RequiresApi(api=29) public static androidx.core.graphics.Insets toCompatInsets(android.graphics.Insets);
+    method @RequiresApi(api=29) public android.graphics.Insets toPlatformInsets();
+    field public static final androidx.core.graphics.Insets NONE;
+    field public final int bottom;
+    field public final int left;
+    field public final int right;
+    field public final int top;
+  }
+
+  public final class PaintCompat {
+    method public static boolean hasGlyph(android.graphics.Paint, String);
+    method public static boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat?);
+  }
+
+  public final class PathSegment {
+    ctor public PathSegment(android.graphics.PointF, float, android.graphics.PointF, float);
+    method public android.graphics.PointF getEnd();
+    method public float getEndFraction();
+    method public android.graphics.PointF getStart();
+    method public float getStartFraction();
+  }
+
+  public final class PathUtils {
+    method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path);
+    method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path, @FloatRange(from=0) float);
+  }
+
+  public class TypefaceCompat {
+    method public static android.graphics.Typeface create(android.content.Context, android.graphics.Typeface?, int);
+  }
+
+}
+
+package androidx.core.graphics.drawable {
+
+  public final class DrawableCompat {
+    method public static void applyTheme(android.graphics.drawable.Drawable, android.content.res.Resources.Theme);
+    method public static boolean canApplyTheme(android.graphics.drawable.Drawable);
+    method public static void clearColorFilter(android.graphics.drawable.Drawable);
+    method public static int getAlpha(android.graphics.drawable.Drawable);
+    method public static android.graphics.ColorFilter! getColorFilter(android.graphics.drawable.Drawable);
+    method public static int getLayoutDirection(android.graphics.drawable.Drawable);
+    method public static void inflate(android.graphics.drawable.Drawable, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
+    method @Deprecated public static void jumpToCurrentState(android.graphics.drawable.Drawable);
+    method public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
+    method public static void setHotspot(android.graphics.drawable.Drawable, float, float);
+    method public static void setHotspotBounds(android.graphics.drawable.Drawable, int, int, int, int);
+    method public static boolean setLayoutDirection(android.graphics.drawable.Drawable, int);
+    method public static void setTint(android.graphics.drawable.Drawable, @ColorInt int);
+    method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList?);
+    method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode);
+    method public static <T extends android.graphics.drawable.Drawable> T! unwrap(android.graphics.drawable.Drawable);
+    method public static android.graphics.drawable.Drawable! wrap(android.graphics.drawable.Drawable);
+  }
+
+  public class IconCompat implements androidx.versionedparcelable.VersionedParcelable {
+    method public static androidx.core.graphics.drawable.IconCompat? createFromBundle(android.os.Bundle);
+    method @RequiresApi(23) public static androidx.core.graphics.drawable.IconCompat? createFromIcon(android.content.Context, android.graphics.drawable.Icon);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithAdaptiveBitmap(android.graphics.Bitmap!);
+    method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(String);
+    method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(android.net.Uri);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithBitmap(android.graphics.Bitmap!);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithContentUri(String!);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithContentUri(android.net.Uri!);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithData(byte[]!, int, int);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithResource(android.content.Context!, @DrawableRes int);
+    method @IdRes public int getResId();
+    method public String getResPackage();
+    method public int getType();
+    method public android.net.Uri getUri();
+    method public android.graphics.drawable.Drawable? loadDrawable(android.content.Context);
+    method public void onPostParceling();
+    method public void onPreParceling(boolean);
+    method public androidx.core.graphics.drawable.IconCompat! setTint(@ColorInt int);
+    method public androidx.core.graphics.drawable.IconCompat! setTintList(android.content.res.ColorStateList!);
+    method public androidx.core.graphics.drawable.IconCompat! setTintMode(android.graphics.PorterDuff.Mode!);
+    method public android.os.Bundle toBundle();
+    method @Deprecated @RequiresApi(23) public android.graphics.drawable.Icon toIcon();
+    method @RequiresApi(23) public android.graphics.drawable.Icon toIcon(android.content.Context?);
+    field public static final int TYPE_ADAPTIVE_BITMAP = 5; // 0x5
+    field public static final int TYPE_BITMAP = 1; // 0x1
+    field public static final int TYPE_DATA = 3; // 0x3
+    field public static final int TYPE_RESOURCE = 2; // 0x2
+    field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
+    field public static final int TYPE_URI = 4; // 0x4
+    field public static final int TYPE_URI_ADAPTIVE_BITMAP = 6; // 0x6
+  }
+
+  public abstract class RoundedBitmapDrawable extends android.graphics.drawable.Drawable {
+    method public void draw(android.graphics.Canvas);
+    method public final android.graphics.Bitmap? getBitmap();
+    method public float getCornerRadius();
+    method public int getGravity();
+    method public int getOpacity();
+    method public final android.graphics.Paint getPaint();
+    method public boolean hasAntiAlias();
+    method public boolean hasMipMap();
+    method public boolean isCircular();
+    method public void setAlpha(int);
+    method public void setAntiAlias(boolean);
+    method public void setCircular(boolean);
+    method public void setColorFilter(android.graphics.ColorFilter!);
+    method public void setCornerRadius(float);
+    method public void setDither(boolean);
+    method public void setGravity(int);
+    method public void setMipMap(boolean);
+    method public void setTargetDensity(android.graphics.Canvas);
+    method public void setTargetDensity(android.util.DisplayMetrics);
+    method public void setTargetDensity(int);
+  }
+
+  public final class RoundedBitmapDrawableFactory {
+    method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, android.graphics.Bitmap?);
+    method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, String);
+    method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.io.InputStream);
+  }
+
+}
+
+package androidx.core.hardware.display {
+
+  public final class DisplayManagerCompat {
+    method public android.view.Display? getDisplay(int);
+    method public android.view.Display![] getDisplays();
+    method public android.view.Display![] getDisplays(String?);
+    method public static androidx.core.hardware.display.DisplayManagerCompat getInstance(android.content.Context);
+    field public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+  }
+
+}
+
+package androidx.core.hardware.fingerprint {
+
+  @Deprecated public class FingerprintManagerCompat {
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public void authenticate(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject?, int, androidx.core.os.CancellationSignal?, androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback, android.os.Handler?);
+    method @Deprecated public static androidx.core.hardware.fingerprint.FingerprintManagerCompat from(android.content.Context);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
+  }
+
+  @Deprecated public abstract static class FingerprintManagerCompat.AuthenticationCallback {
+    ctor @Deprecated public FingerprintManagerCompat.AuthenticationCallback();
+    method @Deprecated public void onAuthenticationError(int, CharSequence!);
+    method @Deprecated public void onAuthenticationFailed();
+    method @Deprecated public void onAuthenticationHelp(int, CharSequence!);
+    method @Deprecated public void onAuthenticationSucceeded(androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationResult!);
+  }
+
+  @Deprecated public static final class FingerprintManagerCompat.AuthenticationResult {
+    ctor @Deprecated public FingerprintManagerCompat.AuthenticationResult(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject!);
+    method @Deprecated public androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject! getCryptoObject();
+  }
+
+  @Deprecated public static class FingerprintManagerCompat.CryptoObject {
+    ctor @Deprecated public FingerprintManagerCompat.CryptoObject(java.security.Signature);
+    ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Cipher);
+    ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Mac);
+    method @Deprecated public javax.crypto.Cipher? getCipher();
+    method @Deprecated public javax.crypto.Mac? getMac();
+    method @Deprecated public java.security.Signature? getSignature();
+  }
+
+}
+
+package androidx.core.location {
+
+  public abstract class GnssStatusCompat {
+    method @FloatRange(from=0, to=360) public abstract float getAzimuthDegrees(@IntRange(from=0) int);
+    method @FloatRange(from=0, to=63) public abstract float getBasebandCn0DbHz(@IntRange(from=0) int);
+    method @FloatRange(from=0) public abstract float getCarrierFrequencyHz(@IntRange(from=0) int);
+    method @FloatRange(from=0, to=63) public abstract float getCn0DbHz(@IntRange(from=0) int);
+    method public abstract int getConstellationType(@IntRange(from=0) int);
+    method @FloatRange(from=0xffffffa6, to=90) public abstract float getElevationDegrees(@IntRange(from=0) int);
+    method @IntRange(from=0) public abstract int getSatelliteCount();
+    method @IntRange(from=1, to=200) public abstract int getSvid(@IntRange(from=0) int);
+    method public abstract boolean hasAlmanacData(@IntRange(from=0) int);
+    method public abstract boolean hasBasebandCn0DbHz(@IntRange(from=0) int);
+    method public abstract boolean hasCarrierFrequencyHz(@IntRange(from=0) int);
+    method public abstract boolean hasEphemerisData(@IntRange(from=0) int);
+    method public abstract boolean usedInFix(@IntRange(from=0) int);
+    method @RequiresApi(android.os.Build.VERSION_CODES.N) public static androidx.core.location.GnssStatusCompat wrap(android.location.GnssStatus);
+    method public static androidx.core.location.GnssStatusCompat wrap(android.location.GpsStatus);
+    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+    field public static final int CONSTELLATION_GPS = 1; // 0x1
+    field public static final int CONSTELLATION_IRNSS = 7; // 0x7
+    field public static final int CONSTELLATION_QZSS = 4; // 0x4
+    field public static final int CONSTELLATION_SBAS = 2; // 0x2
+    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+  }
+
+  public abstract static class GnssStatusCompat.Callback {
+    ctor public GnssStatusCompat.Callback();
+    method public void onFirstFix(@IntRange(from=0) int);
+    method public void onSatelliteStatusChanged(androidx.core.location.GnssStatusCompat);
+    method public void onStarted();
+    method public void onStopped();
+  }
+
+  public final class LocationManagerCompat {
+    method public static boolean isLocationEnabled(android.location.LocationManager);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback, android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, java.util.concurrent.Executor, androidx.core.location.GnssStatusCompat.Callback);
+    method public static void unregisterGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback);
+  }
+
+}
+
+package androidx.core.math {
+
+  public class MathUtils {
+    method public static float clamp(float, float, float);
+    method public static double clamp(double, double, double);
+    method public static int clamp(int, int, int);
+    method public static long clamp(long, long, long);
+  }
+
+}
+
+package androidx.core.net {
+
+  public final class ConnectivityManagerCompat {
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static android.net.NetworkInfo? getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
+    method public static int getRestrictBackgroundStatus(android.net.ConnectivityManager);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+    field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+    field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+    field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
+  }
+
+  public final class MailTo {
+    method public String? getBcc();
+    method public String? getBody();
+    method public String? getCc();
+    method public java.util.Map<java.lang.String!,java.lang.String!>? getHeaders();
+    method public String? getSubject();
+    method public String? getTo();
+    method public static boolean isMailTo(String?);
+    method public static boolean isMailTo(android.net.Uri?);
+    method public static androidx.core.net.MailTo parse(String) throws androidx.core.net.ParseException;
+    method public static androidx.core.net.MailTo parse(android.net.Uri) throws androidx.core.net.ParseException;
+    field public static final String MAILTO_SCHEME = "mailto:";
+  }
+
+  public class ParseException extends java.lang.RuntimeException {
+    field public final String response;
+  }
+
+  public final class TrafficStatsCompat {
+    method @Deprecated public static void clearThreadStatsTag();
+    method @Deprecated public static int getThreadStatsTag();
+    method @Deprecated public static void incrementOperationCount(int);
+    method @Deprecated public static void incrementOperationCount(int, int);
+    method @Deprecated public static void setThreadStatsTag(int);
+    method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+    method @Deprecated public static void tagSocket(java.net.Socket!) throws java.net.SocketException;
+    method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+    method @Deprecated public static void untagSocket(java.net.Socket!) throws java.net.SocketException;
+  }
+
+  public final class UriCompat {
+    method public static String toSafeString(android.net.Uri);
+  }
+
+}
+
+package androidx.core.os {
+
+  public class BuildCompat {
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N) public static boolean isAtLeastN();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N_MR1) public static boolean isAtLeastNMR1();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O) public static boolean isAtLeastO();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O_MR1) public static boolean isAtLeastOMR1();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.P) public static boolean isAtLeastP();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.Q) public static boolean isAtLeastQ();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.R) public static boolean isAtLeastR();
+    method @ChecksSdkIntAtLeast(codename="S") public static boolean isAtLeastS();
+  }
+
+  public final class CancellationSignal {
+    ctor public CancellationSignal();
+    method public void cancel();
+    method public Object? getCancellationSignalObject();
+    method public boolean isCanceled();
+    method public void setOnCancelListener(androidx.core.os.CancellationSignal.OnCancelListener?);
+    method public void throwIfCanceled();
+  }
+
+  public static interface CancellationSignal.OnCancelListener {
+    method public void onCancel();
+  }
+
+  public final class ConfigurationCompat {
+    method public static androidx.core.os.LocaleListCompat getLocales(android.content.res.Configuration);
+  }
+
+  public final class EnvironmentCompat {
+    method public static String getStorageState(java.io.File);
+    field public static final String MEDIA_UNKNOWN = "unknown";
+  }
+
+  public final class ExecutorCompat {
+    method public static java.util.concurrent.Executor create(android.os.Handler);
+  }
+
+  public final class HandlerCompat {
+    method public static android.os.Handler createAsync(android.os.Looper);
+    method public static android.os.Handler createAsync(android.os.Looper, android.os.Handler.Callback);
+    method public static boolean postDelayed(android.os.Handler, Runnable, Object?, long);
+  }
+
+  public final class LocaleListCompat {
+    method public static androidx.core.os.LocaleListCompat create(java.util.Locale!...);
+    method public static androidx.core.os.LocaleListCompat forLanguageTags(String?);
+    method public java.util.Locale! get(int);
+    method @Size(min=1) public static androidx.core.os.LocaleListCompat getAdjustedDefault();
+    method @Size(min=1) public static androidx.core.os.LocaleListCompat getDefault();
+    method public static androidx.core.os.LocaleListCompat getEmptyLocaleList();
+    method public java.util.Locale? getFirstMatch(String![]);
+    method @IntRange(from=0xffffffff) public int indexOf(java.util.Locale!);
+    method public boolean isEmpty();
+    method @IntRange(from=0) public int size();
+    method public String toLanguageTags();
+    method public Object? unwrap();
+    method @Deprecated @RequiresApi(24) public static androidx.core.os.LocaleListCompat! wrap(Object!);
+    method @RequiresApi(24) public static androidx.core.os.LocaleListCompat wrap(android.os.LocaleList);
+  }
+
+  public final class MessageCompat {
+    method public static boolean isAsynchronous(android.os.Message);
+    method public static void setAsynchronous(android.os.Message, boolean);
+  }
+
+  public class OperationCanceledException extends java.lang.RuntimeException {
+    ctor public OperationCanceledException();
+    ctor public OperationCanceledException(String?);
+  }
+
+  public final class ParcelCompat {
+    method public static boolean readBoolean(android.os.Parcel);
+    method public static void writeBoolean(android.os.Parcel, boolean);
+  }
+
+  @Deprecated public final class ParcelableCompat {
+    method @Deprecated public static <T> android.os.Parcelable.Creator<T!>! newCreator(androidx.core.os.ParcelableCompatCreatorCallbacks<T!>!);
+  }
+
+  @Deprecated public interface ParcelableCompatCreatorCallbacks<T> {
+    method @Deprecated public T! createFromParcel(android.os.Parcel!, ClassLoader!);
+    method @Deprecated public T![]! newArray(int);
+  }
+
+  public final class ProcessCompat {
+    method public static boolean isApplicationUid(int);
+  }
+
+  @Deprecated public final class TraceCompat {
+    method @Deprecated public static void beginAsyncSection(String, int);
+    method @Deprecated public static void beginSection(String);
+    method @Deprecated public static void endAsyncSection(String, int);
+    method @Deprecated public static void endSection();
+    method @Deprecated public static boolean isEnabled();
+    method @Deprecated public static void setCounter(String, int);
+  }
+
+  public class UserManagerCompat {
+    method public static boolean isUserUnlocked(android.content.Context);
+  }
+
+}
+
+package androidx.core.provider {
+
+  public final class FontRequest {
+    ctor public FontRequest(String, String, String, java.util.List<java.util.List<byte[]!>!>);
+    ctor public FontRequest(String, String, String, @ArrayRes int);
+    method public java.util.List<java.util.List<byte[]!>!>? getCertificates();
+    method @ArrayRes public int getCertificatesArrayResId();
+    method public String getProviderAuthority();
+    method public String getProviderPackage();
+    method public String getQuery();
+  }
+
+  public class FontsContractCompat {
+    method public static android.graphics.Typeface? buildTypeface(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![]);
+    method public static androidx.core.provider.FontsContractCompat.FontFamilyResult fetchFonts(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static void requestFont(android.content.Context, androidx.core.provider.FontRequest, androidx.core.provider.FontsContractCompat.FontRequestCallback, android.os.Handler);
+  }
+
+  public static final class FontsContractCompat.Columns implements android.provider.BaseColumns {
+    ctor public FontsContractCompat.Columns();
+    field public static final String FILE_ID = "file_id";
+    field public static final String ITALIC = "font_italic";
+    field public static final String RESULT_CODE = "result_code";
+    field public static final int RESULT_CODE_FONT_NOT_FOUND = 1; // 0x1
+    field public static final int RESULT_CODE_FONT_UNAVAILABLE = 2; // 0x2
+    field public static final int RESULT_CODE_MALFORMED_QUERY = 3; // 0x3
+    field public static final int RESULT_CODE_OK = 0; // 0x0
+    field public static final String TTC_INDEX = "font_ttc_index";
+    field public static final String VARIATION_SETTINGS = "font_variation_settings";
+    field public static final String WEIGHT = "font_weight";
+  }
+
+  public static class FontsContractCompat.FontFamilyResult {
+    method public androidx.core.provider.FontsContractCompat.FontInfo![]! getFonts();
+    method public int getStatusCode();
+    field public static final int STATUS_OK = 0; // 0x0
+    field public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; // 0x2
+    field public static final int STATUS_WRONG_CERTIFICATES = 1; // 0x1
+  }
+
+  public static class FontsContractCompat.FontInfo {
+    method public int getResultCode();
+    method @IntRange(from=0) public int getTtcIndex();
+    method public android.net.Uri getUri();
+    method @IntRange(from=1, to=1000) public int getWeight();
+    method public boolean isItalic();
+  }
+
+  public static class FontsContractCompat.FontRequestCallback {
+    ctor public FontsContractCompat.FontRequestCallback();
+    method public void onTypefaceRequestFailed(int);
+    method public void onTypefaceRetrieved(android.graphics.Typeface!);
+    field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
+    field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
+    field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
+    field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
+    field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
+    field public static final int FAIL_REASON_SECURITY_VIOLATION = -4; // 0xfffffffc
+    field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
+  }
+
+}
+
+package androidx.core.telephony.mbms {
+
+  public final class MbmsHelper {
+    method public static CharSequence? getBestNameForService(android.content.Context, android.telephony.mbms.ServiceInfo);
+  }
+
+}
+
+package androidx.core.text {
+
+  public final class BidiFormatter {
+    method public static androidx.core.text.BidiFormatter! getInstance();
+    method public static androidx.core.text.BidiFormatter! getInstance(boolean);
+    method public static androidx.core.text.BidiFormatter! getInstance(java.util.Locale!);
+    method public boolean getStereoReset();
+    method public boolean isRtl(String!);
+    method public boolean isRtl(CharSequence!);
+    method public boolean isRtlContext();
+    method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+    method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+    method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!);
+    method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!);
+    method public String! unicodeWrap(String!, boolean);
+    method public CharSequence! unicodeWrap(CharSequence!, boolean);
+    method public String! unicodeWrap(String!);
+    method public CharSequence! unicodeWrap(CharSequence!);
+  }
+
+  public static final class BidiFormatter.Builder {
+    ctor public BidiFormatter.Builder();
+    ctor public BidiFormatter.Builder(boolean);
+    ctor public BidiFormatter.Builder(java.util.Locale!);
+    method public androidx.core.text.BidiFormatter! build();
+    method public androidx.core.text.BidiFormatter.Builder! setTextDirectionHeuristic(androidx.core.text.TextDirectionHeuristicCompat!);
+    method public androidx.core.text.BidiFormatter.Builder! stereoReset(boolean);
+  }
+
+  public final class HtmlCompat {
+    method public static android.text.Spanned fromHtml(String, int);
+    method public static android.text.Spanned fromHtml(String, int, android.text.Html.ImageGetter?, android.text.Html.TagHandler?);
+    method public static String toHtml(android.text.Spanned, int);
+    field public static final int FROM_HTML_MODE_COMPACT = 63; // 0x3f
+    field public static final int FROM_HTML_MODE_LEGACY = 0; // 0x0
+    field public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256; // 0x100
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 32; // 0x20
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 16; // 0x10
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 2; // 0x2
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 8; // 0x8
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 4; // 0x4
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 1; // 0x1
+    field public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0; // 0x0
+    field public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1; // 0x1
+  }
+
+  public final class ICUCompat {
+    method public static String? maximizeAndGetScript(java.util.Locale!);
+  }
+
+  public class PrecomputedTextCompat implements android.text.Spannable {
+    method public char charAt(int);
+    method public static androidx.core.text.PrecomputedTextCompat! create(CharSequence, androidx.core.text.PrecomputedTextCompat.Params);
+    method @IntRange(from=0) public int getParagraphCount();
+    method @IntRange(from=0) public int getParagraphEnd(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getParagraphStart(@IntRange(from=0) int);
+    method public androidx.core.text.PrecomputedTextCompat.Params getParams();
+    method public int getSpanEnd(Object!);
+    method public int getSpanFlags(Object!);
+    method public int getSpanStart(Object!);
+    method public <T> T![]! getSpans(int, int, Class<T!>!);
+    method @UiThread public static java.util.concurrent.Future<androidx.core.text.PrecomputedTextCompat!>! getTextFuture(CharSequence, androidx.core.text.PrecomputedTextCompat.Params, java.util.concurrent.Executor?);
+    method public int length();
+    method public int nextSpanTransition(int, int, Class!);
+    method public void removeSpan(Object!);
+    method public void setSpan(Object!, int, int, int);
+    method public CharSequence! subSequence(int, int);
+  }
+
+  public static final class PrecomputedTextCompat.Params {
+    ctor @RequiresApi(28) public PrecomputedTextCompat.Params(android.text.PrecomputedText.Params);
+    method @RequiresApi(23) public int getBreakStrategy();
+    method @RequiresApi(23) public int getHyphenationFrequency();
+    method @RequiresApi(18) public android.text.TextDirectionHeuristic? getTextDirection();
+    method public android.text.TextPaint getTextPaint();
+  }
+
+  public static class PrecomputedTextCompat.Params.Builder {
+    ctor public PrecomputedTextCompat.Params.Builder(android.text.TextPaint);
+    method public androidx.core.text.PrecomputedTextCompat.Params build();
+    method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setBreakStrategy(int);
+    method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setHyphenationFrequency(int);
+    method @RequiresApi(18) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setTextDirection(android.text.TextDirectionHeuristic);
+  }
+
+  public interface TextDirectionHeuristicCompat {
+    method public boolean isRtl(char[]!, int, int);
+    method public boolean isRtl(CharSequence!, int, int);
+  }
+
+  public final class TextDirectionHeuristicsCompat {
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! ANYRTL_LTR;
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_LTR;
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_RTL;
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! LOCALE;
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! LTR;
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! RTL;
+  }
+
+  public final class TextUtilsCompat {
+    method public static int getLayoutDirectionFromLocale(java.util.Locale?);
+    method public static String htmlEncode(String);
+  }
+
+}
+
+package androidx.core.text.util {
+
+  public final class LinkifyCompat {
+    method public static boolean addLinks(android.text.Spannable, int);
+    method public static boolean addLinks(android.widget.TextView, int);
+    method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?);
+    method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+    method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+    method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?);
+    method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+    method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+  }
+
+}
+
+package androidx.core.util {
+
+  public class AtomicFile {
+    ctor public AtomicFile(java.io.File);
+    method public void delete();
+    method public void failWrite(java.io.FileOutputStream?);
+    method public void finishWrite(java.io.FileOutputStream?);
+    method public java.io.File getBaseFile();
+    method public java.io.FileInputStream openRead() throws java.io.FileNotFoundException;
+    method public byte[] readFully() throws java.io.IOException;
+    method public java.io.FileOutputStream startWrite() throws java.io.IOException;
+  }
+
+  public interface Consumer<T> {
+    method public void accept(T!);
+  }
+
+  public class ObjectsCompat {
+    method public static boolean equals(Object?, Object?);
+    method public static int hash(java.lang.Object!...);
+    method public static int hashCode(Object?);
+    method public static String? toString(Object?, String?);
+  }
+
+  public class Pair<F, S> {
+    ctor public Pair(F!, S!);
+    method public static <A, B> androidx.core.util.Pair<A!,B!> create(A!, B!);
+    field public final F! first;
+    field public final S! second;
+  }
+
+  public final class PatternsCompat {
+    field public static final java.util.regex.Pattern DOMAIN_NAME;
+    field public static final java.util.regex.Pattern EMAIL_ADDRESS;
+    field public static final java.util.regex.Pattern IP_ADDRESS;
+    field public static final java.util.regex.Pattern WEB_URL;
+  }
+
+  public final class Pools {
+  }
+
+  public static interface Pools.Pool<T> {
+    method public T? acquire();
+    method public boolean release(T);
+  }
+
+  public static class Pools.SimplePool<T> implements androidx.core.util.Pools.Pool<T> {
+    ctor public Pools.SimplePool(int);
+    method public T! acquire();
+    method public boolean release(T);
+  }
+
+  public static class Pools.SynchronizedPool<T> extends androidx.core.util.Pools.SimplePool<T> {
+    ctor public Pools.SynchronizedPool(int);
+  }
+
+  public interface Predicate<T> {
+    method public boolean test(T!);
+  }
+
+  public interface Supplier<T> {
+    method public T! get();
+  }
+
+}
+
+package androidx.core.view {
+
+  public class AccessibilityDelegateCompat {
+    ctor public AccessibilityDelegateCompat();
+    method public boolean dispatchPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public androidx.core.view.accessibility.AccessibilityNodeProviderCompat! getAccessibilityNodeProvider(android.view.View!);
+    method public void onInitializeAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public void onInitializeAccessibilityNodeInfo(android.view.View!, androidx.core.view.accessibility.AccessibilityNodeInfoCompat!);
+    method public void onPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public boolean performAccessibilityAction(android.view.View!, int, android.os.Bundle!);
+    method public void sendAccessibilityEvent(android.view.View!, int);
+    method public void sendAccessibilityEventUnchecked(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+  }
+
+  public abstract class ActionProvider {
+    ctor public ActionProvider(android.content.Context!);
+    method public android.content.Context! getContext();
+    method public boolean hasSubMenu();
+    method public boolean isVisible();
+    method public abstract android.view.View! onCreateActionView();
+    method public android.view.View! onCreateActionView(android.view.MenuItem!);
+    method public boolean onPerformDefaultAction();
+    method public void onPrepareSubMenu(android.view.SubMenu!);
+    method public boolean overridesItemVisibility();
+    method public void refreshVisibility();
+    method public void setVisibilityListener(androidx.core.view.ActionProvider.VisibilityListener!);
+  }
+
+  public static interface ActionProvider.VisibilityListener {
+    method public void onActionProviderVisibilityChanged(boolean);
+  }
+
+  public final class ContentInfoCompat {
+    method public android.content.ClipData getClip();
+    method public android.os.Bundle? getExtras();
+    method public int getFlags();
+    method public android.net.Uri? getLinkUri();
+    method public int getSource();
+    method public android.util.Pair<androidx.core.view.ContentInfoCompat!,androidx.core.view.ContentInfoCompat!> partition(androidx.core.util.Predicate<android.content.ClipData.Item!>);
+    field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
+    field public static final int SOURCE_APP = 0; // 0x0
+    field public static final int SOURCE_CLIPBOARD = 1; // 0x1
+    field public static final int SOURCE_DRAG_AND_DROP = 3; // 0x3
+    field public static final int SOURCE_INPUT_METHOD = 2; // 0x2
+  }
+
+  public static final class ContentInfoCompat.Builder {
+    ctor public ContentInfoCompat.Builder(androidx.core.view.ContentInfoCompat);
+    ctor public ContentInfoCompat.Builder(android.content.ClipData, int);
+    method public androidx.core.view.ContentInfoCompat build();
+    method public androidx.core.view.ContentInfoCompat.Builder setClip(android.content.ClipData);
+    method public androidx.core.view.ContentInfoCompat.Builder setExtras(android.os.Bundle?);
+    method public androidx.core.view.ContentInfoCompat.Builder setFlags(int);
+    method public androidx.core.view.ContentInfoCompat.Builder setLinkUri(android.net.Uri?);
+    method public androidx.core.view.ContentInfoCompat.Builder setSource(int);
+  }
+
+  public final class DisplayCompat {
+    method public static androidx.core.view.DisplayCompat.ModeCompat![] getSupportedModes(android.content.Context, android.view.Display);
+  }
+
+  public static final class DisplayCompat.ModeCompat {
+    method public int getPhysicalHeight();
+    method public int getPhysicalWidth();
+    method public boolean isNative();
+    method @RequiresApi(android.os.Build.VERSION_CODES.M) public android.view.Display.Mode? toMode();
+  }
+
+  public final class DisplayCutoutCompat {
+    ctor public DisplayCutoutCompat(android.graphics.Rect!, java.util.List<android.graphics.Rect!>!);
+    ctor public DisplayCutoutCompat(androidx.core.graphics.Insets, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, androidx.core.graphics.Insets);
+    method public java.util.List<android.graphics.Rect!> getBoundingRects();
+    method public int getSafeInsetBottom();
+    method public int getSafeInsetLeft();
+    method public int getSafeInsetRight();
+    method public int getSafeInsetTop();
+    method public androidx.core.graphics.Insets getWaterfallInsets();
+  }
+
+  public final class DragAndDropPermissionsCompat {
+    method public void release();
+  }
+
+  public class DragStartHelper {
+    ctor public DragStartHelper(android.view.View!, androidx.core.view.DragStartHelper.OnDragStartListener!);
+    method public void attach();
+    method public void detach();
+    method public void getTouchPosition(android.graphics.Point!);
+    method public boolean onLongClick(android.view.View!);
+    method public boolean onTouch(android.view.View!, android.view.MotionEvent!);
+  }
+
+  public static interface DragStartHelper.OnDragStartListener {
+    method public boolean onDragStart(android.view.View!, androidx.core.view.DragStartHelper!);
+  }
+
+  public final class GestureDetectorCompat {
+    ctor public GestureDetectorCompat(android.content.Context!, android.view.GestureDetector.OnGestureListener!);
+    ctor public GestureDetectorCompat(android.content.Context!, android.view.GestureDetector.OnGestureListener!, android.os.Handler!);
+    method public boolean isLongpressEnabled();
+    method public boolean onTouchEvent(android.view.MotionEvent!);
+    method public void setIsLongpressEnabled(boolean);
+    method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener!);
+  }
+
+  public final class GravityCompat {
+    method public static void apply(int, int, int, android.graphics.Rect!, android.graphics.Rect!, int);
+    method public static void apply(int, int, int, android.graphics.Rect!, int, int, android.graphics.Rect!, int);
+    method public static void applyDisplay(int, android.graphics.Rect!, android.graphics.Rect!, int);
+    method public static int getAbsoluteGravity(int, int);
+    field public static final int END = 8388613; // 0x800005
+    field public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = 8388615; // 0x800007
+    field public static final int RELATIVE_LAYOUT_DIRECTION = 8388608; // 0x800000
+    field public static final int START = 8388611; // 0x800003
+  }
+
+  public final class InputDeviceCompat {
+    field public static final int SOURCE_ANY = -256; // 0xffffff00
+    field public static final int SOURCE_CLASS_BUTTON = 1; // 0x1
+    field public static final int SOURCE_CLASS_JOYSTICK = 16; // 0x10
+    field public static final int SOURCE_CLASS_MASK = 255; // 0xff
+    field public static final int SOURCE_CLASS_NONE = 0; // 0x0
+    field public static final int SOURCE_CLASS_POINTER = 2; // 0x2
+    field public static final int SOURCE_CLASS_POSITION = 8; // 0x8
+    field public static final int SOURCE_CLASS_TRACKBALL = 4; // 0x4
+    field public static final int SOURCE_DPAD = 513; // 0x201
+    field public static final int SOURCE_GAMEPAD = 1025; // 0x401
+    field public static final int SOURCE_HDMI = 33554433; // 0x2000001
+    field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
+    field public static final int SOURCE_KEYBOARD = 257; // 0x101
+    field public static final int SOURCE_MOUSE = 8194; // 0x2002
+    field public static final int SOURCE_ROTARY_ENCODER = 4194304; // 0x400000
+    field public static final int SOURCE_STYLUS = 16386; // 0x4002
+    field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
+    field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
+    field public static final int SOURCE_TOUCH_NAVIGATION = 2097152; // 0x200000
+    field public static final int SOURCE_TRACKBALL = 65540; // 0x10004
+    field public static final int SOURCE_UNKNOWN = 0; // 0x0
+  }
+
+  public final class LayoutInflaterCompat {
+    method @Deprecated public static androidx.core.view.LayoutInflaterFactory! getFactory(android.view.LayoutInflater!);
+    method @Deprecated public static void setFactory(android.view.LayoutInflater, androidx.core.view.LayoutInflaterFactory);
+    method public static void setFactory2(android.view.LayoutInflater, android.view.LayoutInflater.Factory2);
+  }
+
+  @Deprecated public interface LayoutInflaterFactory {
+    method @Deprecated public android.view.View! onCreateView(android.view.View!, String!, android.content.Context!, android.util.AttributeSet!);
+  }
+
+  public final class MarginLayoutParamsCompat {
+    method public static int getLayoutDirection(android.view.ViewGroup.MarginLayoutParams!);
+    method public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams!);
+    method public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams!);
+    method public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams!);
+    method public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams!, int);
+    method public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams!, int);
+    method public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams!, int);
+    method public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams!, int);
+  }
+
+  public final class MenuCompat {
+    method public static void setGroupDividerEnabled(android.view.Menu!, boolean);
+    method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+  }
+
+  public final class MenuItemCompat {
+    method @Deprecated public static boolean collapseActionView(android.view.MenuItem!);
+    method @Deprecated public static boolean expandActionView(android.view.MenuItem!);
+    method public static androidx.core.view.ActionProvider! getActionProvider(android.view.MenuItem!);
+    method @Deprecated public static android.view.View! getActionView(android.view.MenuItem!);
+    method public static int getAlphabeticModifiers(android.view.MenuItem!);
+    method public static CharSequence! getContentDescription(android.view.MenuItem!);
+    method public static android.content.res.ColorStateList! getIconTintList(android.view.MenuItem!);
+    method public static android.graphics.PorterDuff.Mode! getIconTintMode(android.view.MenuItem!);
+    method public static int getNumericModifiers(android.view.MenuItem!);
+    method public static CharSequence! getTooltipText(android.view.MenuItem!);
+    method @Deprecated public static boolean isActionViewExpanded(android.view.MenuItem!);
+    method public static android.view.MenuItem! setActionProvider(android.view.MenuItem!, androidx.core.view.ActionProvider!);
+    method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, android.view.View!);
+    method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, int);
+    method public static void setAlphabeticShortcut(android.view.MenuItem!, char, int);
+    method public static void setContentDescription(android.view.MenuItem!, CharSequence!);
+    method public static void setIconTintList(android.view.MenuItem!, android.content.res.ColorStateList!);
+    method public static void setIconTintMode(android.view.MenuItem!, android.graphics.PorterDuff.Mode!);
+    method public static void setNumericShortcut(android.view.MenuItem!, char, int);
+    method @Deprecated public static android.view.MenuItem! setOnActionExpandListener(android.view.MenuItem!, androidx.core.view.MenuItemCompat.OnActionExpandListener!);
+    method public static void setShortcut(android.view.MenuItem!, char, char, int, int);
+    method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+    method public static void setTooltipText(android.view.MenuItem!, CharSequence!);
+    field @Deprecated public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+    field @Deprecated public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+    field @Deprecated public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+    field @Deprecated public static final int SHOW_AS_ACTION_NEVER = 0; // 0x0
+    field @Deprecated public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+  }
+
+  @Deprecated public static interface MenuItemCompat.OnActionExpandListener {
+    method @Deprecated public boolean onMenuItemActionCollapse(android.view.MenuItem!);
+    method @Deprecated public boolean onMenuItemActionExpand(android.view.MenuItem!);
+  }
+
+  public final class MotionEventCompat {
+    method @Deprecated public static int findPointerIndex(android.view.MotionEvent!, int);
+    method @Deprecated public static int getActionIndex(android.view.MotionEvent!);
+    method @Deprecated public static int getActionMasked(android.view.MotionEvent!);
+    method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int);
+    method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int, int);
+    method @Deprecated public static int getButtonState(android.view.MotionEvent!);
+    method @Deprecated public static int getPointerCount(android.view.MotionEvent!);
+    method @Deprecated public static int getPointerId(android.view.MotionEvent!, int);
+    method @Deprecated public static int getSource(android.view.MotionEvent!);
+    method @Deprecated public static float getX(android.view.MotionEvent!, int);
+    method @Deprecated public static float getY(android.view.MotionEvent!, int);
+    method public static boolean isFromSource(android.view.MotionEvent!, int);
+    field @Deprecated public static final int ACTION_HOVER_ENTER = 9; // 0x9
+    field @Deprecated public static final int ACTION_HOVER_EXIT = 10; // 0xa
+    field @Deprecated public static final int ACTION_HOVER_MOVE = 7; // 0x7
+    field @Deprecated public static final int ACTION_MASK = 255; // 0xff
+    field @Deprecated public static final int ACTION_POINTER_DOWN = 5; // 0x5
+    field @Deprecated public static final int ACTION_POINTER_INDEX_MASK = 65280; // 0xff00
+    field @Deprecated public static final int ACTION_POINTER_INDEX_SHIFT = 8; // 0x8
+    field @Deprecated public static final int ACTION_POINTER_UP = 6; // 0x6
+    field @Deprecated public static final int ACTION_SCROLL = 8; // 0x8
+    field @Deprecated public static final int AXIS_BRAKE = 23; // 0x17
+    field @Deprecated public static final int AXIS_DISTANCE = 24; // 0x18
+    field @Deprecated public static final int AXIS_GAS = 22; // 0x16
+    field @Deprecated public static final int AXIS_GENERIC_1 = 32; // 0x20
+    field @Deprecated public static final int AXIS_GENERIC_10 = 41; // 0x29
+    field @Deprecated public static final int AXIS_GENERIC_11 = 42; // 0x2a
+    field @Deprecated public static final int AXIS_GENERIC_12 = 43; // 0x2b
+    field @Deprecated public static final int AXIS_GENERIC_13 = 44; // 0x2c
+    field @Deprecated public static final int AXIS_GENERIC_14 = 45; // 0x2d
+    field @Deprecated public static final int AXIS_GENERIC_15 = 46; // 0x2e
+    field @Deprecated public static final int AXIS_GENERIC_16 = 47; // 0x2f
+    field @Deprecated public static final int AXIS_GENERIC_2 = 33; // 0x21
+    field @Deprecated public static final int AXIS_GENERIC_3 = 34; // 0x22
+    field @Deprecated public static final int AXIS_GENERIC_4 = 35; // 0x23
+    field @Deprecated public static final int AXIS_GENERIC_5 = 36; // 0x24
+    field @Deprecated public static final int AXIS_GENERIC_6 = 37; // 0x25
+    field @Deprecated public static final int AXIS_GENERIC_7 = 38; // 0x26
+    field @Deprecated public static final int AXIS_GENERIC_8 = 39; // 0x27
+    field @Deprecated public static final int AXIS_GENERIC_9 = 40; // 0x28
+    field @Deprecated public static final int AXIS_HAT_X = 15; // 0xf
+    field @Deprecated public static final int AXIS_HAT_Y = 16; // 0x10
+    field @Deprecated public static final int AXIS_HSCROLL = 10; // 0xa
+    field @Deprecated public static final int AXIS_LTRIGGER = 17; // 0x11
+    field @Deprecated public static final int AXIS_ORIENTATION = 8; // 0x8
+    field @Deprecated public static final int AXIS_PRESSURE = 2; // 0x2
+    field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+    field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
+    field @Deprecated public static final int AXIS_RTRIGGER = 18; // 0x12
+    field @Deprecated public static final int AXIS_RUDDER = 20; // 0x14
+    field @Deprecated public static final int AXIS_RX = 12; // 0xc
+    field @Deprecated public static final int AXIS_RY = 13; // 0xd
+    field @Deprecated public static final int AXIS_RZ = 14; // 0xe
+    field public static final int AXIS_SCROLL = 26; // 0x1a
+    field @Deprecated public static final int AXIS_SIZE = 3; // 0x3
+    field @Deprecated public static final int AXIS_THROTTLE = 19; // 0x13
+    field @Deprecated public static final int AXIS_TILT = 25; // 0x19
+    field @Deprecated public static final int AXIS_TOOL_MAJOR = 6; // 0x6
+    field @Deprecated public static final int AXIS_TOOL_MINOR = 7; // 0x7
+    field @Deprecated public static final int AXIS_TOUCH_MAJOR = 4; // 0x4
+    field @Deprecated public static final int AXIS_TOUCH_MINOR = 5; // 0x5
+    field @Deprecated public static final int AXIS_VSCROLL = 9; // 0x9
+    field @Deprecated public static final int AXIS_WHEEL = 21; // 0x15
+    field @Deprecated public static final int AXIS_X = 0; // 0x0
+    field @Deprecated public static final int AXIS_Y = 1; // 0x1
+    field @Deprecated public static final int AXIS_Z = 11; // 0xb
+    field @Deprecated public static final int BUTTON_PRIMARY = 1; // 0x1
+  }
+
+  public interface NestedScrollingChild {
+    method public boolean dispatchNestedFling(float, float, boolean);
+    method public boolean dispatchNestedPreFling(float, float);
+    method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+    method public boolean hasNestedScrollingParent();
+    method public boolean isNestedScrollingEnabled();
+    method public void setNestedScrollingEnabled(boolean);
+    method public boolean startNestedScroll(int);
+    method public void stopNestedScroll();
+  }
+
+  public interface NestedScrollingChild2 extends androidx.core.view.NestedScrollingChild {
+    method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, int);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]?, int);
+    method public boolean hasNestedScrollingParent(int);
+    method public boolean startNestedScroll(int, int);
+    method public void stopNestedScroll(int);
+  }
+
+  public interface NestedScrollingChild3 extends androidx.core.view.NestedScrollingChild2 {
+    method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]);
+  }
+
+  public class NestedScrollingChildHelper {
+    ctor public NestedScrollingChildHelper(android.view.View);
+    method public boolean dispatchNestedFling(float, float, boolean);
+    method public boolean dispatchNestedPreFling(float, float);
+    method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+    method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, int);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]?, int);
+    method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]?);
+    method public boolean hasNestedScrollingParent();
+    method public boolean hasNestedScrollingParent(int);
+    method public boolean isNestedScrollingEnabled();
+    method public void onDetachedFromWindow();
+    method public void onStopNestedScroll(android.view.View);
+    method public void setNestedScrollingEnabled(boolean);
+    method public boolean startNestedScroll(int);
+    method public boolean startNestedScroll(int, int);
+    method public void stopNestedScroll();
+    method public void stopNestedScroll(int);
+  }
+
+  public interface NestedScrollingParent {
+    method public int getNestedScrollAxes();
+    method public boolean onNestedFling(android.view.View, float, float, boolean);
+    method public boolean onNestedPreFling(android.view.View, float, float);
+    method public void onNestedPreScroll(android.view.View, int, int, int[]);
+    method public void onNestedScroll(android.view.View, int, int, int, int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+    method public boolean onStartNestedScroll(android.view.View, android.view.View, int);
+    method public void onStopNestedScroll(android.view.View);
+  }
+
+  public interface NestedScrollingParent2 extends androidx.core.view.NestedScrollingParent {
+    method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+    method public void onNestedScroll(android.view.View, int, int, int, int, int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+    method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+    method public void onStopNestedScroll(android.view.View, int);
+  }
+
+  public interface NestedScrollingParent3 extends androidx.core.view.NestedScrollingParent2 {
+    method public void onNestedScroll(android.view.View, int, int, int, int, int, int[]);
+  }
+
+  public class NestedScrollingParentHelper {
+    ctor public NestedScrollingParentHelper(android.view.ViewGroup);
+    method public int getNestedScrollAxes();
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+    method public void onStopNestedScroll(android.view.View);
+    method public void onStopNestedScroll(android.view.View, int);
+  }
+
+  public interface OnApplyWindowInsetsListener {
+    method public androidx.core.view.WindowInsetsCompat! onApplyWindowInsets(android.view.View!, androidx.core.view.WindowInsetsCompat!);
+  }
+
+  public interface OnReceiveContentListener {
+    method public androidx.core.view.ContentInfoCompat? onReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+  }
+
+  public interface OnReceiveContentViewBehavior {
+    method public androidx.core.view.ContentInfoCompat? onReceiveContent(androidx.core.view.ContentInfoCompat);
+  }
+
+  public final class OneShotPreDrawListener implements android.view.View.OnAttachStateChangeListener android.view.ViewTreeObserver.OnPreDrawListener {
+    method public static androidx.core.view.OneShotPreDrawListener add(android.view.View, Runnable);
+    method public boolean onPreDraw();
+    method public void onViewAttachedToWindow(android.view.View!);
+    method public void onViewDetachedFromWindow(android.view.View!);
+    method public void removeListener();
+  }
+
+  public final class PointerIconCompat {
+    method public static androidx.core.view.PointerIconCompat! create(android.graphics.Bitmap!, float, float);
+    method public static androidx.core.view.PointerIconCompat! getSystemIcon(android.content.Context!, int);
+    method public static androidx.core.view.PointerIconCompat! load(android.content.res.Resources!, int);
+    field public static final int TYPE_ALIAS = 1010; // 0x3f2
+    field public static final int TYPE_ALL_SCROLL = 1013; // 0x3f5
+    field public static final int TYPE_ARROW = 1000; // 0x3e8
+    field public static final int TYPE_CELL = 1006; // 0x3ee
+    field public static final int TYPE_CONTEXT_MENU = 1001; // 0x3e9
+    field public static final int TYPE_COPY = 1011; // 0x3f3
+    field public static final int TYPE_CROSSHAIR = 1007; // 0x3ef
+    field public static final int TYPE_DEFAULT = 1000; // 0x3e8
+    field public static final int TYPE_GRAB = 1020; // 0x3fc
+    field public static final int TYPE_GRABBING = 1021; // 0x3fd
+    field public static final int TYPE_HAND = 1002; // 0x3ea
+    field public static final int TYPE_HELP = 1003; // 0x3eb
+    field public static final int TYPE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6
+    field public static final int TYPE_NO_DROP = 1012; // 0x3f4
+    field public static final int TYPE_NULL = 0; // 0x0
+    field public static final int TYPE_TEXT = 1008; // 0x3f0
+    field public static final int TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9
+    field public static final int TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8
+    field public static final int TYPE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7
+    field public static final int TYPE_VERTICAL_TEXT = 1009; // 0x3f1
+    field public static final int TYPE_WAIT = 1004; // 0x3ec
+    field public static final int TYPE_ZOOM_IN = 1018; // 0x3fa
+    field public static final int TYPE_ZOOM_OUT = 1019; // 0x3fb
+  }
+
+  public final class ScaleGestureDetectorCompat {
+    method @Deprecated public static boolean isQuickScaleEnabled(Object!);
+    method public static boolean isQuickScaleEnabled(android.view.ScaleGestureDetector!);
+    method @Deprecated public static void setQuickScaleEnabled(Object!, boolean);
+    method public static void setQuickScaleEnabled(android.view.ScaleGestureDetector!, boolean);
+  }
+
+  public interface ScrollingView {
+    method public int computeHorizontalScrollExtent();
+    method public int computeHorizontalScrollOffset();
+    method public int computeHorizontalScrollRange();
+    method public int computeVerticalScrollExtent();
+    method public int computeVerticalScrollOffset();
+    method public int computeVerticalScrollRange();
+  }
+
+  public interface TintableBackgroundView {
+    method public android.content.res.ColorStateList? getSupportBackgroundTintList();
+    method public android.graphics.PorterDuff.Mode? getSupportBackgroundTintMode();
+    method public void setSupportBackgroundTintList(android.content.res.ColorStateList?);
+    method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode?);
+  }
+
+  @Deprecated public final class VelocityTrackerCompat {
+    method @Deprecated public static float getXVelocity(android.view.VelocityTracker!, int);
+    method @Deprecated public static float getYVelocity(android.view.VelocityTracker!, int);
+  }
+
+  public class ViewCompat {
+    ctor @Deprecated protected ViewCompat();
+    method public static int addAccessibilityAction(android.view.View, CharSequence, androidx.core.view.accessibility.AccessibilityViewCommand);
+    method public static void addKeyboardNavigationClusters(android.view.View, java.util.Collection<android.view.View!>, int);
+    method public static void addOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+    method public static androidx.core.view.ViewPropertyAnimatorCompat animate(android.view.View);
+    method @Deprecated public static boolean canScrollHorizontally(android.view.View!, int);
+    method @Deprecated public static boolean canScrollVertically(android.view.View!, int);
+    method public static void cancelDragAndDrop(android.view.View);
+    method @Deprecated public static int combineMeasuredStates(int, int);
+    method public static androidx.core.view.WindowInsetsCompat computeSystemWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat, android.graphics.Rect);
+    method public static androidx.core.view.WindowInsetsCompat dispatchApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+    method public static void dispatchFinishTemporaryDetach(android.view.View);
+    method public static boolean dispatchNestedFling(android.view.View, float, float, boolean);
+    method public static boolean dispatchNestedPreFling(android.view.View, float, float);
+    method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?);
+    method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?, int);
+    method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?);
+    method public static void dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, int, int[]);
+    method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, int);
+    method public static void dispatchStartTemporaryDetach(android.view.View);
+    method public static void enableAccessibleClickableSpanSupport(android.view.View!);
+    method public static int generateViewId();
+    method public static androidx.core.view.AccessibilityDelegateCompat? getAccessibilityDelegate(android.view.View);
+    method public static int getAccessibilityLiveRegion(android.view.View);
+    method public static androidx.core.view.accessibility.AccessibilityNodeProviderCompat! getAccessibilityNodeProvider(android.view.View);
+    method @UiThread public static CharSequence! getAccessibilityPaneTitle(android.view.View!);
+    method @Deprecated public static float getAlpha(android.view.View!);
+    method public static android.content.res.ColorStateList! getBackgroundTintList(android.view.View);
+    method public static android.graphics.PorterDuff.Mode! getBackgroundTintMode(android.view.View);
+    method public static android.graphics.Rect? getClipBounds(android.view.View);
+    method public static android.view.Display? getDisplay(android.view.View);
+    method public static float getElevation(android.view.View);
+    method public static boolean getFitsSystemWindows(android.view.View);
+    method public static int getImportantForAccessibility(android.view.View);
+    method public static int getImportantForAutofill(android.view.View);
+    method public static int getLabelFor(android.view.View);
+    method @Deprecated public static int getLayerType(android.view.View!);
+    method public static int getLayoutDirection(android.view.View);
+    method @Deprecated public static android.graphics.Matrix? getMatrix(android.view.View!);
+    method @Deprecated public static int getMeasuredHeightAndState(android.view.View!);
+    method @Deprecated public static int getMeasuredState(android.view.View!);
+    method @Deprecated public static int getMeasuredWidthAndState(android.view.View!);
+    method public static int getMinimumHeight(android.view.View);
+    method public static int getMinimumWidth(android.view.View);
+    method public static int getNextClusterForwardId(android.view.View);
+    method public static String![]? getOnReceiveContentMimeTypes(android.view.View);
+    method @Deprecated public static int getOverScrollMode(android.view.View!);
+    method @Px public static int getPaddingEnd(android.view.View);
+    method @Px public static int getPaddingStart(android.view.View);
+    method public static android.view.ViewParent! getParentForAccessibility(android.view.View);
+    method @Deprecated public static float getPivotX(android.view.View!);
+    method @Deprecated public static float getPivotY(android.view.View!);
+    method public static androidx.core.view.WindowInsetsCompat? getRootWindowInsets(android.view.View);
+    method @Deprecated public static float getRotation(android.view.View!);
+    method @Deprecated public static float getRotationX(android.view.View!);
+    method @Deprecated public static float getRotationY(android.view.View!);
+    method @Deprecated public static float getScaleX(android.view.View!);
+    method @Deprecated public static float getScaleY(android.view.View!);
+    method public static int getScrollIndicators(android.view.View);
+    method @UiThread public static final CharSequence? getStateDescription(android.view.View);
+    method public static java.util.List<android.graphics.Rect!> getSystemGestureExclusionRects(android.view.View);
+    method public static String? getTransitionName(android.view.View);
+    method @Deprecated public static float getTranslationX(android.view.View!);
+    method @Deprecated public static float getTranslationY(android.view.View!);
+    method public static float getTranslationZ(android.view.View);
+    method public static androidx.core.view.WindowInsetsControllerCompat? getWindowInsetsController(android.view.View);
+    method public static int getWindowSystemUiVisibility(android.view.View);
+    method @Deprecated public static float getX(android.view.View!);
+    method @Deprecated public static float getY(android.view.View!);
+    method public static float getZ(android.view.View);
+    method public static boolean hasAccessibilityDelegate(android.view.View);
+    method public static boolean hasExplicitFocusable(android.view.View);
+    method public static boolean hasNestedScrollingParent(android.view.View);
+    method public static boolean hasNestedScrollingParent(android.view.View, int);
+    method public static boolean hasOnClickListeners(android.view.View);
+    method public static boolean hasOverlappingRendering(android.view.View);
+    method public static boolean hasTransientState(android.view.View);
+    method @UiThread public static boolean isAccessibilityHeading(android.view.View!);
+    method public static boolean isAttachedToWindow(android.view.View);
+    method public static boolean isFocusedByDefault(android.view.View);
+    method public static boolean isImportantForAccessibility(android.view.View);
+    method public static boolean isImportantForAutofill(android.view.View);
+    method public static boolean isInLayout(android.view.View);
+    method public static boolean isKeyboardNavigationCluster(android.view.View);
+    method public static boolean isLaidOut(android.view.View);
+    method public static boolean isLayoutDirectionResolved(android.view.View);
+    method public static boolean isNestedScrollingEnabled(android.view.View);
+    method @Deprecated public static boolean isOpaque(android.view.View!);
+    method public static boolean isPaddingRelative(android.view.View);
+    method @UiThread public static boolean isScreenReaderFocusable(android.view.View!);
+    method @Deprecated public static void jumpDrawablesToCurrentState(android.view.View!);
+    method public static android.view.View! keyboardNavigationClusterSearch(android.view.View, android.view.View!, int);
+    method public static void offsetLeftAndRight(android.view.View, int);
+    method public static void offsetTopAndBottom(android.view.View, int);
+    method public static androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+    method @Deprecated public static void onInitializeAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public static void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat!);
+    method @Deprecated public static void onPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle!);
+    method public static androidx.core.view.ContentInfoCompat? performReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+    method public static void postInvalidateOnAnimation(android.view.View);
+    method public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
+    method public static void postOnAnimation(android.view.View, Runnable!);
+    method public static void postOnAnimationDelayed(android.view.View, Runnable!, long);
+    method public static void removeAccessibilityAction(android.view.View, int);
+    method public static void removeOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+    method public static void replaceAccessibilityAction(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat, CharSequence?, androidx.core.view.accessibility.AccessibilityViewCommand?);
+    method public static void requestApplyInsets(android.view.View);
+    method public static <T extends android.view.View> T requireViewById(android.view.View, @IdRes int);
+    method @Deprecated public static int resolveSizeAndState(int, int, int);
+    method public static boolean restoreDefaultFocus(android.view.View);
+    method public static void saveAttributeDataForStyleable(android.view.View, android.content.Context, int[], android.util.AttributeSet?, android.content.res.TypedArray, int, int);
+    method public static void setAccessibilityDelegate(android.view.View, androidx.core.view.AccessibilityDelegateCompat!);
+    method @UiThread public static void setAccessibilityHeading(android.view.View!, boolean);
+    method public static void setAccessibilityLiveRegion(android.view.View, int);
+    method @UiThread public static void setAccessibilityPaneTitle(android.view.View!, CharSequence!);
+    method @Deprecated public static void setActivated(android.view.View!, boolean);
+    method @Deprecated public static void setAlpha(android.view.View!, @FloatRange(from=0.0, to=1.0) float);
+    method public static void setAutofillHints(android.view.View, java.lang.String!...);
+    method public static void setBackground(android.view.View, android.graphics.drawable.Drawable?);
+    method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList!);
+    method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode!);
+    method @Deprecated public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup!, boolean);
+    method public static void setClipBounds(android.view.View, android.graphics.Rect!);
+    method public static void setElevation(android.view.View, float);
+    method @Deprecated public static void setFitsSystemWindows(android.view.View!, boolean);
+    method public static void setFocusedByDefault(android.view.View, boolean);
+    method public static void setHasTransientState(android.view.View, boolean);
+    method public static void setImportantForAccessibility(android.view.View, int);
+    method public static void setImportantForAutofill(android.view.View, int);
+    method public static void setKeyboardNavigationCluster(android.view.View, boolean);
+    method public static void setLabelFor(android.view.View, @IdRes int);
+    method public static void setLayerPaint(android.view.View, android.graphics.Paint!);
+    method @Deprecated public static void setLayerType(android.view.View!, int, android.graphics.Paint!);
+    method public static void setLayoutDirection(android.view.View, int);
+    method public static void setNestedScrollingEnabled(android.view.View, boolean);
+    method public static void setNextClusterForwardId(android.view.View, int);
+    method public static void setOnApplyWindowInsetsListener(android.view.View, androidx.core.view.OnApplyWindowInsetsListener?);
+    method public static void setOnReceiveContentListener(android.view.View, String![]?, androidx.core.view.OnReceiveContentListener?);
+    method @Deprecated public static void setOverScrollMode(android.view.View!, int);
+    method public static void setPaddingRelative(android.view.View, @Px int, @Px int, @Px int, @Px int);
+    method @Deprecated public static void setPivotX(android.view.View!, float);
+    method @Deprecated public static void setPivotY(android.view.View!, float);
+    method public static void setPointerIcon(android.view.View, androidx.core.view.PointerIconCompat!);
+    method @Deprecated public static void setRotation(android.view.View!, float);
+    method @Deprecated public static void setRotationX(android.view.View!, float);
+    method @Deprecated public static void setRotationY(android.view.View!, float);
+    method @Deprecated public static void setSaveFromParentEnabled(android.view.View!, boolean);
+    method @Deprecated public static void setScaleX(android.view.View!, float);
+    method @Deprecated public static void setScaleY(android.view.View!, float);
+    method @UiThread public static void setScreenReaderFocusable(android.view.View!, boolean);
+    method public static void setScrollIndicators(android.view.View, int);
+    method public static void setScrollIndicators(android.view.View, int, int);
+    method @UiThread public static void setStateDescription(android.view.View, CharSequence?);
+    method public static void setSystemGestureExclusionRects(android.view.View, java.util.List<android.graphics.Rect!>);
+    method public static void setTooltipText(android.view.View, CharSequence?);
+    method public static void setTransitionName(android.view.View, String!);
+    method @Deprecated public static void setTranslationX(android.view.View!, float);
+    method @Deprecated public static void setTranslationY(android.view.View!, float);
+    method public static void setTranslationZ(android.view.View, float);
+    method public static void setWindowInsetsAnimationCallback(android.view.View, androidx.core.view.WindowInsetsAnimationCompat.Callback?);
+    method @Deprecated public static void setX(android.view.View!, float);
+    method @Deprecated public static void setY(android.view.View!, float);
+    method public static void setZ(android.view.View, float);
+    method public static boolean startDragAndDrop(android.view.View, android.content.ClipData!, android.view.View.DragShadowBuilder!, Object!, int);
+    method public static boolean startNestedScroll(android.view.View, int);
+    method public static boolean startNestedScroll(android.view.View, int, int);
+    method public static void stopNestedScroll(android.view.View);
+    method public static void stopNestedScroll(android.view.View, int);
+    method public static void updateDragShadow(android.view.View, android.view.View.DragShadowBuilder!);
+    field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
+    field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
+    field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0; // 0x0
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
+    field @Deprecated public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
+    field @Deprecated public static final int LAYER_TYPE_NONE = 0; // 0x0
+    field @Deprecated public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
+    field public static final int LAYOUT_DIRECTION_INHERIT = 2; // 0x2
+    field public static final int LAYOUT_DIRECTION_LOCALE = 3; // 0x3
+    field public static final int LAYOUT_DIRECTION_LTR = 0; // 0x0
+    field public static final int LAYOUT_DIRECTION_RTL = 1; // 0x1
+    field @Deprecated public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
+    field @Deprecated public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
+    field @Deprecated public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
+    field @Deprecated public static final int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+    field @Deprecated public static final int OVER_SCROLL_ALWAYS = 0; // 0x0
+    field @Deprecated public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
+    field @Deprecated public static final int OVER_SCROLL_NEVER = 2; // 0x2
+    field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
+    field public static final int SCROLL_AXIS_NONE = 0; // 0x0
+    field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+    field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
+    field public static final int SCROLL_INDICATOR_END = 32; // 0x20
+    field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
+    field public static final int SCROLL_INDICATOR_RIGHT = 8; // 0x8
+    field public static final int SCROLL_INDICATOR_START = 16; // 0x10
+    field public static final int SCROLL_INDICATOR_TOP = 1; // 0x1
+    field public static final int TYPE_NON_TOUCH = 1; // 0x1
+    field public static final int TYPE_TOUCH = 0; // 0x0
+  }
+
+  public static interface ViewCompat.OnUnhandledKeyEventListenerCompat {
+    method public boolean onUnhandledKeyEvent(android.view.View!, android.view.KeyEvent!);
+  }
+
+  public final class ViewConfigurationCompat {
+    method public static float getScaledHorizontalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+    method public static int getScaledHoverSlop(android.view.ViewConfiguration!);
+    method @Deprecated public static int getScaledPagingTouchSlop(android.view.ViewConfiguration!);
+    method public static float getScaledVerticalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+    method @Deprecated public static boolean hasPermanentMenuKey(android.view.ViewConfiguration!);
+    method public static boolean shouldShowMenuShortcutsWhenKeyboardPresent(android.view.ViewConfiguration!, android.content.Context);
+  }
+
+  public final class ViewGroupCompat {
+    method public static int getLayoutMode(android.view.ViewGroup);
+    method public static int getNestedScrollAxes(android.view.ViewGroup);
+    method public static boolean isTransitionGroup(android.view.ViewGroup);
+    method @Deprecated public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public static void setLayoutMode(android.view.ViewGroup, int);
+    method @Deprecated public static void setMotionEventSplittingEnabled(android.view.ViewGroup!, boolean);
+    method public static void setTransitionGroup(android.view.ViewGroup, boolean);
+    field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
+    field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
+  }
+
+  public final class ViewParentCompat {
+    method public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent!, android.view.View!, android.view.View!, int);
+    method public static boolean onNestedFling(android.view.ViewParent!, android.view.View!, float, float, boolean);
+    method public static boolean onNestedPreFling(android.view.ViewParent!, android.view.View!, float, float);
+    method public static void onNestedPreScroll(android.view.ViewParent!, android.view.View!, int, int, int[]!);
+    method public static void onNestedPreScroll(android.view.ViewParent!, android.view.View!, int, int, int[]!, int);
+    method public static void onNestedScroll(android.view.ViewParent!, android.view.View!, int, int, int, int);
+    method public static void onNestedScroll(android.view.ViewParent!, android.view.View!, int, int, int, int, int);
+    method public static void onNestedScroll(android.view.ViewParent!, android.view.View!, int, int, int, int, int, int[]);
+    method public static void onNestedScrollAccepted(android.view.ViewParent!, android.view.View!, android.view.View!, int);
+    method public static void onNestedScrollAccepted(android.view.ViewParent!, android.view.View!, android.view.View!, int, int);
+    method public static boolean onStartNestedScroll(android.view.ViewParent!, android.view.View!, android.view.View!, int);
+    method public static boolean onStartNestedScroll(android.view.ViewParent!, android.view.View!, android.view.View!, int, int);
+    method public static void onStopNestedScroll(android.view.ViewParent!, android.view.View!);
+    method public static void onStopNestedScroll(android.view.ViewParent!, android.view.View!, int);
+    method @Deprecated public static boolean requestSendAccessibilityEvent(android.view.ViewParent!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+  }
+
+  public final class ViewPropertyAnimatorCompat {
+    method public androidx.core.view.ViewPropertyAnimatorCompat! alpha(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! alphaBy(float);
+    method public void cancel();
+    method public long getDuration();
+    method public android.view.animation.Interpolator! getInterpolator();
+    method public long getStartDelay();
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotation(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotationBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotationX(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotationXBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotationY(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotationYBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! scaleX(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! scaleXBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! scaleY(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! scaleYBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! setDuration(long);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! setInterpolator(android.view.animation.Interpolator!);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! setListener(androidx.core.view.ViewPropertyAnimatorListener!);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! setStartDelay(long);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! setUpdateListener(androidx.core.view.ViewPropertyAnimatorUpdateListener!);
+    method public void start();
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationX(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationXBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationY(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationYBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationZ(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationZBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! withEndAction(Runnable!);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! withLayer();
+    method public androidx.core.view.ViewPropertyAnimatorCompat! withStartAction(Runnable!);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! x(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! xBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! y(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! yBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! z(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! zBy(float);
+  }
+
+  public interface ViewPropertyAnimatorListener {
+    method public void onAnimationCancel(android.view.View!);
+    method public void onAnimationEnd(android.view.View!);
+    method public void onAnimationStart(android.view.View!);
+  }
+
+  public class ViewPropertyAnimatorListenerAdapter implements androidx.core.view.ViewPropertyAnimatorListener {
+    ctor public ViewPropertyAnimatorListenerAdapter();
+    method public void onAnimationCancel(android.view.View!);
+    method public void onAnimationEnd(android.view.View!);
+    method public void onAnimationStart(android.view.View!);
+  }
+
+  public interface ViewPropertyAnimatorUpdateListener {
+    method public void onAnimationUpdate(android.view.View!);
+  }
+
+  public final class WindowCompat {
+    method public static androidx.core.view.WindowInsetsControllerCompat? getInsetsController(android.view.Window, android.view.View);
+    method public static <T extends android.view.View> T requireViewById(android.view.Window, @IdRes int);
+    method public static void setDecorFitsSystemWindows(android.view.Window, boolean);
+    field public static final int FEATURE_ACTION_BAR = 8; // 0x8
+    field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
+    field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+  }
+
+  public final class WindowInsetsAnimationCompat {
+    ctor public WindowInsetsAnimationCompat(int, android.view.animation.Interpolator?, long);
+    method @FloatRange(from=0.0f, to=1.0f) public float getAlpha();
+    method public long getDurationMillis();
+    method @FloatRange(from=0.0f, to=1.0f) public float getFraction();
+    method public float getInterpolatedFraction();
+    method public android.view.animation.Interpolator? getInterpolator();
+    method public int getTypeMask();
+    method public void setAlpha(@FloatRange(from=0.0f, to=1.0f) float);
+    method public void setFraction(@FloatRange(from=0.0f, to=1.0f) float);
+  }
+
+  public static final class WindowInsetsAnimationCompat.BoundsCompat {
+    ctor public WindowInsetsAnimationCompat.BoundsCompat(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+    method public androidx.core.graphics.Insets getLowerBound();
+    method public androidx.core.graphics.Insets getUpperBound();
+    method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat inset(androidx.core.graphics.Insets);
+    method @RequiresApi(30) public android.view.WindowInsetsAnimation.Bounds toBounds();
+    method @RequiresApi(30) public static androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat toBoundsCompat(android.view.WindowInsetsAnimation.Bounds);
+  }
+
+  public abstract static class WindowInsetsAnimationCompat.Callback {
+    ctor public WindowInsetsAnimationCompat.Callback(int);
+    method public final int getDispatchMode();
+    method public void onEnd(androidx.core.view.WindowInsetsAnimationCompat);
+    method public void onPrepare(androidx.core.view.WindowInsetsAnimationCompat);
+    method public abstract androidx.core.view.WindowInsetsCompat onProgress(androidx.core.view.WindowInsetsCompat, java.util.List<androidx.core.view.WindowInsetsAnimationCompat!>);
+    method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat onStart(androidx.core.view.WindowInsetsAnimationCompat, androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat);
+    field public static final int DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1; // 0x1
+    field public static final int DISPATCH_MODE_STOP = 0; // 0x0
+  }
+
+  public interface WindowInsetsAnimationControlListenerCompat {
+    method public void onCancelled(androidx.core.view.WindowInsetsAnimationControllerCompat?);
+    method public void onFinished(androidx.core.view.WindowInsetsAnimationControllerCompat);
+    method public void onReady(androidx.core.view.WindowInsetsAnimationControllerCompat, int);
+  }
+
+  public final class WindowInsetsAnimationControllerCompat {
+    method public void finish(boolean);
+    method public float getCurrentAlpha();
+    method @FloatRange(from=0.0f, to=1.0f) public float getCurrentFraction();
+    method public androidx.core.graphics.Insets getCurrentInsets();
+    method public androidx.core.graphics.Insets getHiddenStateInsets();
+    method public androidx.core.graphics.Insets getShownStateInsets();
+    method public int getTypes();
+    method public boolean isCancelled();
+    method public boolean isFinished();
+    method public boolean isReady();
+    method public void setInsetsAndAlpha(androidx.core.graphics.Insets?, @FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float);
+  }
+
+  public class WindowInsetsCompat {
+    ctor public WindowInsetsCompat(androidx.core.view.WindowInsetsCompat?);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat consumeDisplayCutout();
+    method @Deprecated public androidx.core.view.WindowInsetsCompat consumeStableInsets();
+    method @Deprecated public androidx.core.view.WindowInsetsCompat consumeSystemWindowInsets();
+    method public androidx.core.view.DisplayCutoutCompat? getDisplayCutout();
+    method public androidx.core.graphics.Insets getInsets(int);
+    method public androidx.core.graphics.Insets getInsetsIgnoringVisibility(int);
+    method @Deprecated public androidx.core.graphics.Insets getMandatorySystemGestureInsets();
+    method @Deprecated public int getStableInsetBottom();
+    method @Deprecated public int getStableInsetLeft();
+    method @Deprecated public int getStableInsetRight();
+    method @Deprecated public int getStableInsetTop();
+    method @Deprecated public androidx.core.graphics.Insets getStableInsets();
+    method @Deprecated public androidx.core.graphics.Insets getSystemGestureInsets();
+    method @Deprecated public int getSystemWindowInsetBottom();
+    method @Deprecated public int getSystemWindowInsetLeft();
+    method @Deprecated public int getSystemWindowInsetRight();
+    method @Deprecated public int getSystemWindowInsetTop();
+    method @Deprecated public androidx.core.graphics.Insets getSystemWindowInsets();
+    method @Deprecated public androidx.core.graphics.Insets getTappableElementInsets();
+    method public boolean hasInsets();
+    method @Deprecated public boolean hasStableInsets();
+    method @Deprecated public boolean hasSystemWindowInsets();
+    method public androidx.core.view.WindowInsetsCompat inset(androidx.core.graphics.Insets);
+    method public androidx.core.view.WindowInsetsCompat inset(@IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+    method public boolean isConsumed();
+    method public boolean isRound();
+    method public boolean isVisible(int);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(int, int, int, int);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(android.graphics.Rect);
+    method @RequiresApi(20) public android.view.WindowInsets? toWindowInsets();
+    method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets);
+    method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets, android.view.View?);
+    field public static final androidx.core.view.WindowInsetsCompat CONSUMED;
+  }
+
+  public static final class WindowInsetsCompat.Builder {
+    ctor public WindowInsetsCompat.Builder();
+    ctor public WindowInsetsCompat.Builder(androidx.core.view.WindowInsetsCompat);
+    method public androidx.core.view.WindowInsetsCompat build();
+    method public androidx.core.view.WindowInsetsCompat.Builder setDisplayCutout(androidx.core.view.DisplayCutoutCompat?);
+    method public androidx.core.view.WindowInsetsCompat.Builder setInsets(int, androidx.core.graphics.Insets);
+    method public androidx.core.view.WindowInsetsCompat.Builder setInsetsIgnoringVisibility(int, androidx.core.graphics.Insets);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setMandatorySystemGestureInsets(androidx.core.graphics.Insets);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setStableInsets(androidx.core.graphics.Insets);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemGestureInsets(androidx.core.graphics.Insets);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemWindowInsets(androidx.core.graphics.Insets);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setTappableElementInsets(androidx.core.graphics.Insets);
+    method public androidx.core.view.WindowInsetsCompat.Builder setVisible(int, boolean);
+  }
+
+  public static final class WindowInsetsCompat.Type {
+    method public static int captionBar();
+    method public static int displayCutout();
+    method public static int ime();
+    method public static int mandatorySystemGestures();
+    method public static int navigationBars();
+    method public static int statusBars();
+    method public static int systemBars();
+    method public static int systemGestures();
+    method public static int tappableElement();
+  }
+
+  public final class WindowInsetsControllerCompat {
+    ctor public WindowInsetsControllerCompat(android.view.Window, android.view.View);
+    method public void addOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+    method public void controlWindowInsetsAnimation(int, long, android.view.animation.Interpolator?, android.os.CancellationSignal?, androidx.core.view.WindowInsetsAnimationControlListenerCompat);
+    method public int getSystemBarsBehavior();
+    method public void hide(int);
+    method public boolean isAppearanceLightNavigationBars();
+    method public boolean isAppearanceLightStatusBars();
+    method public void removeOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+    method public void setAppearanceLightNavigationBars(boolean);
+    method public void setAppearanceLightStatusBars(boolean);
+    method public void setSystemBarsBehavior(int);
+    method public void show(int);
+    method @RequiresApi(30) public static androidx.core.view.WindowInsetsControllerCompat toWindowInsetsControllerCompat(android.view.WindowInsetsController);
+    field public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
+    field public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0; // 0x0
+    field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2
+  }
+
+  public static interface WindowInsetsControllerCompat.OnControllableInsetsChangedListener {
+    method public void onControllableInsetsChanged(androidx.core.view.WindowInsetsControllerCompat, int);
+  }
+
+}
+
+package androidx.core.view.accessibility {
+
+  public final class AccessibilityClickableSpanCompat extends android.text.style.ClickableSpan {
+    method public void onClick(android.view.View);
+  }
+
+  public final class AccessibilityEventCompat {
+    method @Deprecated public static void appendRecord(android.view.accessibility.AccessibilityEvent!, androidx.core.view.accessibility.AccessibilityRecordCompat!);
+    method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! asRecord(android.view.accessibility.AccessibilityEvent!);
+    method public static int getAction(android.view.accessibility.AccessibilityEvent!);
+    method public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent!);
+    method public static int getMovementGranularity(android.view.accessibility.AccessibilityEvent!);
+    method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! getRecord(android.view.accessibility.AccessibilityEvent!, int);
+    method @Deprecated public static int getRecordCount(android.view.accessibility.AccessibilityEvent!);
+    method public static void setAction(android.view.accessibility.AccessibilityEvent!, int);
+    method public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent!, int);
+    method public static void setMovementGranularity(android.view.accessibility.AccessibilityEvent!, int);
+    field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+    field public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 16; // 0x10
+    field public static final int CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 32; // 0x20
+    field public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 8; // 0x8
+    field public static final int CONTENT_CHANGE_TYPE_STATE_DESCRIPTION = 64; // 0x40
+    field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
+    field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
+    field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
+    field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
+    field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
+    field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000
+    field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000
+    field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000
+    field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
+    field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
+    field public static final int TYPE_TOUCH_INTERACTION_END = 2097152; // 0x200000
+    field public static final int TYPE_TOUCH_INTERACTION_START = 1048576; // 0x100000
+    field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 32768; // 0x8000
+    field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 65536; // 0x10000
+    field public static final int TYPE_VIEW_CONTEXT_CLICKED = 8388608; // 0x800000
+    field @Deprecated public static final int TYPE_VIEW_HOVER_ENTER = 128; // 0x80
+    field @Deprecated public static final int TYPE_VIEW_HOVER_EXIT = 256; // 0x100
+    field @Deprecated public static final int TYPE_VIEW_SCROLLED = 4096; // 0x1000
+    field @Deprecated public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192; // 0x2000
+    field public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072; // 0x20000
+    field public static final int TYPE_WINDOWS_CHANGED = 4194304; // 0x400000
+    field @Deprecated public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
+  }
+
+  public final class AccessibilityManagerCompat {
+    method @Deprecated public static boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+    method public static boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener!);
+    method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!, int);
+    method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!);
+    method @Deprecated public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager!);
+    method @Deprecated public static boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+    method public static boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener!);
+  }
+
+  @Deprecated public static interface AccessibilityManagerCompat.AccessibilityStateChangeListener {
+    method @Deprecated public void onAccessibilityStateChanged(boolean);
+  }
+
+  @Deprecated public abstract static class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat implements androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener {
+    ctor @Deprecated public AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat();
+  }
+
+  public static interface AccessibilityManagerCompat.TouchExplorationStateChangeListener {
+    method public void onTouchExplorationStateChanged(boolean);
+  }
+
+  public class AccessibilityNodeInfoCompat {
+    ctor @Deprecated public AccessibilityNodeInfoCompat(Object!);
+    method public void addAction(int);
+    method public void addAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+    method public void addChild(android.view.View!);
+    method public void addChild(android.view.View!, int);
+    method public boolean canOpenPopup();
+    method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByText(String!);
+    method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByViewId(String!);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! findFocus(int);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! focusSearch(int);
+    method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!>! getActionList();
+    method public int getActions();
+    method @Deprecated public void getBoundsInParent(android.graphics.Rect!);
+    method public void getBoundsInScreen(android.graphics.Rect!);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getChild(int);
+    method public int getChildCount();
+    method public CharSequence! getClassName();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! getCollectionInfo();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! getCollectionItemInfo();
+    method public CharSequence! getContentDescription();
+    method public int getDrawingOrder();
+    method public CharSequence! getError();
+    method public android.os.Bundle! getExtras();
+    method public CharSequence? getHintText();
+    method @Deprecated public Object! getInfo();
+    method public int getInputType();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabelFor();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabeledBy();
+    method public int getLiveRegion();
+    method public int getMaxTextLength();
+    method public int getMovementGranularities();
+    method public CharSequence! getPackageName();
+    method public CharSequence? getPaneTitle();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getParent();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! getRangeInfo();
+    method public CharSequence? getRoleDescription();
+    method public CharSequence? getStateDescription();
+    method public CharSequence! getText();
+    method public int getTextSelectionEnd();
+    method public int getTextSelectionStart();
+    method public CharSequence? getTooltipText();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat? getTouchDelegateInfo();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalAfter();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalBefore();
+    method public String! getViewIdResourceName();
+    method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat! getWindow();
+    method public int getWindowId();
+    method public boolean isAccessibilityFocused();
+    method public boolean isCheckable();
+    method public boolean isChecked();
+    method public boolean isClickable();
+    method public boolean isContentInvalid();
+    method public boolean isContextClickable();
+    method public boolean isDismissable();
+    method public boolean isEditable();
+    method public boolean isEnabled();
+    method public boolean isFocusable();
+    method public boolean isFocused();
+    method public boolean isHeading();
+    method public boolean isImportantForAccessibility();
+    method public boolean isLongClickable();
+    method public boolean isMultiLine();
+    method public boolean isPassword();
+    method public boolean isScreenReaderFocusable();
+    method public boolean isScrollable();
+    method public boolean isSelected();
+    method public boolean isShowingHintText();
+    method public boolean isTextEntryKey();
+    method public boolean isVisibleToUser();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!);
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!, int);
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(androidx.core.view.accessibility.AccessibilityNodeInfoCompat!);
+    method public boolean performAction(int);
+    method public boolean performAction(int, android.os.Bundle!);
+    method public void recycle();
+    method public boolean refresh();
+    method public boolean removeAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+    method public boolean removeChild(android.view.View!);
+    method public boolean removeChild(android.view.View!, int);
+    method public void setAccessibilityFocused(boolean);
+    method @Deprecated public void setBoundsInParent(android.graphics.Rect!);
+    method public void setBoundsInScreen(android.graphics.Rect!);
+    method public void setCanOpenPopup(boolean);
+    method public void setCheckable(boolean);
+    method public void setChecked(boolean);
+    method public void setClassName(CharSequence!);
+    method public void setClickable(boolean);
+    method public void setCollectionInfo(Object!);
+    method public void setCollectionItemInfo(Object!);
+    method public void setContentDescription(CharSequence!);
+    method public void setContentInvalid(boolean);
+    method public void setContextClickable(boolean);
+    method public void setDismissable(boolean);
+    method public void setDrawingOrder(int);
+    method public void setEditable(boolean);
+    method public void setEnabled(boolean);
+    method public void setError(CharSequence!);
+    method public void setFocusable(boolean);
+    method public void setFocused(boolean);
+    method public void setHeading(boolean);
+    method public void setHintText(CharSequence?);
+    method public void setImportantForAccessibility(boolean);
+    method public void setInputType(int);
+    method public void setLabelFor(android.view.View!);
+    method public void setLabelFor(android.view.View!, int);
+    method public void setLabeledBy(android.view.View!);
+    method public void setLabeledBy(android.view.View!, int);
+    method public void setLiveRegion(int);
+    method public void setLongClickable(boolean);
+    method public void setMaxTextLength(int);
+    method public void setMovementGranularities(int);
+    method public void setMultiLine(boolean);
+    method public void setPackageName(CharSequence!);
+    method public void setPaneTitle(CharSequence?);
+    method public void setParent(android.view.View!);
+    method public void setParent(android.view.View!, int);
+    method public void setPassword(boolean);
+    method public void setRangeInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat!);
+    method public void setRoleDescription(CharSequence?);
+    method public void setScreenReaderFocusable(boolean);
+    method public void setScrollable(boolean);
+    method public void setSelected(boolean);
+    method public void setShowingHintText(boolean);
+    method public void setSource(android.view.View!);
+    method public void setSource(android.view.View!, int);
+    method public void setStateDescription(CharSequence?);
+    method public void setText(CharSequence!);
+    method public void setTextEntryKey(boolean);
+    method public void setTextSelection(int, int);
+    method public void setTooltipText(CharSequence?);
+    method public void setTouchDelegateInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat);
+    method public void setTraversalAfter(android.view.View!);
+    method public void setTraversalAfter(android.view.View!, int);
+    method public void setTraversalBefore(android.view.View!);
+    method public void setTraversalBefore(android.view.View!, int);
+    method public void setViewIdResourceName(String!);
+    method public void setVisibleToUser(boolean);
+    method public android.view.accessibility.AccessibilityNodeInfo! unwrap();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! wrap(android.view.accessibility.AccessibilityNodeInfo);
+    field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
+    field public static final String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
+    field public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
+    field public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
+    field public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
+    field public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = "ACTION_ARGUMENT_MOVE_WINDOW_X";
+    field public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = "ACTION_ARGUMENT_MOVE_WINDOW_Y";
+    field public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT = "android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT";
+    field public static final String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
+    field public static final String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
+    field public static final String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
+    field public static final String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
+    field public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
+    field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
+    field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
+    field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
+    field public static final int ACTION_CLICK = 16; // 0x10
+    field public static final int ACTION_COLLAPSE = 524288; // 0x80000
+    field public static final int ACTION_COPY = 16384; // 0x4000
+    field public static final int ACTION_CUT = 65536; // 0x10000
+    field public static final int ACTION_DISMISS = 1048576; // 0x100000
+    field public static final int ACTION_EXPAND = 262144; // 0x40000
+    field public static final int ACTION_FOCUS = 1; // 0x1
+    field public static final int ACTION_LONG_CLICK = 32; // 0x20
+    field public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 256; // 0x100
+    field public static final int ACTION_NEXT_HTML_ELEMENT = 1024; // 0x400
+    field public static final int ACTION_PASTE = 32768; // 0x8000
+    field public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 512; // 0x200
+    field public static final int ACTION_PREVIOUS_HTML_ELEMENT = 2048; // 0x800
+    field public static final int ACTION_SCROLL_BACKWARD = 8192; // 0x2000
+    field public static final int ACTION_SCROLL_FORWARD = 4096; // 0x1000
+    field public static final int ACTION_SELECT = 4; // 0x4
+    field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
+    field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
+    field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
+    field public static final int FOCUS_INPUT = 1; // 0x1
+    field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
+    field public static final int MOVEMENT_GRANULARITY_LINE = 4; // 0x4
+    field public static final int MOVEMENT_GRANULARITY_PAGE = 16; // 0x10
+    field public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 8; // 0x8
+    field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
+  }
+
+  public static class AccessibilityNodeInfoCompat.AccessibilityActionCompat {
+    ctor public AccessibilityNodeInfoCompat.AccessibilityActionCompat(int, CharSequence!);
+    method public int getId();
+    method public CharSequence! getLabel();
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_ACCESSIBILITY_FOCUS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_FOCUS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_SELECTION;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLICK;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COLLAPSE;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CONTEXT_CLICK;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COPY;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CUT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_DISMISS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_EXPAND;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_FOCUS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_HIDE_TOOLTIP;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_IME_ENTER;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_LONG_CLICK;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_MOVE_WINDOW;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_HTML_ELEMENT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_DOWN;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_LEFT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_RIGHT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_UP;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PASTE;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PRESS_AND_HOLD;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_HTML_ELEMENT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_BACKWARD;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_DOWN;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_FORWARD;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_LEFT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_RIGHT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_TO_POSITION;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_UP;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SELECT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_PROGRESS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_SELECTION;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_TEXT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_ON_SCREEN;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_TOOLTIP;
+  }
+
+  public static class AccessibilityNodeInfoCompat.CollectionInfoCompat {
+    method public int getColumnCount();
+    method public int getRowCount();
+    method public int getSelectionMode();
+    method public boolean isHierarchical();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean, int);
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean);
+    field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
+    field public static final int SELECTION_MODE_NONE = 0; // 0x0
+    field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
+  }
+
+  public static class AccessibilityNodeInfoCompat.CollectionItemInfoCompat {
+    method public int getColumnIndex();
+    method public int getColumnSpan();
+    method public int getRowIndex();
+    method public int getRowSpan();
+    method @Deprecated public boolean isHeading();
+    method public boolean isSelected();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean, boolean);
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean);
+  }
+
+  public static class AccessibilityNodeInfoCompat.RangeInfoCompat {
+    method public float getCurrent();
+    method public float getMax();
+    method public float getMin();
+    method public int getType();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! obtain(int, float, float, float);
+    field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
+    field public static final int RANGE_TYPE_INT = 0; // 0x0
+    field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
+  }
+
+  public static final class AccessibilityNodeInfoCompat.TouchDelegateInfoCompat {
+    ctor public AccessibilityNodeInfoCompat.TouchDelegateInfoCompat(java.util.Map<android.graphics.Region!,android.view.View!>);
+    method public android.graphics.Region? getRegionAt(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getRegionCount();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getTargetForRegion(android.graphics.Region);
+  }
+
+  public class AccessibilityNodeProviderCompat {
+    ctor public AccessibilityNodeProviderCompat();
+    ctor public AccessibilityNodeProviderCompat(Object!);
+    method public void addExtraDataToAccessibilityNodeInfo(int, androidx.core.view.accessibility.AccessibilityNodeInfoCompat, String, android.os.Bundle?);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? createAccessibilityNodeInfo(int);
+    method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>? findAccessibilityNodeInfosByText(String!, int);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? findFocus(int);
+    method public Object! getProvider();
+    method public boolean performAction(int, int, android.os.Bundle!);
+    field public static final int HOST_VIEW_ID = -1; // 0xffffffff
+  }
+
+  public class AccessibilityRecordCompat {
+    ctor @Deprecated public AccessibilityRecordCompat(Object!);
+    method @Deprecated public boolean equals(Object?);
+    method @Deprecated public int getAddedCount();
+    method @Deprecated public CharSequence! getBeforeText();
+    method @Deprecated public CharSequence! getClassName();
+    method @Deprecated public CharSequence! getContentDescription();
+    method @Deprecated public int getCurrentItemIndex();
+    method @Deprecated public int getFromIndex();
+    method @Deprecated public Object! getImpl();
+    method @Deprecated public int getItemCount();
+    method @Deprecated public int getMaxScrollX();
+    method public static int getMaxScrollX(android.view.accessibility.AccessibilityRecord!);
+    method @Deprecated public int getMaxScrollY();
+    method public static int getMaxScrollY(android.view.accessibility.AccessibilityRecord!);
+    method @Deprecated public android.os.Parcelable! getParcelableData();
+    method @Deprecated public int getRemovedCount();
+    method @Deprecated public int getScrollX();
+    method @Deprecated public int getScrollY();
+    method @Deprecated public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getSource();
+    method @Deprecated public java.util.List<java.lang.CharSequence!>! getText();
+    method @Deprecated public int getToIndex();
+    method @Deprecated public int getWindowId();
+    method @Deprecated public int hashCode();
+    method @Deprecated public boolean isChecked();
+    method @Deprecated public boolean isEnabled();
+    method @Deprecated public boolean isFullScreen();
+    method @Deprecated public boolean isPassword();
+    method @Deprecated public boolean isScrollable();
+    method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain(androidx.core.view.accessibility.AccessibilityRecordCompat!);
+    method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain();
+    method @Deprecated public void recycle();
+    method @Deprecated public void setAddedCount(int);
+    method @Deprecated public void setBeforeText(CharSequence!);
+    method @Deprecated public void setChecked(boolean);
+    method @Deprecated public void setClassName(CharSequence!);
+    method @Deprecated public void setContentDescription(CharSequence!);
+    method @Deprecated public void setCurrentItemIndex(int);
+    method @Deprecated public void setEnabled(boolean);
+    method @Deprecated public void setFromIndex(int);
+    method @Deprecated public void setFullScreen(boolean);
+    method @Deprecated public void setItemCount(int);
+    method @Deprecated public void setMaxScrollX(int);
+    method public static void setMaxScrollX(android.view.accessibility.AccessibilityRecord!, int);
+    method @Deprecated public void setMaxScrollY(int);
+    method public static void setMaxScrollY(android.view.accessibility.AccessibilityRecord!, int);
+    method @Deprecated public void setParcelableData(android.os.Parcelable!);
+    method @Deprecated public void setPassword(boolean);
+    method @Deprecated public void setRemovedCount(int);
+    method @Deprecated public void setScrollX(int);
+    method @Deprecated public void setScrollY(int);
+    method @Deprecated public void setScrollable(boolean);
+    method @Deprecated public void setSource(android.view.View!);
+    method @Deprecated public void setSource(android.view.View!, int);
+    method public static void setSource(android.view.accessibility.AccessibilityRecord, android.view.View!, int);
+    method @Deprecated public void setToIndex(int);
+  }
+
+  public interface AccessibilityViewCommand {
+    method public boolean perform(android.view.View, androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments?);
+  }
+
+  public abstract static class AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.CommandArguments();
+  }
+
+  public static final class AccessibilityViewCommand.MoveAtGranularityArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.MoveAtGranularityArguments();
+    method public boolean getExtendSelection();
+    method public int getGranularity();
+  }
+
+  public static final class AccessibilityViewCommand.MoveHtmlArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.MoveHtmlArguments();
+    method public String! getHTMLElement();
+  }
+
+  public static final class AccessibilityViewCommand.MoveWindowArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.MoveWindowArguments();
+    method public int getX();
+    method public int getY();
+  }
+
+  public static final class AccessibilityViewCommand.ScrollToPositionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.ScrollToPositionArguments();
+    method public int getColumn();
+    method public int getRow();
+  }
+
+  public static final class AccessibilityViewCommand.SetProgressArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.SetProgressArguments();
+    method public float getProgress();
+  }
+
+  public static final class AccessibilityViewCommand.SetSelectionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.SetSelectionArguments();
+    method public int getEnd();
+    method public int getStart();
+  }
+
+  public static final class AccessibilityViewCommand.SetTextArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.SetTextArguments();
+    method public CharSequence! getText();
+  }
+
+  public class AccessibilityWindowInfoCompat {
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getAnchor();
+    method public void getBoundsInScreen(android.graphics.Rect!);
+    method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat! getChild(int);
+    method public int getChildCount();
+    method public int getId();
+    method public int getLayer();
+    method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat! getParent();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getRoot();
+    method public CharSequence! getTitle();
+    method public int getType();
+    method public boolean isAccessibilityFocused();
+    method public boolean isActive();
+    method public boolean isFocused();
+    method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat! obtain();
+    method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat! obtain(androidx.core.view.accessibility.AccessibilityWindowInfoCompat!);
+    method public void recycle();
+    field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
+    field public static final int TYPE_APPLICATION = 1; // 0x1
+    field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+    field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
+    field public static final int TYPE_SYSTEM = 3; // 0x3
+  }
+
+}
+
+package androidx.core.view.animation {
+
+  public final class PathInterpolatorCompat {
+    method public static android.view.animation.Interpolator! create(android.graphics.Path!);
+    method public static android.view.animation.Interpolator! create(float, float);
+    method public static android.view.animation.Interpolator! create(float, float, float, float);
+  }
+
+}
+
+package androidx.core.view.inputmethod {
+
+  public final class EditorInfoCompat {
+    ctor @Deprecated public EditorInfoCompat();
+    method public static String![] getContentMimeTypes(android.view.inputmethod.EditorInfo!);
+    method public static CharSequence? getInitialSelectedText(android.view.inputmethod.EditorInfo, int);
+    method public static CharSequence? getInitialTextAfterCursor(android.view.inputmethod.EditorInfo, int, int);
+    method public static CharSequence? getInitialTextBeforeCursor(android.view.inputmethod.EditorInfo, int, int);
+    method public static void setContentMimeTypes(android.view.inputmethod.EditorInfo, String![]?);
+    method public static void setInitialSurroundingSubText(android.view.inputmethod.EditorInfo, CharSequence, int);
+    method public static void setInitialSurroundingText(android.view.inputmethod.EditorInfo, CharSequence);
+    field public static final int IME_FLAG_FORCE_ASCII = -2147483648; // 0x80000000
+    field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
+  }
+
+  public final class InputConnectionCompat {
+    ctor @Deprecated public InputConnectionCompat();
+    method public static boolean commitContent(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
+    method public static android.view.inputmethod.InputConnection createWrapper(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputConnectionCompat.OnCommitContentListener);
+    field public static final int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 1; // 0x1
+  }
+
+  public static interface InputConnectionCompat.OnCommitContentListener {
+    method public boolean onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat!, int, android.os.Bundle!);
+  }
+
+  public final class InputContentInfoCompat {
+    ctor public InputContentInfoCompat(android.net.Uri, android.content.ClipDescription, android.net.Uri?);
+    method public android.net.Uri getContentUri();
+    method public android.content.ClipDescription getDescription();
+    method public android.net.Uri? getLinkUri();
+    method public void releasePermission();
+    method public void requestPermission();
+    method public Object? unwrap();
+    method public static androidx.core.view.inputmethod.InputContentInfoCompat? wrap(Object?);
+  }
+
+}
+
+package androidx.core.widget {
+
+  public abstract class AutoScrollHelper implements android.view.View.OnTouchListener {
+    ctor public AutoScrollHelper(android.view.View);
+    method public abstract boolean canTargetScrollHorizontally(int);
+    method public abstract boolean canTargetScrollVertically(int);
+    method public boolean isEnabled();
+    method public boolean isExclusive();
+    method public boolean onTouch(android.view.View!, android.view.MotionEvent!);
+    method public abstract void scrollTargetBy(int, int);
+    method public androidx.core.widget.AutoScrollHelper setActivationDelay(int);
+    method public androidx.core.widget.AutoScrollHelper setEdgeType(int);
+    method public androidx.core.widget.AutoScrollHelper! setEnabled(boolean);
+    method public androidx.core.widget.AutoScrollHelper! setExclusive(boolean);
+    method public androidx.core.widget.AutoScrollHelper setMaximumEdges(float, float);
+    method public androidx.core.widget.AutoScrollHelper setMaximumVelocity(float, float);
+    method public androidx.core.widget.AutoScrollHelper setMinimumVelocity(float, float);
+    method public androidx.core.widget.AutoScrollHelper setRampDownDuration(int);
+    method public androidx.core.widget.AutoScrollHelper setRampUpDuration(int);
+    method public androidx.core.widget.AutoScrollHelper setRelativeEdges(float, float);
+    method public androidx.core.widget.AutoScrollHelper setRelativeVelocity(float, float);
+    field public static final int EDGE_TYPE_INSIDE = 0; // 0x0
+    field public static final int EDGE_TYPE_INSIDE_EXTEND = 1; // 0x1
+    field public static final int EDGE_TYPE_OUTSIDE = 2; // 0x2
+    field public static final float NO_MAX = 3.4028235E38f;
+    field public static final float NO_MIN = 0.0f;
+    field public static final float RELATIVE_UNSPECIFIED = 0.0f;
+  }
+
+  public final class CompoundButtonCompat {
+    method public static android.graphics.drawable.Drawable? getButtonDrawable(android.widget.CompoundButton);
+    method public static android.content.res.ColorStateList? getButtonTintList(android.widget.CompoundButton);
+    method public static android.graphics.PorterDuff.Mode? getButtonTintMode(android.widget.CompoundButton);
+    method public static void setButtonTintList(android.widget.CompoundButton, android.content.res.ColorStateList?);
+    method public static void setButtonTintMode(android.widget.CompoundButton, android.graphics.PorterDuff.Mode?);
+  }
+
+  public class ContentLoadingProgressBar extends android.widget.ProgressBar {
+    ctor public ContentLoadingProgressBar(android.content.Context);
+    ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet?);
+    method public void hide();
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public void show();
+  }
+
+  public final class EdgeEffectCompat {
+    ctor @Deprecated public EdgeEffectCompat(android.content.Context!);
+    method @Deprecated public boolean draw(android.graphics.Canvas!);
+    method @Deprecated public void finish();
+    method @Deprecated public boolean isFinished();
+    method @Deprecated public boolean onAbsorb(int);
+    method @Deprecated public boolean onPull(float);
+    method @Deprecated public boolean onPull(float, float);
+    method public static void onPull(android.widget.EdgeEffect, float, float);
+    method @Deprecated public boolean onRelease();
+    method @Deprecated public void setSize(int, int);
+  }
+
+  public class ImageViewCompat {
+    method public static android.content.res.ColorStateList? getImageTintList(android.widget.ImageView);
+    method public static android.graphics.PorterDuff.Mode? getImageTintMode(android.widget.ImageView);
+    method public static void setImageTintList(android.widget.ImageView, android.content.res.ColorStateList?);
+    method public static void setImageTintMode(android.widget.ImageView, android.graphics.PorterDuff.Mode?);
+  }
+
+  public final class ListPopupWindowCompat {
+    method @Deprecated public static android.view.View.OnTouchListener! createDragToOpenListener(Object!, android.view.View!);
+    method public static android.view.View.OnTouchListener? createDragToOpenListener(android.widget.ListPopupWindow, android.view.View);
+  }
+
+  public class ListViewAutoScrollHelper extends androidx.core.widget.AutoScrollHelper {
+    ctor public ListViewAutoScrollHelper(android.widget.ListView);
+    method public boolean canTargetScrollHorizontally(int);
+    method public boolean canTargetScrollVertically(int);
+    method public void scrollTargetBy(int, int);
+  }
+
+  public final class ListViewCompat {
+    method public static boolean canScrollList(android.widget.ListView, int);
+    method public static void scrollListBy(android.widget.ListView, int);
+  }
+
+  public class NestedScrollView extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingChild3 androidx.core.view.NestedScrollingParent3 androidx.core.view.ScrollingView {
+    ctor public NestedScrollView(android.content.Context);
+    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?);
+    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?, int);
+    method public boolean arrowScroll(int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollExtent();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollOffset();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollRange();
+    method protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollExtent();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollOffset();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollRange();
+    method public boolean dispatchNestedPreScroll(int, int, int[]!, int[]!, int);
+    method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]!, int);
+    method public boolean executeKeyEvent(android.view.KeyEvent);
+    method public void fling(int);
+    method public boolean fullScroll(int);
+    method public int getMaxScrollAmount();
+    method public boolean hasNestedScrollingParent(int);
+    method public boolean isFillViewport();
+    method public boolean isSmoothScrollingEnabled();
+    method public void onAttachedToWindow();
+    method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+    method public void onNestedScroll(android.view.View, int, int, int, int, int, int[]);
+    method public void onNestedScroll(android.view.View, int, int, int, int, int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+    method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+    method public void onStopNestedScroll(android.view.View, int);
+    method public boolean pageScroll(int);
+    method public void setFillViewport(boolean);
+    method public void setOnScrollChangeListener(androidx.core.widget.NestedScrollView.OnScrollChangeListener?);
+    method public void setSmoothScrollingEnabled(boolean);
+    method public final void smoothScrollBy(int, int);
+    method public final void smoothScrollBy(int, int, int);
+    method public final void smoothScrollTo(int, int);
+    method public final void smoothScrollTo(int, int, int);
+    method public boolean startNestedScroll(int, int);
+    method public void stopNestedScroll(int);
+  }
+
+  public static interface NestedScrollView.OnScrollChangeListener {
+    method public void onScrollChange(androidx.core.widget.NestedScrollView!, int, int, int, int);
+  }
+
+  public final class PopupMenuCompat {
+    method public static android.view.View.OnTouchListener? getDragToOpenListener(Object);
+  }
+
+  public final class PopupWindowCompat {
+    method public static boolean getOverlapAnchor(android.widget.PopupWindow);
+    method public static int getWindowLayoutType(android.widget.PopupWindow);
+    method public static void setOverlapAnchor(android.widget.PopupWindow, boolean);
+    method public static void setWindowLayoutType(android.widget.PopupWindow, int);
+    method public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
+  }
+
+  @Deprecated public final class ScrollerCompat {
+    method @Deprecated public void abortAnimation();
+    method @Deprecated public boolean computeScrollOffset();
+    method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!);
+    method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!, android.view.animation.Interpolator!);
+    method @Deprecated public void fling(int, int, int, int, int, int, int, int);
+    method @Deprecated public void fling(int, int, int, int, int, int, int, int, int, int);
+    method @Deprecated public float getCurrVelocity();
+    method @Deprecated public int getCurrX();
+    method @Deprecated public int getCurrY();
+    method @Deprecated public int getFinalX();
+    method @Deprecated public int getFinalY();
+    method @Deprecated public boolean isFinished();
+    method @Deprecated public boolean isOverScrolled();
+    method @Deprecated public void notifyHorizontalEdgeReached(int, int, int);
+    method @Deprecated public void notifyVerticalEdgeReached(int, int, int);
+    method @Deprecated public boolean springBack(int, int, int, int, int, int);
+    method @Deprecated public void startScroll(int, int, int, int);
+    method @Deprecated public void startScroll(int, int, int, int, int);
+  }
+
+  public final class TextViewCompat {
+    method public static int getAutoSizeMaxTextSize(android.widget.TextView);
+    method public static int getAutoSizeMinTextSize(android.widget.TextView);
+    method public static int getAutoSizeStepGranularity(android.widget.TextView);
+    method public static int[] getAutoSizeTextAvailableSizes(android.widget.TextView);
+    method public static int getAutoSizeTextType(android.widget.TextView);
+    method public static android.content.res.ColorStateList? getCompoundDrawableTintList(android.widget.TextView);
+    method public static android.graphics.PorterDuff.Mode? getCompoundDrawableTintMode(android.widget.TextView);
+    method public static android.graphics.drawable.Drawable![] getCompoundDrawablesRelative(android.widget.TextView);
+    method public static int getFirstBaselineToTopHeight(android.widget.TextView);
+    method public static int getLastBaselineToBottomHeight(android.widget.TextView);
+    method public static int getMaxLines(android.widget.TextView);
+    method public static int getMinLines(android.widget.TextView);
+    method public static androidx.core.text.PrecomputedTextCompat.Params getTextMetricsParams(android.widget.TextView);
+    method public static void setAutoSizeTextTypeUniformWithConfiguration(android.widget.TextView, int, int, int, int) throws java.lang.IllegalArgumentException;
+    method public static void setAutoSizeTextTypeUniformWithPresetSizes(android.widget.TextView, int[], int) throws java.lang.IllegalArgumentException;
+    method public static void setAutoSizeTextTypeWithDefaults(android.widget.TextView, int);
+    method public static void setCompoundDrawableTintList(android.widget.TextView, android.content.res.ColorStateList?);
+    method public static void setCompoundDrawableTintMode(android.widget.TextView, android.graphics.PorterDuff.Mode?);
+    method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, @DrawableRes int, @DrawableRes int, @DrawableRes int, @DrawableRes int);
+    method public static void setCustomSelectionActionModeCallback(android.widget.TextView, android.view.ActionMode.Callback);
+    method public static void setFirstBaselineToTopHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+    method public static void setLastBaselineToBottomHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+    method public static void setLineHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+    method public static void setPrecomputedText(android.widget.TextView, androidx.core.text.PrecomputedTextCompat);
+    method public static void setTextAppearance(android.widget.TextView, @StyleRes int);
+    method public static void setTextMetricsParams(android.widget.TextView, androidx.core.text.PrecomputedTextCompat.Params);
+    field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
+    field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1
+  }
+
+  public interface TintableCompoundButton {
+    method public android.content.res.ColorStateList? getSupportButtonTintList();
+    method public android.graphics.PorterDuff.Mode? getSupportButtonTintMode();
+    method public void setSupportButtonTintList(android.content.res.ColorStateList?);
+    method public void setSupportButtonTintMode(android.graphics.PorterDuff.Mode?);
+  }
+
+  public interface TintableCompoundDrawablesView {
+    method public android.content.res.ColorStateList? getSupportCompoundDrawablesTintList();
+    method public android.graphics.PorterDuff.Mode? getSupportCompoundDrawablesTintMode();
+    method public void setSupportCompoundDrawablesTintList(android.content.res.ColorStateList?);
+    method public void setSupportCompoundDrawablesTintMode(android.graphics.PorterDuff.Mode?);
+  }
+
+}
+
diff --git a/core/core/api/current.ignore b/core/core/api/current.ignore
new file mode 100644
index 0000000..15be615
--- /dev/null
+++ b/core/core/api/current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+RemovedClass: androidx.core.os.HandlerExecutor:
+    Removed class androidx.core.os.HandlerExecutor
diff --git a/core/core/api/current.txt b/core/core/api/current.txt
index c7d59de9..b7ab56a 100644
--- a/core/core/api/current.txt
+++ b/core/core/api/current.txt
@@ -1552,17 +1552,16 @@
     field public static final String MEDIA_UNKNOWN = "unknown";
   }
 
+  public final class ExecutorCompat {
+    method public static java.util.concurrent.Executor create(android.os.Handler);
+  }
+
   public final class HandlerCompat {
     method public static android.os.Handler createAsync(android.os.Looper);
     method public static android.os.Handler createAsync(android.os.Looper, android.os.Handler.Callback);
     method public static boolean postDelayed(android.os.Handler, Runnable, Object?, long);
   }
 
-  public class HandlerExecutor implements java.util.concurrent.Executor {
-    ctor public HandlerExecutor(android.os.Handler);
-    method public void execute(Runnable);
-  }
-
   public final class LocaleListCompat {
     method public static androidx.core.os.LocaleListCompat create(java.util.Locale!...);
     method public static androidx.core.os.LocaleListCompat forLanguageTags(String?);
diff --git a/core/core/api/public_plus_experimental_1.5.0-beta03.txt b/core/core/api/public_plus_experimental_1.5.0-beta03.txt
new file mode 100644
index 0000000..28165c4
--- /dev/null
+++ b/core/core/api/public_plus_experimental_1.5.0-beta03.txt
@@ -0,0 +1,3502 @@
+// Signature format: 4.0
+package androidx.core.accessibilityservice {
+
+  public final class AccessibilityServiceInfoCompat {
+    method public static String capabilityToString(int);
+    method public static String feedbackTypeToString(int);
+    method public static String? flagToString(int);
+    method public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static String? loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager);
+    field public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 8; // 0x8
+    field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+    field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
+    field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
+    field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
+    field public static final int FEEDBACK_BRAILLE = 32; // 0x20
+    field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
+    field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+    field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+    field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
+    field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
+  }
+
+}
+
+package androidx.core.app {
+
+  public class ActivityCompat extends androidx.core.content.ContextCompat {
+    ctor protected ActivityCompat();
+    method public static void finishAffinity(android.app.Activity);
+    method public static void finishAfterTransition(android.app.Activity);
+    method public static android.net.Uri? getReferrer(android.app.Activity);
+    method @Deprecated public static boolean invalidateOptionsMenu(android.app.Activity!);
+    method public static void postponeEnterTransition(android.app.Activity);
+    method public static void recreate(android.app.Activity);
+    method public static androidx.core.view.DragAndDropPermissionsCompat? requestDragAndDropPermissions(android.app.Activity!, android.view.DragEvent!);
+    method public static void requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+    method public static <T extends android.view.View> T requireViewById(android.app.Activity, @IdRes int);
+    method public static void setEnterSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+    method public static void setExitSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+    method public static void setLocusContext(android.app.Activity, androidx.core.content.LocusIdCompat?, android.os.Bundle?);
+    method public static void setPermissionCompatDelegate(androidx.core.app.ActivityCompat.PermissionCompatDelegate?);
+    method public static boolean shouldShowRequestPermissionRationale(android.app.Activity, String);
+    method public static void startActivityForResult(android.app.Activity, android.content.Intent, int, android.os.Bundle?);
+    method public static void startIntentSenderForResult(android.app.Activity, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public static void startPostponedEnterTransition(android.app.Activity);
+  }
+
+  public static interface ActivityCompat.OnRequestPermissionsResultCallback {
+    method public void onRequestPermissionsResult(int, String![], int[]);
+  }
+
+  public static interface ActivityCompat.PermissionCompatDelegate {
+    method public boolean onActivityResult(android.app.Activity, @IntRange(from=0) int, int, android.content.Intent?);
+    method public boolean requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+  }
+
+  public final class ActivityManagerCompat {
+    method public static boolean isLowRamDevice(android.app.ActivityManager);
+  }
+
+  public class ActivityOptionsCompat {
+    ctor protected ActivityOptionsCompat();
+    method public android.graphics.Rect? getLaunchBounds();
+    method public static androidx.core.app.ActivityOptionsCompat makeBasic();
+    method public static androidx.core.app.ActivityOptionsCompat makeClipRevealAnimation(android.view.View, int, int, int, int);
+    method public static androidx.core.app.ActivityOptionsCompat makeCustomAnimation(android.content.Context, int, int);
+    method public static androidx.core.app.ActivityOptionsCompat makeScaleUpAnimation(android.view.View, int, int, int, int);
+    method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.view.View, String);
+    method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, androidx.core.util.Pair<android.view.View!,java.lang.String!>!...);
+    method public static androidx.core.app.ActivityOptionsCompat makeTaskLaunchBehind();
+    method public static androidx.core.app.ActivityOptionsCompat makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
+    method public void requestUsageTimeReport(android.app.PendingIntent);
+    method public androidx.core.app.ActivityOptionsCompat setLaunchBounds(android.graphics.Rect?);
+    method public android.os.Bundle? toBundle();
+    method public void update(androidx.core.app.ActivityOptionsCompat);
+    field public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
+    field public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
+  }
+
+  public final class AlarmManagerCompat {
+    method public static void setAlarmClock(android.app.AlarmManager, long, android.app.PendingIntent, android.app.PendingIntent);
+    method public static void setAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+    method public static void setExact(android.app.AlarmManager, int, long, android.app.PendingIntent);
+    method public static void setExactAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+  }
+
+  @RequiresApi(28) public class AppComponentFactory extends android.app.AppComponentFactory {
+    ctor public AppComponentFactory();
+    method public final android.app.Activity instantiateActivity(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.app.Activity instantiateActivityCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public final android.app.Application instantiateApplication(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.app.Application instantiateApplicationCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public final android.content.ContentProvider instantiateProvider(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.content.ContentProvider instantiateProviderCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public final android.content.BroadcastReceiver instantiateReceiver(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.content.BroadcastReceiver instantiateReceiverCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public final android.app.Service instantiateService(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.app.Service instantiateServiceCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+  }
+
+  public class AppLaunchChecker {
+    ctor @Deprecated public AppLaunchChecker();
+    method public static boolean hasStartedFromLauncher(android.content.Context);
+    method public static void onActivityCreate(android.app.Activity);
+  }
+
+  public final class AppOpsManagerCompat {
+    method public static int noteOp(android.content.Context, String, int, String);
+    method public static int noteOpNoThrow(android.content.Context, String, int, String);
+    method public static int noteProxyOp(android.content.Context, String, String);
+    method public static int noteProxyOpNoThrow(android.content.Context, String, String);
+    method public static String? permissionToOp(String);
+    field public static final int MODE_ALLOWED = 0; // 0x0
+    field public static final int MODE_DEFAULT = 3; // 0x3
+    field public static final int MODE_ERRORED = 2; // 0x2
+    field public static final int MODE_IGNORED = 1; // 0x1
+  }
+
+  public final class BundleCompat {
+    method public static android.os.IBinder? getBinder(android.os.Bundle, String?);
+    method public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
+  }
+
+  public class DialogCompat {
+    method public static android.view.View requireViewById(android.app.Dialog, int);
+  }
+
+  public class FrameMetricsAggregator {
+    ctor public FrameMetricsAggregator();
+    ctor public FrameMetricsAggregator(int);
+    method public void add(android.app.Activity);
+    method public android.util.SparseIntArray![]? getMetrics();
+    method public android.util.SparseIntArray![]? remove(android.app.Activity);
+    method public android.util.SparseIntArray![]? reset();
+    method public android.util.SparseIntArray![]? stop();
+    field public static final int ANIMATION_DURATION = 256; // 0x100
+    field public static final int ANIMATION_INDEX = 8; // 0x8
+    field public static final int COMMAND_DURATION = 32; // 0x20
+    field public static final int COMMAND_INDEX = 5; // 0x5
+    field public static final int DELAY_DURATION = 128; // 0x80
+    field public static final int DELAY_INDEX = 7; // 0x7
+    field public static final int DRAW_DURATION = 8; // 0x8
+    field public static final int DRAW_INDEX = 3; // 0x3
+    field public static final int EVERY_DURATION = 511; // 0x1ff
+    field public static final int INPUT_DURATION = 2; // 0x2
+    field public static final int INPUT_INDEX = 1; // 0x1
+    field public static final int LAYOUT_MEASURE_DURATION = 4; // 0x4
+    field public static final int LAYOUT_MEASURE_INDEX = 2; // 0x2
+    field public static final int SWAP_DURATION = 64; // 0x40
+    field public static final int SWAP_INDEX = 6; // 0x6
+    field public static final int SYNC_DURATION = 16; // 0x10
+    field public static final int SYNC_INDEX = 4; // 0x4
+    field public static final int TOTAL_DURATION = 1; // 0x1
+    field public static final int TOTAL_INDEX = 0; // 0x0
+  }
+
+  public abstract class JobIntentService extends android.app.Service {
+    ctor public JobIntentService();
+    method public static void enqueueWork(android.content.Context, Class<?>, int, android.content.Intent);
+    method public static void enqueueWork(android.content.Context, android.content.ComponentName, int, android.content.Intent);
+    method public boolean isStopped();
+    method public android.os.IBinder! onBind(android.content.Intent);
+    method protected abstract void onHandleWork(android.content.Intent);
+    method public boolean onStopCurrentWork();
+    method public void setInterruptIfStopped(boolean);
+  }
+
+  public final class NavUtils {
+    method public static android.content.Intent? getParentActivityIntent(android.app.Activity);
+    method public static android.content.Intent? getParentActivityIntent(android.content.Context, Class<?>) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static android.content.Intent? getParentActivityIntent(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static String? getParentActivityName(android.app.Activity);
+    method public static String? getParentActivityName(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static void navigateUpFromSameTask(android.app.Activity);
+    method public static void navigateUpTo(android.app.Activity, android.content.Intent);
+    method public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
+    field public static final String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
+  }
+
+  public class NotificationChannelCompat {
+    method public boolean canBubble();
+    method public boolean canBypassDnd();
+    method public boolean canShowBadge();
+    method public android.media.AudioAttributes? getAudioAttributes();
+    method public String? getConversationId();
+    method public String? getDescription();
+    method public String? getGroup();
+    method public String getId();
+    method public int getImportance();
+    method public int getLightColor();
+    method public int getLockscreenVisibility();
+    method public CharSequence? getName();
+    method public String? getParentChannelId();
+    method public android.net.Uri? getSound();
+    method public long[]? getVibrationPattern();
+    method public boolean isImportantConversation();
+    method public boolean shouldShowLights();
+    method public boolean shouldVibrate();
+    method public androidx.core.app.NotificationChannelCompat.Builder toBuilder();
+    field public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
+  }
+
+  public static class NotificationChannelCompat.Builder {
+    ctor public NotificationChannelCompat.Builder(String, int);
+    method public androidx.core.app.NotificationChannelCompat build();
+    method public androidx.core.app.NotificationChannelCompat.Builder setConversationId(String, String);
+    method public androidx.core.app.NotificationChannelCompat.Builder setDescription(String?);
+    method public androidx.core.app.NotificationChannelCompat.Builder setGroup(String?);
+    method public androidx.core.app.NotificationChannelCompat.Builder setImportance(int);
+    method public androidx.core.app.NotificationChannelCompat.Builder setLightColor(int);
+    method public androidx.core.app.NotificationChannelCompat.Builder setLightsEnabled(boolean);
+    method public androidx.core.app.NotificationChannelCompat.Builder setName(CharSequence?);
+    method public androidx.core.app.NotificationChannelCompat.Builder setShowBadge(boolean);
+    method public androidx.core.app.NotificationChannelCompat.Builder setSound(android.net.Uri?, android.media.AudioAttributes?);
+    method public androidx.core.app.NotificationChannelCompat.Builder setVibrationEnabled(boolean);
+    method public androidx.core.app.NotificationChannelCompat.Builder setVibrationPattern(long[]?);
+  }
+
+  public class NotificationChannelGroupCompat {
+    method public java.util.List<androidx.core.app.NotificationChannelCompat!> getChannels();
+    method public String? getDescription();
+    method public String getId();
+    method public CharSequence? getName();
+    method public boolean isBlocked();
+    method public androidx.core.app.NotificationChannelGroupCompat.Builder toBuilder();
+  }
+
+  public static class NotificationChannelGroupCompat.Builder {
+    ctor public NotificationChannelGroupCompat.Builder(String);
+    method public androidx.core.app.NotificationChannelGroupCompat build();
+    method public androidx.core.app.NotificationChannelGroupCompat.Builder setDescription(String?);
+    method public androidx.core.app.NotificationChannelGroupCompat.Builder setName(CharSequence?);
+  }
+
+  public class NotificationCompat {
+    ctor @Deprecated public NotificationCompat();
+    method public static androidx.core.app.NotificationCompat.Action? getAction(android.app.Notification, int);
+    method public static int getActionCount(android.app.Notification);
+    method public static boolean getAllowSystemGeneratedContextualActions(android.app.Notification);
+    method public static boolean getAutoCancel(android.app.Notification);
+    method public static int getBadgeIconType(android.app.Notification);
+    method public static androidx.core.app.NotificationCompat.BubbleMetadata? getBubbleMetadata(android.app.Notification);
+    method public static String? getCategory(android.app.Notification);
+    method public static String? getChannelId(android.app.Notification);
+    method public static int getColor(android.app.Notification);
+    method @RequiresApi(19) public static CharSequence? getContentInfo(android.app.Notification);
+    method @RequiresApi(19) public static CharSequence? getContentText(android.app.Notification);
+    method @RequiresApi(19) public static CharSequence? getContentTitle(android.app.Notification);
+    method public static android.os.Bundle? getExtras(android.app.Notification);
+    method public static String? getGroup(android.app.Notification);
+    method public static int getGroupAlertBehavior(android.app.Notification);
+    method @RequiresApi(21) public static java.util.List<androidx.core.app.NotificationCompat.Action!> getInvisibleActions(android.app.Notification);
+    method public static boolean getLocalOnly(android.app.Notification);
+    method public static androidx.core.content.LocusIdCompat? getLocusId(android.app.Notification);
+    method public static boolean getOngoing(android.app.Notification);
+    method public static boolean getOnlyAlertOnce(android.app.Notification);
+    method public static java.util.List<androidx.core.app.Person!> getPeople(android.app.Notification);
+    method public static android.app.Notification? getPublicVersion(android.app.Notification);
+    method public static CharSequence? getSettingsText(android.app.Notification);
+    method public static String? getShortcutId(android.app.Notification);
+    method @RequiresApi(19) public static boolean getShowWhen(android.app.Notification);
+    method public static String? getSortKey(android.app.Notification);
+    method @RequiresApi(19) public static CharSequence? getSubText(android.app.Notification);
+    method public static long getTimeoutAfter(android.app.Notification);
+    method @RequiresApi(19) public static boolean getUsesChronometer(android.app.Notification);
+    method public static int getVisibility(android.app.Notification);
+    method public static boolean isGroupSummary(android.app.Notification);
+    field public static final int BADGE_ICON_LARGE = 2; // 0x2
+    field public static final int BADGE_ICON_NONE = 0; // 0x0
+    field public static final int BADGE_ICON_SMALL = 1; // 0x1
+    field public static final String CATEGORY_ALARM = "alarm";
+    field public static final String CATEGORY_CALL = "call";
+    field public static final String CATEGORY_EMAIL = "email";
+    field public static final String CATEGORY_ERROR = "err";
+    field public static final String CATEGORY_EVENT = "event";
+    field public static final String CATEGORY_LOCATION_SHARING = "location_sharing";
+    field public static final String CATEGORY_MESSAGE = "msg";
+    field public static final String CATEGORY_MISSED_CALL = "missed_call";
+    field public static final String CATEGORY_NAVIGATION = "navigation";
+    field public static final String CATEGORY_PROGRESS = "progress";
+    field public static final String CATEGORY_PROMO = "promo";
+    field public static final String CATEGORY_RECOMMENDATION = "recommendation";
+    field public static final String CATEGORY_REMINDER = "reminder";
+    field public static final String CATEGORY_SERVICE = "service";
+    field public static final String CATEGORY_SOCIAL = "social";
+    field public static final String CATEGORY_STATUS = "status";
+    field public static final String CATEGORY_STOPWATCH = "stopwatch";
+    field public static final String CATEGORY_SYSTEM = "sys";
+    field public static final String CATEGORY_TRANSPORT = "transport";
+    field public static final String CATEGORY_WORKOUT = "workout";
+    field @ColorInt public static final int COLOR_DEFAULT = 0; // 0x0
+    field public static final int DEFAULT_ALL = -1; // 0xffffffff
+    field public static final int DEFAULT_LIGHTS = 4; // 0x4
+    field public static final int DEFAULT_SOUND = 1; // 0x1
+    field public static final int DEFAULT_VIBRATE = 2; // 0x2
+    field public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
+    field public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
+    field public static final String EXTRA_BIG_TEXT = "android.bigText";
+    field public static final String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
+    field public static final String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID";
+    field public static final String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
+    field public static final String EXTRA_COLORIZED = "android.colorized";
+    field public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+    field public static final String EXTRA_COMPAT_TEMPLATE = "androidx.core.app.extra.COMPAT_TEMPLATE";
+    field public static final String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+    field public static final String EXTRA_HIDDEN_CONVERSATION_TITLE = "android.hiddenConversationTitle";
+    field public static final String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
+    field public static final String EXTRA_INFO_TEXT = "android.infoText";
+    field public static final String EXTRA_IS_GROUP_CONVERSATION = "android.isGroupConversation";
+    field public static final String EXTRA_LARGE_ICON = "android.largeIcon";
+    field public static final String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
+    field public static final String EXTRA_MEDIA_SESSION = "android.mediaSession";
+    field public static final String EXTRA_MESSAGES = "android.messages";
+    field public static final String EXTRA_MESSAGING_STYLE_USER = "android.messagingStyleUser";
+    field public static final String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID";
+    field public static final String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG";
+    field @Deprecated public static final String EXTRA_PEOPLE = "android.people";
+    field public static final String EXTRA_PEOPLE_LIST = "android.people.list";
+    field public static final String EXTRA_PICTURE = "android.picture";
+    field public static final String EXTRA_PROGRESS = "android.progress";
+    field public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+    field public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
+    field public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
+    field public static final String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
+    field public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+    field public static final String EXTRA_SHOW_WHEN = "android.showWhen";
+    field public static final String EXTRA_SMALL_ICON = "android.icon";
+    field public static final String EXTRA_SUB_TEXT = "android.subText";
+    field public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
+    field public static final String EXTRA_TEMPLATE = "android.template";
+    field public static final String EXTRA_TEXT = "android.text";
+    field public static final String EXTRA_TEXT_LINES = "android.textLines";
+    field public static final String EXTRA_TITLE = "android.title";
+    field public static final String EXTRA_TITLE_BIG = "android.title.big";
+    field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
+    field public static final int FLAG_BUBBLE = 4096; // 0x1000
+    field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
+    field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
+    field @Deprecated public static final int FLAG_HIGH_PRIORITY = 128; // 0x80
+    field public static final int FLAG_INSISTENT = 4; // 0x4
+    field public static final int FLAG_LOCAL_ONLY = 256; // 0x100
+    field public static final int FLAG_NO_CLEAR = 32; // 0x20
+    field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
+    field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
+    field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+    field public static final int GROUP_ALERT_ALL = 0; // 0x0
+    field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
+    field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
+    field public static final String GROUP_KEY_SILENT = "silent";
+    field public static final String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
+    field public static final int PRIORITY_DEFAULT = 0; // 0x0
+    field public static final int PRIORITY_HIGH = 1; // 0x1
+    field public static final int PRIORITY_LOW = -1; // 0xffffffff
+    field public static final int PRIORITY_MAX = 2; // 0x2
+    field public static final int PRIORITY_MIN = -2; // 0xfffffffe
+    field public static final int STREAM_DEFAULT = -1; // 0xffffffff
+    field public static final int VISIBILITY_PRIVATE = 0; // 0x0
+    field public static final int VISIBILITY_PUBLIC = 1; // 0x1
+    field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
+  }
+
+  public static class NotificationCompat.Action {
+    ctor public NotificationCompat.Action(int, CharSequence?, android.app.PendingIntent?);
+    ctor public NotificationCompat.Action(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+    method public android.app.PendingIntent? getActionIntent();
+    method public boolean getAllowGeneratedReplies();
+    method public androidx.core.app.RemoteInput![]? getDataOnlyRemoteInputs();
+    method public android.os.Bundle getExtras();
+    method @Deprecated public int getIcon();
+    method public androidx.core.graphics.drawable.IconCompat? getIconCompat();
+    method public androidx.core.app.RemoteInput![]? getRemoteInputs();
+    method @androidx.core.app.NotificationCompat.Action.SemanticAction public int getSemanticAction();
+    method public boolean getShowsUserInterface();
+    method public CharSequence? getTitle();
+    method public boolean isContextual();
+    field public static final int SEMANTIC_ACTION_ARCHIVE = 5; // 0x5
+    field public static final int SEMANTIC_ACTION_CALL = 10; // 0xa
+    field public static final int SEMANTIC_ACTION_DELETE = 4; // 0x4
+    field public static final int SEMANTIC_ACTION_MARK_AS_READ = 2; // 0x2
+    field public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3; // 0x3
+    field public static final int SEMANTIC_ACTION_MUTE = 6; // 0x6
+    field public static final int SEMANTIC_ACTION_NONE = 0; // 0x0
+    field public static final int SEMANTIC_ACTION_REPLY = 1; // 0x1
+    field public static final int SEMANTIC_ACTION_THUMBS_DOWN = 9; // 0x9
+    field public static final int SEMANTIC_ACTION_THUMBS_UP = 8; // 0x8
+    field public static final int SEMANTIC_ACTION_UNMUTE = 7; // 0x7
+    field public android.app.PendingIntent! actionIntent;
+    field @Deprecated public int icon;
+    field public CharSequence! title;
+  }
+
+  public static final class NotificationCompat.Action.Builder {
+    ctor public NotificationCompat.Action.Builder(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+    ctor public NotificationCompat.Action.Builder(int, CharSequence?, android.app.PendingIntent?);
+    ctor public NotificationCompat.Action.Builder(androidx.core.app.NotificationCompat.Action);
+    method public androidx.core.app.NotificationCompat.Action.Builder addExtras(android.os.Bundle?);
+    method public androidx.core.app.NotificationCompat.Action.Builder addRemoteInput(androidx.core.app.RemoteInput?);
+    method public androidx.core.app.NotificationCompat.Action build();
+    method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Extender);
+    method public android.os.Bundle getExtras();
+    method public androidx.core.app.NotificationCompat.Action.Builder setAllowGeneratedReplies(boolean);
+    method public androidx.core.app.NotificationCompat.Action.Builder setContextual(boolean);
+    method public androidx.core.app.NotificationCompat.Action.Builder setSemanticAction(@androidx.core.app.NotificationCompat.Action.SemanticAction int);
+    method public androidx.core.app.NotificationCompat.Action.Builder setShowsUserInterface(boolean);
+  }
+
+  public static interface NotificationCompat.Action.Extender {
+    method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+  }
+
+  @IntDef({androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_NONE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_REPLY, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_UNREAD, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_DELETE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_ARCHIVE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_UNMUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_UP, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_DOWN, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_CALL}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.Action.SemanticAction {
+  }
+
+  public static final class NotificationCompat.Action.WearableExtender implements androidx.core.app.NotificationCompat.Action.Extender {
+    ctor public NotificationCompat.Action.WearableExtender();
+    ctor public NotificationCompat.Action.WearableExtender(androidx.core.app.NotificationCompat.Action);
+    method public androidx.core.app.NotificationCompat.Action.WearableExtender clone();
+    method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+    method @Deprecated public CharSequence? getCancelLabel();
+    method @Deprecated public CharSequence? getConfirmLabel();
+    method public boolean getHintDisplayActionInline();
+    method public boolean getHintLaunchesActivity();
+    method @Deprecated public CharSequence? getInProgressLabel();
+    method public boolean isAvailableOffline();
+    method public androidx.core.app.NotificationCompat.Action.WearableExtender setAvailableOffline(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setCancelLabel(CharSequence?);
+    method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setConfirmLabel(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintDisplayActionInline(boolean);
+    method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintLaunchesActivity(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setInProgressLabel(CharSequence?);
+  }
+
+  public static class NotificationCompat.BigPictureStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor public NotificationCompat.BigPictureStyle();
+    ctor public NotificationCompat.BigPictureStyle(androidx.core.app.NotificationCompat.Builder?);
+    method public androidx.core.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.Bitmap?);
+    method public androidx.core.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.Bitmap?);
+    method public androidx.core.app.NotificationCompat.BigPictureStyle setBigContentTitle(CharSequence?);
+    method public androidx.core.app.NotificationCompat.BigPictureStyle setSummaryText(CharSequence?);
+  }
+
+  public static class NotificationCompat.BigTextStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor public NotificationCompat.BigTextStyle();
+    ctor public NotificationCompat.BigTextStyle(androidx.core.app.NotificationCompat.Builder?);
+    method public androidx.core.app.NotificationCompat.BigTextStyle bigText(CharSequence?);
+    method public androidx.core.app.NotificationCompat.BigTextStyle setBigContentTitle(CharSequence?);
+    method public androidx.core.app.NotificationCompat.BigTextStyle setSummaryText(CharSequence?);
+  }
+
+  public static final class NotificationCompat.BubbleMetadata {
+    method public static androidx.core.app.NotificationCompat.BubbleMetadata? fromPlatform(android.app.Notification.BubbleMetadata?);
+    method public boolean getAutoExpandBubble();
+    method public android.app.PendingIntent? getDeleteIntent();
+    method @Dimension(unit=androidx.annotation.Dimension.DP) public int getDesiredHeight();
+    method @DimenRes public int getDesiredHeightResId();
+    method public androidx.core.graphics.drawable.IconCompat? getIcon();
+    method public android.app.PendingIntent? getIntent();
+    method public String? getShortcutId();
+    method public boolean isNotificationSuppressed();
+    method public static android.app.Notification.BubbleMetadata? toPlatform(androidx.core.app.NotificationCompat.BubbleMetadata?);
+  }
+
+  public static final class NotificationCompat.BubbleMetadata.Builder {
+    ctor @Deprecated public NotificationCompat.BubbleMetadata.Builder();
+    ctor @RequiresApi(30) public NotificationCompat.BubbleMetadata.Builder(String);
+    ctor public NotificationCompat.BubbleMetadata.Builder(android.app.PendingIntent, androidx.core.graphics.drawable.IconCompat);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata build();
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setAutoExpandBubble(boolean);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDeleteIntent(android.app.PendingIntent?);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeight(@Dimension(unit=androidx.annotation.Dimension.DP) int);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIcon(androidx.core.graphics.drawable.IconCompat);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIntent(android.app.PendingIntent);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setSuppressNotification(boolean);
+  }
+
+  public static class NotificationCompat.Builder {
+    ctor @RequiresApi(19) public NotificationCompat.Builder(android.content.Context, android.app.Notification);
+    ctor public NotificationCompat.Builder(android.content.Context, String);
+    ctor @Deprecated public NotificationCompat.Builder(android.content.Context);
+    method public androidx.core.app.NotificationCompat.Builder addAction(int, CharSequence?, android.app.PendingIntent?);
+    method public androidx.core.app.NotificationCompat.Builder addAction(androidx.core.app.NotificationCompat.Action?);
+    method public androidx.core.app.NotificationCompat.Builder addExtras(android.os.Bundle?);
+    method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(int, CharSequence?, android.app.PendingIntent?);
+    method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(androidx.core.app.NotificationCompat.Action?);
+    method @Deprecated public androidx.core.app.NotificationCompat.Builder addPerson(String?);
+    method public androidx.core.app.NotificationCompat.Builder addPerson(androidx.core.app.Person?);
+    method public android.app.Notification build();
+    method public androidx.core.app.NotificationCompat.Builder clearActions();
+    method public androidx.core.app.NotificationCompat.Builder clearInvisibleActions();
+    method public androidx.core.app.NotificationCompat.Builder clearPeople();
+    method public android.widget.RemoteViews? createBigContentView();
+    method public android.widget.RemoteViews? createContentView();
+    method public android.widget.RemoteViews? createHeadsUpContentView();
+    method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Extender);
+    method public android.os.Bundle getExtras();
+    method @Deprecated public android.app.Notification getNotification();
+    method protected static CharSequence? limitCharSequenceLength(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setAllowSystemGeneratedContextualActions(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setAutoCancel(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setBadgeIconType(int);
+    method public androidx.core.app.NotificationCompat.Builder setBubbleMetadata(androidx.core.app.NotificationCompat.BubbleMetadata?);
+    method public androidx.core.app.NotificationCompat.Builder setCategory(String?);
+    method public androidx.core.app.NotificationCompat.Builder setChannelId(String);
+    method @RequiresApi(24) public androidx.core.app.NotificationCompat.Builder setChronometerCountDown(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setColor(@ColorInt int);
+    method public androidx.core.app.NotificationCompat.Builder setColorized(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setContent(android.widget.RemoteViews?);
+    method public androidx.core.app.NotificationCompat.Builder setContentInfo(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setContentIntent(android.app.PendingIntent?);
+    method public androidx.core.app.NotificationCompat.Builder setContentText(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setContentTitle(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setCustomBigContentView(android.widget.RemoteViews?);
+    method public androidx.core.app.NotificationCompat.Builder setCustomContentView(android.widget.RemoteViews?);
+    method public androidx.core.app.NotificationCompat.Builder setCustomHeadsUpContentView(android.widget.RemoteViews?);
+    method public androidx.core.app.NotificationCompat.Builder setDefaults(int);
+    method public androidx.core.app.NotificationCompat.Builder setDeleteIntent(android.app.PendingIntent?);
+    method public androidx.core.app.NotificationCompat.Builder setExtras(android.os.Bundle?);
+    method public androidx.core.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent?, boolean);
+    method public androidx.core.app.NotificationCompat.Builder setGroup(String?);
+    method public androidx.core.app.NotificationCompat.Builder setGroupAlertBehavior(int);
+    method public androidx.core.app.NotificationCompat.Builder setGroupSummary(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setLargeIcon(android.graphics.Bitmap?);
+    method public androidx.core.app.NotificationCompat.Builder setLights(@ColorInt int, int, int);
+    method public androidx.core.app.NotificationCompat.Builder setLocalOnly(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+    method @Deprecated public androidx.core.app.NotificationCompat.Builder setNotificationSilent();
+    method public androidx.core.app.NotificationCompat.Builder setNumber(int);
+    method public androidx.core.app.NotificationCompat.Builder setOngoing(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setOnlyAlertOnce(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setPriority(int);
+    method public androidx.core.app.NotificationCompat.Builder setProgress(int, int, boolean);
+    method public androidx.core.app.NotificationCompat.Builder setPublicVersion(android.app.Notification?);
+    method public androidx.core.app.NotificationCompat.Builder setRemoteInputHistory(CharSequence![]?);
+    method public androidx.core.app.NotificationCompat.Builder setSettingsText(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setShortcutId(String?);
+    method public androidx.core.app.NotificationCompat.Builder setShortcutInfo(androidx.core.content.pm.ShortcutInfoCompat?);
+    method public androidx.core.app.NotificationCompat.Builder setShowWhen(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setSilent(boolean);
+    method @RequiresApi(23) public androidx.core.app.NotificationCompat.Builder setSmallIcon(androidx.core.graphics.drawable.IconCompat);
+    method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int);
+    method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int, int);
+    method public androidx.core.app.NotificationCompat.Builder setSortKey(String?);
+    method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?);
+    method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?, int);
+    method public androidx.core.app.NotificationCompat.Builder setStyle(androidx.core.app.NotificationCompat.Style?);
+    method public androidx.core.app.NotificationCompat.Builder setSubText(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?);
+    method @Deprecated public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?, android.widget.RemoteViews?);
+    method public androidx.core.app.NotificationCompat.Builder setTimeoutAfter(long);
+    method public androidx.core.app.NotificationCompat.Builder setUsesChronometer(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setVibrate(long[]?);
+    method public androidx.core.app.NotificationCompat.Builder setVisibility(int);
+    method public androidx.core.app.NotificationCompat.Builder setWhen(long);
+    field @Deprecated public java.util.ArrayList<java.lang.String!>! mPeople;
+  }
+
+  public static final class NotificationCompat.CarExtender implements androidx.core.app.NotificationCompat.Extender {
+    ctor public NotificationCompat.CarExtender();
+    ctor public NotificationCompat.CarExtender(android.app.Notification);
+    method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+    method @ColorInt public int getColor();
+    method public android.graphics.Bitmap? getLargeIcon();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation? getUnreadConversation();
+    method public androidx.core.app.NotificationCompat.CarExtender setColor(@ColorInt int);
+    method public androidx.core.app.NotificationCompat.CarExtender setLargeIcon(android.graphics.Bitmap?);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation?);
+  }
+
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+    method @Deprecated public long getLatestTimestamp();
+    method @Deprecated public String![]? getMessages();
+    method @Deprecated public String? getParticipant();
+    method @Deprecated public String![]? getParticipants();
+    method @Deprecated public android.app.PendingIntent? getReadPendingIntent();
+    method @Deprecated public androidx.core.app.RemoteInput? getRemoteInput();
+    method @Deprecated public android.app.PendingIntent? getReplyPendingIntent();
+  }
+
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+    ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder addMessage(String?);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation build();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setLatestTimestamp(long);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReadPendingIntent(android.app.PendingIntent?);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReplyAction(android.app.PendingIntent?, androidx.core.app.RemoteInput?);
+  }
+
+  public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor public NotificationCompat.DecoratedCustomViewStyle();
+  }
+
+  public static interface NotificationCompat.Extender {
+    method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+  }
+
+  public static class NotificationCompat.InboxStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor public NotificationCompat.InboxStyle();
+    ctor public NotificationCompat.InboxStyle(androidx.core.app.NotificationCompat.Builder?);
+    method public androidx.core.app.NotificationCompat.InboxStyle addLine(CharSequence?);
+    method public androidx.core.app.NotificationCompat.InboxStyle setBigContentTitle(CharSequence?);
+    method public androidx.core.app.NotificationCompat.InboxStyle setSummaryText(CharSequence?);
+  }
+
+  public static class NotificationCompat.MessagingStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor @Deprecated public NotificationCompat.MessagingStyle(CharSequence);
+    ctor public NotificationCompat.MessagingStyle(androidx.core.app.Person);
+    method public void addCompatExtras(android.os.Bundle);
+    method public androidx.core.app.NotificationCompat.MessagingStyle addHistoricMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+    method @Deprecated public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, CharSequence?);
+    method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, androidx.core.app.Person?);
+    method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+    method public static androidx.core.app.NotificationCompat.MessagingStyle? extractMessagingStyleFromNotification(android.app.Notification);
+    method public CharSequence? getConversationTitle();
+    method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getHistoricMessages();
+    method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getMessages();
+    method public androidx.core.app.Person getUser();
+    method @Deprecated public CharSequence? getUserDisplayName();
+    method public boolean isGroupConversation();
+    method public androidx.core.app.NotificationCompat.MessagingStyle setConversationTitle(CharSequence?);
+    method public androidx.core.app.NotificationCompat.MessagingStyle setGroupConversation(boolean);
+    field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19
+  }
+
+  public static final class NotificationCompat.MessagingStyle.Message {
+    ctor public NotificationCompat.MessagingStyle.Message(CharSequence?, long, androidx.core.app.Person?);
+    ctor @Deprecated public NotificationCompat.MessagingStyle.Message(CharSequence?, long, CharSequence?);
+    method public String? getDataMimeType();
+    method public android.net.Uri? getDataUri();
+    method public android.os.Bundle getExtras();
+    method public androidx.core.app.Person? getPerson();
+    method @Deprecated public CharSequence? getSender();
+    method public CharSequence? getText();
+    method public long getTimestamp();
+    method public androidx.core.app.NotificationCompat.MessagingStyle.Message setData(String?, android.net.Uri?);
+  }
+
+  public abstract static class NotificationCompat.Style {
+    ctor public NotificationCompat.Style();
+    method public android.app.Notification? build();
+    method public void setBuilder(androidx.core.app.NotificationCompat.Builder?);
+  }
+
+  public static final class NotificationCompat.WearableExtender implements androidx.core.app.NotificationCompat.Extender {
+    ctor public NotificationCompat.WearableExtender();
+    ctor public NotificationCompat.WearableExtender(android.app.Notification);
+    method public androidx.core.app.NotificationCompat.WearableExtender addAction(androidx.core.app.NotificationCompat.Action);
+    method public androidx.core.app.NotificationCompat.WearableExtender addActions(java.util.List<androidx.core.app.NotificationCompat.Action!>);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPage(android.app.Notification);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPages(java.util.List<android.app.Notification!>);
+    method public androidx.core.app.NotificationCompat.WearableExtender clearActions();
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender clearPages();
+    method public androidx.core.app.NotificationCompat.WearableExtender clone();
+    method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+    method public java.util.List<androidx.core.app.NotificationCompat.Action!> getActions();
+    method @Deprecated public android.graphics.Bitmap? getBackground();
+    method public String? getBridgeTag();
+    method public int getContentAction();
+    method @Deprecated public int getContentIcon();
+    method @Deprecated public int getContentIconGravity();
+    method public boolean getContentIntentAvailableOffline();
+    method @Deprecated public int getCustomContentHeight();
+    method @Deprecated public int getCustomSizePreset();
+    method public String? getDismissalId();
+    method @Deprecated public android.app.PendingIntent? getDisplayIntent();
+    method @Deprecated public int getGravity();
+    method @Deprecated public boolean getHintAmbientBigPicture();
+    method @Deprecated public boolean getHintAvoidBackgroundClipping();
+    method public boolean getHintContentIntentLaunchesActivity();
+    method @Deprecated public boolean getHintHideIcon();
+    method @Deprecated public int getHintScreenTimeout();
+    method @Deprecated public boolean getHintShowBackgroundOnly();
+    method @Deprecated public java.util.List<android.app.Notification!> getPages();
+    method public boolean getStartScrollBottom();
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setBackground(android.graphics.Bitmap?);
+    method public androidx.core.app.NotificationCompat.WearableExtender setBridgeTag(String?);
+    method public androidx.core.app.NotificationCompat.WearableExtender setContentAction(int);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIcon(int);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIconGravity(int);
+    method public androidx.core.app.NotificationCompat.WearableExtender setContentIntentAvailableOffline(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomContentHeight(int);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomSizePreset(int);
+    method public androidx.core.app.NotificationCompat.WearableExtender setDismissalId(String?);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setDisplayIntent(android.app.PendingIntent?);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setGravity(int);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAmbientBigPicture(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAvoidBackgroundClipping(boolean);
+    method public androidx.core.app.NotificationCompat.WearableExtender setHintContentIntentLaunchesActivity(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintHideIcon(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintScreenTimeout(int);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintShowBackgroundOnly(boolean);
+    method public androidx.core.app.NotificationCompat.WearableExtender setStartScrollBottom(boolean);
+    field @Deprecated public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+    field @Deprecated public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
+    field @Deprecated public static final int SIZE_DEFAULT = 0; // 0x0
+    field @Deprecated public static final int SIZE_FULL_SCREEN = 5; // 0x5
+    field @Deprecated public static final int SIZE_LARGE = 4; // 0x4
+    field @Deprecated public static final int SIZE_MEDIUM = 3; // 0x3
+    field @Deprecated public static final int SIZE_SMALL = 2; // 0x2
+    field @Deprecated public static final int SIZE_XSMALL = 1; // 0x1
+    field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
+  }
+
+  public final class NotificationCompatExtras {
+    field public static final String EXTRA_ACTION_EXTRAS = "android.support.actionExtras";
+    field public static final String EXTRA_GROUP_KEY = "android.support.groupKey";
+    field public static final String EXTRA_GROUP_SUMMARY = "android.support.isGroupSummary";
+    field public static final String EXTRA_LOCAL_ONLY = "android.support.localOnly";
+    field public static final String EXTRA_REMOTE_INPUTS = "android.support.remoteInputs";
+    field public static final String EXTRA_SORT_KEY = "android.support.sortKey";
+  }
+
+  public abstract class NotificationCompatSideChannelService extends android.app.Service {
+    ctor public NotificationCompatSideChannelService();
+    method public abstract void cancel(String!, int, String!);
+    method public abstract void cancelAll(String!);
+    method public abstract void notify(String!, int, String!, android.app.Notification!);
+    method public android.os.IBinder! onBind(android.content.Intent!);
+  }
+
+  public final class NotificationManagerCompat {
+    method public boolean areNotificationsEnabled();
+    method public void cancel(int);
+    method public void cancel(String?, int);
+    method public void cancelAll();
+    method public void createNotificationChannel(android.app.NotificationChannel);
+    method public void createNotificationChannel(androidx.core.app.NotificationChannelCompat);
+    method public void createNotificationChannelGroup(android.app.NotificationChannelGroup);
+    method public void createNotificationChannelGroup(androidx.core.app.NotificationChannelGroupCompat);
+    method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup!>);
+    method public void createNotificationChannelGroupsCompat(java.util.List<androidx.core.app.NotificationChannelGroupCompat!>);
+    method public void createNotificationChannels(java.util.List<android.app.NotificationChannel!>);
+    method public void createNotificationChannelsCompat(java.util.List<androidx.core.app.NotificationChannelCompat!>);
+    method public void deleteNotificationChannel(String);
+    method public void deleteNotificationChannelGroup(String);
+    method public void deleteUnlistedNotificationChannels(java.util.Collection<java.lang.String!>);
+    method public static androidx.core.app.NotificationManagerCompat from(android.content.Context);
+    method public static java.util.Set<java.lang.String!> getEnabledListenerPackages(android.content.Context);
+    method public int getImportance();
+    method public android.app.NotificationChannel? getNotificationChannel(String);
+    method public android.app.NotificationChannel? getNotificationChannel(String, String);
+    method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String);
+    method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String, String);
+    method public android.app.NotificationChannelGroup? getNotificationChannelGroup(String);
+    method public androidx.core.app.NotificationChannelGroupCompat? getNotificationChannelGroupCompat(String);
+    method public java.util.List<android.app.NotificationChannelGroup!> getNotificationChannelGroups();
+    method public java.util.List<androidx.core.app.NotificationChannelGroupCompat!> getNotificationChannelGroupsCompat();
+    method public java.util.List<android.app.NotificationChannel!> getNotificationChannels();
+    method public java.util.List<androidx.core.app.NotificationChannelCompat!> getNotificationChannelsCompat();
+    method public void notify(int, android.app.Notification);
+    method public void notify(String?, int, android.app.Notification);
+    field public static final String ACTION_BIND_SIDE_CHANNEL = "android.support.BIND_NOTIFICATION_SIDE_CHANNEL";
+    field public static final String EXTRA_USE_SIDE_CHANNEL = "android.support.useSideChannel";
+    field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+    field public static final int IMPORTANCE_HIGH = 4; // 0x4
+    field public static final int IMPORTANCE_LOW = 2; // 0x2
+    field public static final int IMPORTANCE_MAX = 5; // 0x5
+    field public static final int IMPORTANCE_MIN = 1; // 0x1
+    field public static final int IMPORTANCE_NONE = 0; // 0x0
+    field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
+  }
+
+  public class Person {
+    method public static androidx.core.app.Person fromBundle(android.os.Bundle);
+    method public androidx.core.graphics.drawable.IconCompat? getIcon();
+    method public String? getKey();
+    method public CharSequence? getName();
+    method public String? getUri();
+    method public boolean isBot();
+    method public boolean isImportant();
+    method public androidx.core.app.Person.Builder toBuilder();
+    method public android.os.Bundle toBundle();
+  }
+
+  public static class Person.Builder {
+    ctor public Person.Builder();
+    method public androidx.core.app.Person build();
+    method public androidx.core.app.Person.Builder setBot(boolean);
+    method public androidx.core.app.Person.Builder setIcon(androidx.core.graphics.drawable.IconCompat?);
+    method public androidx.core.app.Person.Builder setImportant(boolean);
+    method public androidx.core.app.Person.Builder setKey(String?);
+    method public androidx.core.app.Person.Builder setName(CharSequence?);
+    method public androidx.core.app.Person.Builder setUri(String?);
+  }
+
+  @androidx.versionedparcelable.VersionedParcelize(jetifyAs="android.support.v4.app.RemoteActionCompat") public final class RemoteActionCompat implements androidx.versionedparcelable.VersionedParcelable {
+    ctor public RemoteActionCompat(androidx.core.graphics.drawable.IconCompat, CharSequence, CharSequence, android.app.PendingIntent);
+    ctor public RemoteActionCompat(androidx.core.app.RemoteActionCompat);
+    method @RequiresApi(26) public static androidx.core.app.RemoteActionCompat createFromRemoteAction(android.app.RemoteAction);
+    method public android.app.PendingIntent getActionIntent();
+    method public CharSequence getContentDescription();
+    method public androidx.core.graphics.drawable.IconCompat getIcon();
+    method public CharSequence getTitle();
+    method public boolean isEnabled();
+    method public void setEnabled(boolean);
+    method public void setShouldShowIcon(boolean);
+    method public boolean shouldShowIcon();
+    method @RequiresApi(26) public android.app.RemoteAction toRemoteAction();
+  }
+
+  public final class RemoteInput {
+    method public static void addDataResultToIntent(androidx.core.app.RemoteInput!, android.content.Intent!, java.util.Map<java.lang.String!,android.net.Uri!>!);
+    method public static void addResultsToIntent(androidx.core.app.RemoteInput![]!, android.content.Intent!, android.os.Bundle!);
+    method public boolean getAllowFreeFormInput();
+    method public java.util.Set<java.lang.String!>! getAllowedDataTypes();
+    method public CharSequence![]! getChoices();
+    method public static java.util.Map<java.lang.String!,android.net.Uri!>! getDataResultsFromIntent(android.content.Intent!, String!);
+    method public int getEditChoicesBeforeSending();
+    method public android.os.Bundle! getExtras();
+    method public CharSequence! getLabel();
+    method public String! getResultKey();
+    method public static android.os.Bundle! getResultsFromIntent(android.content.Intent!);
+    method public static int getResultsSource(android.content.Intent);
+    method public boolean isDataOnly();
+    method public static void setResultsSource(android.content.Intent, int);
+    field public static final int EDIT_CHOICES_BEFORE_SENDING_AUTO = 0; // 0x0
+    field public static final int EDIT_CHOICES_BEFORE_SENDING_DISABLED = 1; // 0x1
+    field public static final int EDIT_CHOICES_BEFORE_SENDING_ENABLED = 2; // 0x2
+    field public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+    field public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+    field public static final int SOURCE_CHOICE = 1; // 0x1
+    field public static final int SOURCE_FREE_FORM_INPUT = 0; // 0x0
+  }
+
+  public static final class RemoteInput.Builder {
+    ctor public RemoteInput.Builder(String);
+    method public androidx.core.app.RemoteInput.Builder addExtras(android.os.Bundle);
+    method public androidx.core.app.RemoteInput build();
+    method public android.os.Bundle getExtras();
+    method public androidx.core.app.RemoteInput.Builder setAllowDataType(String, boolean);
+    method public androidx.core.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
+    method public androidx.core.app.RemoteInput.Builder setChoices(CharSequence![]?);
+    method public androidx.core.app.RemoteInput.Builder setEditChoicesBeforeSending(int);
+    method public androidx.core.app.RemoteInput.Builder setLabel(CharSequence?);
+  }
+
+  public final class ServiceCompat {
+    method public static void stopForeground(android.app.Service, int);
+    field public static final int START_STICKY = 1; // 0x1
+    field public static final int STOP_FOREGROUND_DETACH = 2; // 0x2
+    field public static final int STOP_FOREGROUND_REMOVE = 1; // 0x1
+  }
+
+  public final class ShareCompat {
+    method @Deprecated public static void configureMenuItem(android.view.MenuItem, androidx.core.app.ShareCompat.IntentBuilder);
+    method @Deprecated public static void configureMenuItem(android.view.Menu, @IdRes int, androidx.core.app.ShareCompat.IntentBuilder);
+    method public static android.content.ComponentName? getCallingActivity(android.app.Activity);
+    method public static String? getCallingPackage(android.app.Activity);
+    field public static final String EXTRA_CALLING_ACTIVITY = "androidx.core.app.EXTRA_CALLING_ACTIVITY";
+    field public static final String EXTRA_CALLING_ACTIVITY_INTEROP = "android.support.v4.app.EXTRA_CALLING_ACTIVITY";
+    field public static final String EXTRA_CALLING_PACKAGE = "androidx.core.app.EXTRA_CALLING_PACKAGE";
+    field public static final String EXTRA_CALLING_PACKAGE_INTEROP = "android.support.v4.app.EXTRA_CALLING_PACKAGE";
+  }
+
+  public static class ShareCompat.IntentBuilder {
+    ctor public ShareCompat.IntentBuilder(android.content.Context);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String![]);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String![]);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String![]);
+    method public androidx.core.app.ShareCompat.IntentBuilder addStream(android.net.Uri);
+    method public android.content.Intent createChooserIntent();
+    method @Deprecated public static androidx.core.app.ShareCompat.IntentBuilder from(android.app.Activity);
+    method public android.content.Intent getIntent();
+    method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(CharSequence?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(@StringRes int);
+    method public androidx.core.app.ShareCompat.IntentBuilder setEmailBcc(String![]?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setEmailCc(String![]?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setEmailTo(String![]?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setHtmlText(String?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setStream(android.net.Uri?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setSubject(String?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setText(CharSequence?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setType(String?);
+    method public void startChooser();
+  }
+
+  public static class ShareCompat.IntentReader {
+    ctor public ShareCompat.IntentReader(android.app.Activity);
+    ctor public ShareCompat.IntentReader(android.content.Context, android.content.Intent);
+    method @Deprecated public static androidx.core.app.ShareCompat.IntentReader from(android.app.Activity);
+    method public android.content.ComponentName? getCallingActivity();
+    method public android.graphics.drawable.Drawable? getCallingActivityIcon();
+    method public android.graphics.drawable.Drawable? getCallingApplicationIcon();
+    method public CharSequence? getCallingApplicationLabel();
+    method public String? getCallingPackage();
+    method public String![]? getEmailBcc();
+    method public String![]? getEmailCc();
+    method public String![]? getEmailTo();
+    method public String? getHtmlText();
+    method public android.net.Uri? getStream();
+    method public android.net.Uri? getStream(int);
+    method public int getStreamCount();
+    method public String? getSubject();
+    method public CharSequence? getText();
+    method public String? getType();
+    method public boolean isMultipleShare();
+    method public boolean isShareIntent();
+    method public boolean isSingleShare();
+  }
+
+  public abstract class SharedElementCallback {
+    ctor public SharedElementCallback();
+    method public android.os.Parcelable! onCaptureSharedElementSnapshot(android.view.View!, android.graphics.Matrix!, android.graphics.RectF!);
+    method public android.view.View! onCreateSnapshotView(android.content.Context!, android.os.Parcelable!);
+    method public void onMapSharedElements(java.util.List<java.lang.String!>!, java.util.Map<java.lang.String!,android.view.View!>!);
+    method public void onRejectSharedElements(java.util.List<android.view.View!>!);
+    method public void onSharedElementEnd(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+    method public void onSharedElementStart(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+    method public void onSharedElementsArrived(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, androidx.core.app.SharedElementCallback.OnSharedElementsReadyListener!);
+  }
+
+  public static interface SharedElementCallback.OnSharedElementsReadyListener {
+    method public void onSharedElementsReady();
+  }
+
+  public final class TaskStackBuilder implements java.lang.Iterable<android.content.Intent> {
+    method public androidx.core.app.TaskStackBuilder addNextIntent(android.content.Intent);
+    method public androidx.core.app.TaskStackBuilder addNextIntentWithParentStack(android.content.Intent);
+    method public androidx.core.app.TaskStackBuilder addParentStack(android.app.Activity);
+    method public androidx.core.app.TaskStackBuilder addParentStack(Class<?>);
+    method public androidx.core.app.TaskStackBuilder! addParentStack(android.content.ComponentName!);
+    method public static androidx.core.app.TaskStackBuilder create(android.content.Context);
+    method public android.content.Intent? editIntentAt(int);
+    method @Deprecated public static androidx.core.app.TaskStackBuilder! from(android.content.Context!);
+    method @Deprecated public android.content.Intent! getIntent(int);
+    method public int getIntentCount();
+    method public android.content.Intent![] getIntents();
+    method public android.app.PendingIntent? getPendingIntent(int, int);
+    method public android.app.PendingIntent? getPendingIntent(int, int, android.os.Bundle?);
+    method @Deprecated public java.util.Iterator<android.content.Intent!>! iterator();
+    method public void startActivities();
+    method public void startActivities(android.os.Bundle?);
+  }
+
+  public static interface TaskStackBuilder.SupportParentable {
+    method public android.content.Intent? getSupportParentActivityIntent();
+  }
+
+}
+
+package androidx.core.content {
+
+  public final class ContentProviderCompat {
+    method public static android.content.Context requireContext(android.content.ContentProvider);
+  }
+
+  public final class ContentResolverCompat {
+    method public static android.database.Cursor! query(android.content.ContentResolver!, android.net.Uri!, String![]!, String!, String![]!, String!, androidx.core.os.CancellationSignal!);
+  }
+
+  public class ContextCompat {
+    ctor protected ContextCompat();
+    method public static int checkSelfPermission(android.content.Context, String);
+    method public static android.content.Context? createDeviceProtectedStorageContext(android.content.Context);
+    method public static java.io.File! getCodeCacheDir(android.content.Context);
+    method @ColorInt public static int getColor(android.content.Context, @ColorRes int);
+    method public static android.content.res.ColorStateList? getColorStateList(android.content.Context, @ColorRes int);
+    method public static java.io.File? getDataDir(android.content.Context);
+    method public static android.graphics.drawable.Drawable? getDrawable(android.content.Context, @DrawableRes int);
+    method public static java.io.File![] getExternalCacheDirs(android.content.Context);
+    method public static java.io.File![] getExternalFilesDirs(android.content.Context, String?);
+    method public static java.util.concurrent.Executor! getMainExecutor(android.content.Context!);
+    method public static java.io.File? getNoBackupFilesDir(android.content.Context);
+    method public static java.io.File![] getObbDirs(android.content.Context);
+    method public static <T> T? getSystemService(android.content.Context, Class<T!>);
+    method public static String? getSystemServiceName(android.content.Context, Class<?>);
+    method public static boolean isDeviceProtectedStorage(android.content.Context);
+    method public static boolean startActivities(android.content.Context, android.content.Intent![]);
+    method public static boolean startActivities(android.content.Context, android.content.Intent![], android.os.Bundle?);
+    method public static void startActivity(android.content.Context, android.content.Intent, android.os.Bundle?);
+    method public static void startForegroundService(android.content.Context, android.content.Intent);
+  }
+
+  public class FileProvider extends android.content.ContentProvider {
+    ctor public FileProvider();
+    method public int delete(android.net.Uri, String?, String![]?);
+    method public String! getType(android.net.Uri);
+    method public static android.net.Uri! getUriForFile(android.content.Context, String, java.io.File);
+    method public static android.net.Uri getUriForFile(android.content.Context, String, java.io.File, String);
+    method public android.net.Uri! insert(android.net.Uri, android.content.ContentValues!);
+    method public boolean onCreate();
+    method public android.database.Cursor! query(android.net.Uri, String![]?, String?, String![]?, String?);
+    method public int update(android.net.Uri, android.content.ContentValues!, String?, String![]?);
+  }
+
+  public final class IntentCompat {
+    method public static android.content.Intent makeMainSelectorActivity(String, String);
+    field public static final String ACTION_CREATE_REMINDER = "android.intent.action.CREATE_REMINDER";
+    field public static final String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
+    field public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+    field public static final String EXTRA_START_PLAYBACK = "android.intent.extra.START_PLAYBACK";
+    field public static final String EXTRA_TIME = "android.intent.extra.TIME";
+  }
+
+  public final class LocusIdCompat {
+    ctor public LocusIdCompat(String);
+    method public String getId();
+    method @RequiresApi(29) public android.content.LocusId toLocusId();
+    method @RequiresApi(29) public static androidx.core.content.LocusIdCompat toLocusIdCompat(android.content.LocusId);
+  }
+
+  public final class MimeTypeFilter {
+    method public static boolean matches(String?, String);
+    method public static String? matches(String?, String![]);
+    method public static String? matches(String![]?, String);
+    method public static String![] matchesMany(String![]?, String);
+  }
+
+  public final class PermissionChecker {
+    method public static int checkCallingOrSelfPermission(android.content.Context, String);
+    method public static int checkCallingPermission(android.content.Context, String, String?);
+    method public static int checkPermission(android.content.Context, String, int, int, String?);
+    method public static int checkSelfPermission(android.content.Context, String);
+    field public static final int PERMISSION_DENIED = -1; // 0xffffffff
+    field public static final int PERMISSION_DENIED_APP_OP = -2; // 0xfffffffe
+    field public static final int PERMISSION_GRANTED = 0; // 0x0
+  }
+
+  @Deprecated public final class SharedPreferencesCompat {
+  }
+
+  @Deprecated public static final class SharedPreferencesCompat.EditorCompat {
+    method @Deprecated public void apply(android.content.SharedPreferences.Editor);
+    method @Deprecated public static androidx.core.content.SharedPreferencesCompat.EditorCompat! getInstance();
+  }
+
+}
+
+package androidx.core.content.pm {
+
+  @Deprecated public final class ActivityInfoCompat {
+    field @Deprecated public static final int CONFIG_UI_MODE = 512; // 0x200
+  }
+
+  public final class PackageInfoCompat {
+    method public static long getLongVersionCode(android.content.pm.PackageInfo);
+    method public static java.util.List<android.content.pm.Signature!> getSignatures(android.content.pm.PackageManager, String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static boolean hasSignatures(android.content.pm.PackageManager, String, @Size(min=1) java.util.Map<byte[]!,java.lang.Integer!>, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
+  }
+
+  public final class PermissionInfoCompat {
+    method public static int getProtection(android.content.pm.PermissionInfo);
+    method public static int getProtectionFlags(android.content.pm.PermissionInfo);
+  }
+
+  public class ShortcutInfoCompat {
+    method public android.content.ComponentName? getActivity();
+    method public java.util.Set<java.lang.String!>? getCategories();
+    method public CharSequence? getDisabledMessage();
+    method public int getDisabledReason();
+    method public android.os.PersistableBundle? getExtras();
+    method public String getId();
+    method public android.content.Intent getIntent();
+    method public android.content.Intent![] getIntents();
+    method public long getLastChangedTimestamp();
+    method public androidx.core.content.LocusIdCompat? getLocusId();
+    method public CharSequence? getLongLabel();
+    method public String getPackage();
+    method public int getRank();
+    method public CharSequence getShortLabel();
+    method public android.os.UserHandle? getUserHandle();
+    method public boolean hasKeyFieldsOnly();
+    method public boolean isCached();
+    method public boolean isDeclaredInManifest();
+    method public boolean isDynamic();
+    method public boolean isEnabled();
+    method public boolean isImmutable();
+    method public boolean isPinned();
+    method @RequiresApi(25) public android.content.pm.ShortcutInfo! toShortcutInfo();
+  }
+
+  public static class ShortcutInfoCompat.Builder {
+    ctor public ShortcutInfoCompat.Builder(android.content.Context, String);
+    method public androidx.core.content.pm.ShortcutInfoCompat build();
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setActivity(android.content.ComponentName);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setAlwaysBadged();
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setCategories(java.util.Set<java.lang.String!>);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setDisabledMessage(CharSequence);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setExtras(android.os.PersistableBundle);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIcon(androidx.core.graphics.drawable.IconCompat!);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntent(android.content.Intent);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntents(android.content.Intent![]);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIsConversation();
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLabel(CharSequence);
+    method @Deprecated public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived();
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived(boolean);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPerson(androidx.core.app.Person);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPersons(androidx.core.app.Person![]);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setRank(int);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setShortLabel(CharSequence);
+  }
+
+  public class ShortcutManagerCompat {
+    method public static boolean addDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+    method public static android.content.Intent createShortcutResultIntent(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+    method public static void disableShortcuts(android.content.Context, java.util.List<java.lang.String!>, CharSequence?);
+    method public static void enableShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+    method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getDynamicShortcuts(android.content.Context);
+    method public static int getIconMaxHeight(android.content.Context);
+    method public static int getIconMaxWidth(android.content.Context);
+    method public static int getMaxShortcutCountPerActivity(android.content.Context);
+    method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getShortcuts(android.content.Context, int);
+    method public static boolean isRateLimitingActive(android.content.Context);
+    method public static boolean isRequestPinShortcutSupported(android.content.Context);
+    method public static boolean pushDynamicShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+    method public static void removeAllDynamicShortcuts(android.content.Context);
+    method public static void removeDynamicShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+    method public static void removeLongLivedShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+    method public static void reportShortcutUsed(android.content.Context, String);
+    method public static boolean requestPinShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat, android.content.IntentSender?);
+    method public static boolean setDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+    method public static boolean updateShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+    field public static final String EXTRA_SHORTCUT_ID = "android.intent.extra.shortcut.ID";
+    field public static final int FLAG_MATCH_CACHED = 8; // 0x8
+    field public static final int FLAG_MATCH_DYNAMIC = 2; // 0x2
+    field public static final int FLAG_MATCH_MANIFEST = 1; // 0x1
+    field public static final int FLAG_MATCH_PINNED = 4; // 0x4
+  }
+
+}
+
+package androidx.core.content.res {
+
+  public final class ConfigurationHelper {
+    method public static int getDensityDpi(android.content.res.Resources);
+  }
+
+  public final class ResourcesCompat {
+    method public static android.graphics.Typeface? getCachedFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+    method @ColorInt public static int getColor(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+    method public static android.content.res.ColorStateList? getColorStateList(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+    method public static android.graphics.drawable.Drawable? getDrawable(android.content.res.Resources, @DrawableRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+    method public static android.graphics.drawable.Drawable? getDrawableForDensity(android.content.res.Resources, @DrawableRes int, int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+    method public static float getFloat(android.content.res.Resources, @DimenRes int);
+    method public static android.graphics.Typeface? getFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+    method public static void getFont(android.content.Context, @FontRes int, androidx.core.content.res.ResourcesCompat.FontCallback, android.os.Handler?) throws android.content.res.Resources.NotFoundException;
+    field @AnyRes public static final int ID_NULL = 0; // 0x0
+  }
+
+  public abstract static class ResourcesCompat.FontCallback {
+    ctor public ResourcesCompat.FontCallback();
+    method public abstract void onFontRetrievalFailed(int);
+    method public abstract void onFontRetrieved(android.graphics.Typeface);
+  }
+
+  public static final class ResourcesCompat.ThemeCompat {
+    method public static void rebase(android.content.res.Resources.Theme);
+  }
+
+}
+
+package androidx.core.database {
+
+  public final class CursorWindowCompat {
+    method public static android.database.CursorWindow create(String?, long);
+  }
+
+  @Deprecated public final class DatabaseUtilsCompat {
+    method @Deprecated public static String![]! appendSelectionArgs(String![]!, String![]!);
+    method @Deprecated public static String! concatenateWhere(String!, String!);
+  }
+
+}
+
+package androidx.core.database.sqlite {
+
+  public final class SQLiteCursorCompat {
+    method public static void setFillWindowForwardOnly(android.database.sqlite.SQLiteCursor, boolean);
+  }
+
+}
+
+package androidx.core.graphics {
+
+  public final class BitmapCompat {
+    method public static int getAllocationByteCount(android.graphics.Bitmap);
+    method public static boolean hasMipMap(android.graphics.Bitmap);
+    method public static void setHasMipMap(android.graphics.Bitmap, boolean);
+  }
+
+  public class BlendModeColorFilterCompat {
+    method public static android.graphics.ColorFilter? createBlendModeColorFilterCompat(int, androidx.core.graphics.BlendModeCompat);
+  }
+
+  public enum BlendModeCompat {
+    enum_constant public static final androidx.core.graphics.BlendModeCompat CLEAR;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_BURN;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_DODGE;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DARKEN;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat DIFFERENCE;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DST;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DST_ATOP;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DST_IN;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OUT;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OVER;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat EXCLUSION;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HARD_LIGHT;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HUE;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat LIGHTEN;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat LUMINOSITY;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat MODULATE;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat MULTIPLY;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat OVERLAY;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat PLUS;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SATURATION;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SCREEN;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SOFT_LIGHT;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SRC;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_ATOP;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_IN;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OUT;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OVER;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat XOR;
+  }
+
+  public final class ColorUtils {
+    method @ColorInt public static int HSLToColor(float[]);
+    method @ColorInt public static int LABToColor(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double);
+    method public static void LABToXYZ(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double, double[]);
+    method public static void RGBToHSL(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, float[]);
+    method public static void RGBToLAB(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+    method public static void RGBToXYZ(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+    method @ColorInt public static int XYZToColor(@FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_X) double, @FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_Y) double, @FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_Z) double);
+    method public static void XYZToLAB(@FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_X) double, @FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_Y) double, @FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_Z) double, double[]);
+    method @ColorInt public static int blendARGB(@ColorInt int, @ColorInt int, @FloatRange(from=0.0, to=1.0) float);
+    method public static void blendHSL(float[], float[], @FloatRange(from=0.0, to=1.0) float, float[]);
+    method public static void blendLAB(double[], double[], @FloatRange(from=0.0, to=1.0) double, double[]);
+    method public static double calculateContrast(@ColorInt int, @ColorInt int);
+    method @FloatRange(from=0.0, to=1.0) public static double calculateLuminance(@ColorInt int);
+    method public static int calculateMinimumAlpha(@ColorInt int, @ColorInt int, float);
+    method public static void colorToHSL(@ColorInt int, float[]);
+    method public static void colorToLAB(@ColorInt int, double[]);
+    method public static void colorToXYZ(@ColorInt int, double[]);
+    method public static int compositeColors(@ColorInt int, @ColorInt int);
+    method @RequiresApi(26) public static android.graphics.Color compositeColors(android.graphics.Color, android.graphics.Color);
+    method public static double distanceEuclidean(double[], double[]);
+    method @ColorInt public static int setAlphaComponent(@ColorInt int, @IntRange(from=0, to=255) int);
+  }
+
+  public final class Insets {
+    method public static androidx.core.graphics.Insets add(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+    method public static androidx.core.graphics.Insets max(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+    method public static androidx.core.graphics.Insets min(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+    method public static androidx.core.graphics.Insets of(int, int, int, int);
+    method public static androidx.core.graphics.Insets of(android.graphics.Rect);
+    method public static androidx.core.graphics.Insets subtract(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+    method @RequiresApi(api=29) public static androidx.core.graphics.Insets toCompatInsets(android.graphics.Insets);
+    method @RequiresApi(api=29) public android.graphics.Insets toPlatformInsets();
+    field public static final androidx.core.graphics.Insets NONE;
+    field public final int bottom;
+    field public final int left;
+    field public final int right;
+    field public final int top;
+  }
+
+  public final class PaintCompat {
+    method public static boolean hasGlyph(android.graphics.Paint, String);
+    method public static boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat?);
+  }
+
+  public final class PathSegment {
+    ctor public PathSegment(android.graphics.PointF, float, android.graphics.PointF, float);
+    method public android.graphics.PointF getEnd();
+    method public float getEndFraction();
+    method public android.graphics.PointF getStart();
+    method public float getStartFraction();
+  }
+
+  public final class PathUtils {
+    method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path);
+    method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path, @FloatRange(from=0) float);
+  }
+
+  public class TypefaceCompat {
+    method public static android.graphics.Typeface create(android.content.Context, android.graphics.Typeface?, int);
+  }
+
+}
+
+package androidx.core.graphics.drawable {
+
+  public final class DrawableCompat {
+    method public static void applyTheme(android.graphics.drawable.Drawable, android.content.res.Resources.Theme);
+    method public static boolean canApplyTheme(android.graphics.drawable.Drawable);
+    method public static void clearColorFilter(android.graphics.drawable.Drawable);
+    method public static int getAlpha(android.graphics.drawable.Drawable);
+    method public static android.graphics.ColorFilter! getColorFilter(android.graphics.drawable.Drawable);
+    method public static int getLayoutDirection(android.graphics.drawable.Drawable);
+    method public static void inflate(android.graphics.drawable.Drawable, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
+    method @Deprecated public static void jumpToCurrentState(android.graphics.drawable.Drawable);
+    method public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
+    method public static void setHotspot(android.graphics.drawable.Drawable, float, float);
+    method public static void setHotspotBounds(android.graphics.drawable.Drawable, int, int, int, int);
+    method public static boolean setLayoutDirection(android.graphics.drawable.Drawable, int);
+    method public static void setTint(android.graphics.drawable.Drawable, @ColorInt int);
+    method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList?);
+    method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode);
+    method public static <T extends android.graphics.drawable.Drawable> T! unwrap(android.graphics.drawable.Drawable);
+    method public static android.graphics.drawable.Drawable! wrap(android.graphics.drawable.Drawable);
+  }
+
+  @androidx.versionedparcelable.VersionedParcelize(allowSerialization=true, ignoreParcelables=true, isCustom=true, jetifyAs="android.support.v4.graphics.drawable.IconCompat") public class IconCompat extends androidx.versionedparcelable.CustomVersionedParcelable {
+    method public static androidx.core.graphics.drawable.IconCompat? createFromBundle(android.os.Bundle);
+    method @RequiresApi(23) public static androidx.core.graphics.drawable.IconCompat? createFromIcon(android.content.Context, android.graphics.drawable.Icon);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithAdaptiveBitmap(android.graphics.Bitmap!);
+    method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(String);
+    method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(android.net.Uri);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithBitmap(android.graphics.Bitmap!);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithContentUri(String!);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithContentUri(android.net.Uri!);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithData(byte[]!, int, int);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithResource(android.content.Context!, @DrawableRes int);
+    method @IdRes public int getResId();
+    method public String getResPackage();
+    method public int getType();
+    method public android.net.Uri getUri();
+    method public android.graphics.drawable.Drawable? loadDrawable(android.content.Context);
+    method public androidx.core.graphics.drawable.IconCompat! setTint(@ColorInt int);
+    method public androidx.core.graphics.drawable.IconCompat! setTintList(android.content.res.ColorStateList!);
+    method public androidx.core.graphics.drawable.IconCompat! setTintMode(android.graphics.PorterDuff.Mode!);
+    method public android.os.Bundle toBundle();
+    method @Deprecated @RequiresApi(23) public android.graphics.drawable.Icon toIcon();
+    method @RequiresApi(23) public android.graphics.drawable.Icon toIcon(android.content.Context?);
+    field public static final int TYPE_ADAPTIVE_BITMAP = 5; // 0x5
+    field public static final int TYPE_BITMAP = 1; // 0x1
+    field public static final int TYPE_DATA = 3; // 0x3
+    field public static final int TYPE_RESOURCE = 2; // 0x2
+    field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
+    field public static final int TYPE_URI = 4; // 0x4
+    field public static final int TYPE_URI_ADAPTIVE_BITMAP = 6; // 0x6
+  }
+
+  public abstract class RoundedBitmapDrawable extends android.graphics.drawable.Drawable {
+    method public void draw(android.graphics.Canvas);
+    method public final android.graphics.Bitmap? getBitmap();
+    method public float getCornerRadius();
+    method public int getGravity();
+    method public int getOpacity();
+    method public final android.graphics.Paint getPaint();
+    method public boolean hasAntiAlias();
+    method public boolean hasMipMap();
+    method public boolean isCircular();
+    method public void setAlpha(int);
+    method public void setAntiAlias(boolean);
+    method public void setCircular(boolean);
+    method public void setColorFilter(android.graphics.ColorFilter!);
+    method public void setCornerRadius(float);
+    method public void setDither(boolean);
+    method public void setGravity(int);
+    method public void setMipMap(boolean);
+    method public void setTargetDensity(android.graphics.Canvas);
+    method public void setTargetDensity(android.util.DisplayMetrics);
+    method public void setTargetDensity(int);
+  }
+
+  public final class RoundedBitmapDrawableFactory {
+    method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, android.graphics.Bitmap?);
+    method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, String);
+    method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.io.InputStream);
+  }
+
+}
+
+package androidx.core.hardware.display {
+
+  public final class DisplayManagerCompat {
+    method public android.view.Display? getDisplay(int);
+    method public android.view.Display![] getDisplays();
+    method public android.view.Display![] getDisplays(String?);
+    method public static androidx.core.hardware.display.DisplayManagerCompat getInstance(android.content.Context);
+    field public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+  }
+
+}
+
+package androidx.core.hardware.fingerprint {
+
+  @Deprecated public class FingerprintManagerCompat {
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public void authenticate(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject?, int, androidx.core.os.CancellationSignal?, androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback, android.os.Handler?);
+    method @Deprecated public static androidx.core.hardware.fingerprint.FingerprintManagerCompat from(android.content.Context);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
+  }
+
+  @Deprecated public abstract static class FingerprintManagerCompat.AuthenticationCallback {
+    ctor @Deprecated public FingerprintManagerCompat.AuthenticationCallback();
+    method @Deprecated public void onAuthenticationError(int, CharSequence!);
+    method @Deprecated public void onAuthenticationFailed();
+    method @Deprecated public void onAuthenticationHelp(int, CharSequence!);
+    method @Deprecated public void onAuthenticationSucceeded(androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationResult!);
+  }
+
+  @Deprecated public static final class FingerprintManagerCompat.AuthenticationResult {
+    ctor @Deprecated public FingerprintManagerCompat.AuthenticationResult(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject!);
+    method @Deprecated public androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject! getCryptoObject();
+  }
+
+  @Deprecated public static class FingerprintManagerCompat.CryptoObject {
+    ctor @Deprecated public FingerprintManagerCompat.CryptoObject(java.security.Signature);
+    ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Cipher);
+    ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Mac);
+    method @Deprecated public javax.crypto.Cipher? getCipher();
+    method @Deprecated public javax.crypto.Mac? getMac();
+    method @Deprecated public java.security.Signature? getSignature();
+  }
+
+}
+
+package androidx.core.location {
+
+  public abstract class GnssStatusCompat {
+    method @FloatRange(from=0, to=360) public abstract float getAzimuthDegrees(@IntRange(from=0) int);
+    method @FloatRange(from=0, to=63) public abstract float getBasebandCn0DbHz(@IntRange(from=0) int);
+    method @FloatRange(from=0) public abstract float getCarrierFrequencyHz(@IntRange(from=0) int);
+    method @FloatRange(from=0, to=63) public abstract float getCn0DbHz(@IntRange(from=0) int);
+    method public abstract int getConstellationType(@IntRange(from=0) int);
+    method @FloatRange(from=0xffffffa6, to=90) public abstract float getElevationDegrees(@IntRange(from=0) int);
+    method @IntRange(from=0) public abstract int getSatelliteCount();
+    method @IntRange(from=1, to=200) public abstract int getSvid(@IntRange(from=0) int);
+    method public abstract boolean hasAlmanacData(@IntRange(from=0) int);
+    method public abstract boolean hasBasebandCn0DbHz(@IntRange(from=0) int);
+    method public abstract boolean hasCarrierFrequencyHz(@IntRange(from=0) int);
+    method public abstract boolean hasEphemerisData(@IntRange(from=0) int);
+    method public abstract boolean usedInFix(@IntRange(from=0) int);
+    method @RequiresApi(android.os.Build.VERSION_CODES.N) public static androidx.core.location.GnssStatusCompat wrap(android.location.GnssStatus);
+    method public static androidx.core.location.GnssStatusCompat wrap(android.location.GpsStatus);
+    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+    field public static final int CONSTELLATION_GPS = 1; // 0x1
+    field public static final int CONSTELLATION_IRNSS = 7; // 0x7
+    field public static final int CONSTELLATION_QZSS = 4; // 0x4
+    field public static final int CONSTELLATION_SBAS = 2; // 0x2
+    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+  }
+
+  public abstract static class GnssStatusCompat.Callback {
+    ctor public GnssStatusCompat.Callback();
+    method public void onFirstFix(@IntRange(from=0) int);
+    method public void onSatelliteStatusChanged(androidx.core.location.GnssStatusCompat);
+    method public void onStarted();
+    method public void onStopped();
+  }
+
+  public final class LocationManagerCompat {
+    method public static boolean isLocationEnabled(android.location.LocationManager);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback, android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, java.util.concurrent.Executor, androidx.core.location.GnssStatusCompat.Callback);
+    method public static void unregisterGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback);
+  }
+
+}
+
+package androidx.core.math {
+
+  public class MathUtils {
+    method public static float clamp(float, float, float);
+    method public static double clamp(double, double, double);
+    method public static int clamp(int, int, int);
+    method public static long clamp(long, long, long);
+  }
+
+}
+
+package androidx.core.net {
+
+  public final class ConnectivityManagerCompat {
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static android.net.NetworkInfo? getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
+    method public static int getRestrictBackgroundStatus(android.net.ConnectivityManager);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+    field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+    field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+    field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
+  }
+
+  public final class MailTo {
+    method public String? getBcc();
+    method public String? getBody();
+    method public String? getCc();
+    method public java.util.Map<java.lang.String!,java.lang.String!>? getHeaders();
+    method public String? getSubject();
+    method public String? getTo();
+    method public static boolean isMailTo(String?);
+    method public static boolean isMailTo(android.net.Uri?);
+    method public static androidx.core.net.MailTo parse(String) throws androidx.core.net.ParseException;
+    method public static androidx.core.net.MailTo parse(android.net.Uri) throws androidx.core.net.ParseException;
+    field public static final String MAILTO_SCHEME = "mailto:";
+  }
+
+  public class ParseException extends java.lang.RuntimeException {
+    field public final String response;
+  }
+
+  public final class TrafficStatsCompat {
+    method @Deprecated public static void clearThreadStatsTag();
+    method @Deprecated public static int getThreadStatsTag();
+    method @Deprecated public static void incrementOperationCount(int);
+    method @Deprecated public static void incrementOperationCount(int, int);
+    method @Deprecated public static void setThreadStatsTag(int);
+    method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+    method @Deprecated public static void tagSocket(java.net.Socket!) throws java.net.SocketException;
+    method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+    method @Deprecated public static void untagSocket(java.net.Socket!) throws java.net.SocketException;
+  }
+
+  public final class UriCompat {
+    method public static String toSafeString(android.net.Uri);
+  }
+
+}
+
+package androidx.core.os {
+
+  public class BuildCompat {
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N) public static boolean isAtLeastN();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N_MR1) public static boolean isAtLeastNMR1();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O) public static boolean isAtLeastO();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O_MR1) public static boolean isAtLeastOMR1();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.P) public static boolean isAtLeastP();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.Q) public static boolean isAtLeastQ();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.R) public static boolean isAtLeastR();
+    method @ChecksSdkIntAtLeast(codename="S") public static boolean isAtLeastS();
+  }
+
+  public final class CancellationSignal {
+    ctor public CancellationSignal();
+    method public void cancel();
+    method public Object? getCancellationSignalObject();
+    method public boolean isCanceled();
+    method public void setOnCancelListener(androidx.core.os.CancellationSignal.OnCancelListener?);
+    method public void throwIfCanceled();
+  }
+
+  public static interface CancellationSignal.OnCancelListener {
+    method public void onCancel();
+  }
+
+  public final class ConfigurationCompat {
+    method public static androidx.core.os.LocaleListCompat getLocales(android.content.res.Configuration);
+  }
+
+  public final class EnvironmentCompat {
+    method public static String getStorageState(java.io.File);
+    field public static final String MEDIA_UNKNOWN = "unknown";
+  }
+
+  public final class ExecutorCompat {
+    method public static java.util.concurrent.Executor create(android.os.Handler);
+  }
+
+  public final class HandlerCompat {
+    method public static android.os.Handler createAsync(android.os.Looper);
+    method public static android.os.Handler createAsync(android.os.Looper, android.os.Handler.Callback);
+    method public static boolean postDelayed(android.os.Handler, Runnable, Object?, long);
+  }
+
+  public final class LocaleListCompat {
+    method public static androidx.core.os.LocaleListCompat create(java.util.Locale!...);
+    method public static androidx.core.os.LocaleListCompat forLanguageTags(String?);
+    method public java.util.Locale! get(int);
+    method @Size(min=1) public static androidx.core.os.LocaleListCompat getAdjustedDefault();
+    method @Size(min=1) public static androidx.core.os.LocaleListCompat getDefault();
+    method public static androidx.core.os.LocaleListCompat getEmptyLocaleList();
+    method public java.util.Locale? getFirstMatch(String![]);
+    method @IntRange(from=0xffffffff) public int indexOf(java.util.Locale!);
+    method public boolean isEmpty();
+    method @IntRange(from=0) public int size();
+    method public String toLanguageTags();
+    method public Object? unwrap();
+    method @Deprecated @RequiresApi(24) public static androidx.core.os.LocaleListCompat! wrap(Object!);
+    method @RequiresApi(24) public static androidx.core.os.LocaleListCompat wrap(android.os.LocaleList);
+  }
+
+  public final class MessageCompat {
+    method public static boolean isAsynchronous(android.os.Message);
+    method public static void setAsynchronous(android.os.Message, boolean);
+  }
+
+  public class OperationCanceledException extends java.lang.RuntimeException {
+    ctor public OperationCanceledException();
+    ctor public OperationCanceledException(String?);
+  }
+
+  public final class ParcelCompat {
+    method public static boolean readBoolean(android.os.Parcel);
+    method public static void writeBoolean(android.os.Parcel, boolean);
+  }
+
+  @Deprecated public final class ParcelableCompat {
+    method @Deprecated public static <T> android.os.Parcelable.Creator<T!>! newCreator(androidx.core.os.ParcelableCompatCreatorCallbacks<T!>!);
+  }
+
+  @Deprecated public interface ParcelableCompatCreatorCallbacks<T> {
+    method @Deprecated public T! createFromParcel(android.os.Parcel!, ClassLoader!);
+    method @Deprecated public T![]! newArray(int);
+  }
+
+  public final class ProcessCompat {
+    method public static boolean isApplicationUid(int);
+  }
+
+  @Deprecated public final class TraceCompat {
+    method @Deprecated public static void beginAsyncSection(String, int);
+    method @Deprecated public static void beginSection(String);
+    method @Deprecated public static void endAsyncSection(String, int);
+    method @Deprecated public static void endSection();
+    method @Deprecated public static boolean isEnabled();
+    method @Deprecated public static void setCounter(String, int);
+  }
+
+  public class UserManagerCompat {
+    method public static boolean isUserUnlocked(android.content.Context);
+  }
+
+}
+
+package androidx.core.provider {
+
+  public final class FontRequest {
+    ctor public FontRequest(String, String, String, java.util.List<java.util.List<byte[]!>!>);
+    ctor public FontRequest(String, String, String, @ArrayRes int);
+    method public java.util.List<java.util.List<byte[]!>!>? getCertificates();
+    method @ArrayRes public int getCertificatesArrayResId();
+    method public String getProviderAuthority();
+    method public String getProviderPackage();
+    method public String getQuery();
+  }
+
+  public class FontsContractCompat {
+    method public static android.graphics.Typeface? buildTypeface(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![]);
+    method public static androidx.core.provider.FontsContractCompat.FontFamilyResult fetchFonts(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static void requestFont(android.content.Context, androidx.core.provider.FontRequest, androidx.core.provider.FontsContractCompat.FontRequestCallback, android.os.Handler);
+  }
+
+  public static final class FontsContractCompat.Columns implements android.provider.BaseColumns {
+    ctor public FontsContractCompat.Columns();
+    field public static final String FILE_ID = "file_id";
+    field public static final String ITALIC = "font_italic";
+    field public static final String RESULT_CODE = "result_code";
+    field public static final int RESULT_CODE_FONT_NOT_FOUND = 1; // 0x1
+    field public static final int RESULT_CODE_FONT_UNAVAILABLE = 2; // 0x2
+    field public static final int RESULT_CODE_MALFORMED_QUERY = 3; // 0x3
+    field public static final int RESULT_CODE_OK = 0; // 0x0
+    field public static final String TTC_INDEX = "font_ttc_index";
+    field public static final String VARIATION_SETTINGS = "font_variation_settings";
+    field public static final String WEIGHT = "font_weight";
+  }
+
+  public static class FontsContractCompat.FontFamilyResult {
+    method public androidx.core.provider.FontsContractCompat.FontInfo![]! getFonts();
+    method public int getStatusCode();
+    field public static final int STATUS_OK = 0; // 0x0
+    field public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; // 0x2
+    field public static final int STATUS_WRONG_CERTIFICATES = 1; // 0x1
+  }
+
+  public static class FontsContractCompat.FontInfo {
+    method public int getResultCode();
+    method @IntRange(from=0) public int getTtcIndex();
+    method public android.net.Uri getUri();
+    method @IntRange(from=1, to=1000) public int getWeight();
+    method public boolean isItalic();
+  }
+
+  public static class FontsContractCompat.FontRequestCallback {
+    ctor public FontsContractCompat.FontRequestCallback();
+    method public void onTypefaceRequestFailed(int);
+    method public void onTypefaceRetrieved(android.graphics.Typeface!);
+    field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
+    field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
+    field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
+    field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
+    field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
+    field public static final int FAIL_REASON_SECURITY_VIOLATION = -4; // 0xfffffffc
+    field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
+  }
+
+}
+
+package androidx.core.telephony.mbms {
+
+  public final class MbmsHelper {
+    method public static CharSequence? getBestNameForService(android.content.Context, android.telephony.mbms.ServiceInfo);
+  }
+
+}
+
+package androidx.core.text {
+
+  public final class BidiFormatter {
+    method public static androidx.core.text.BidiFormatter! getInstance();
+    method public static androidx.core.text.BidiFormatter! getInstance(boolean);
+    method public static androidx.core.text.BidiFormatter! getInstance(java.util.Locale!);
+    method public boolean getStereoReset();
+    method public boolean isRtl(String!);
+    method public boolean isRtl(CharSequence!);
+    method public boolean isRtlContext();
+    method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+    method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+    method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!);
+    method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!);
+    method public String! unicodeWrap(String!, boolean);
+    method public CharSequence! unicodeWrap(CharSequence!, boolean);
+    method public String! unicodeWrap(String!);
+    method public CharSequence! unicodeWrap(CharSequence!);
+  }
+
+  public static final class BidiFormatter.Builder {
+    ctor public BidiFormatter.Builder();
+    ctor public BidiFormatter.Builder(boolean);
+    ctor public BidiFormatter.Builder(java.util.Locale!);
+    method public androidx.core.text.BidiFormatter! build();
+    method public androidx.core.text.BidiFormatter.Builder! setTextDirectionHeuristic(androidx.core.text.TextDirectionHeuristicCompat!);
+    method public androidx.core.text.BidiFormatter.Builder! stereoReset(boolean);
+  }
+
+  public final class HtmlCompat {
+    method public static android.text.Spanned fromHtml(String, int);
+    method public static android.text.Spanned fromHtml(String, int, android.text.Html.ImageGetter?, android.text.Html.TagHandler?);
+    method public static String toHtml(android.text.Spanned, int);
+    field public static final int FROM_HTML_MODE_COMPACT = 63; // 0x3f
+    field public static final int FROM_HTML_MODE_LEGACY = 0; // 0x0
+    field public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256; // 0x100
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 32; // 0x20
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 16; // 0x10
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 2; // 0x2
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 8; // 0x8
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 4; // 0x4
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 1; // 0x1
+    field public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0; // 0x0
+    field public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1; // 0x1
+  }
+
+  public final class ICUCompat {
+    method public static String? maximizeAndGetScript(java.util.Locale!);
+  }
+
+  public class PrecomputedTextCompat implements android.text.Spannable {
+    method public char charAt(int);
+    method public static androidx.core.text.PrecomputedTextCompat! create(CharSequence, androidx.core.text.PrecomputedTextCompat.Params);
+    method @IntRange(from=0) public int getParagraphCount();
+    method @IntRange(from=0) public int getParagraphEnd(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getParagraphStart(@IntRange(from=0) int);
+    method public androidx.core.text.PrecomputedTextCompat.Params getParams();
+    method public int getSpanEnd(Object!);
+    method public int getSpanFlags(Object!);
+    method public int getSpanStart(Object!);
+    method public <T> T![]! getSpans(int, int, Class<T!>!);
+    method @UiThread public static java.util.concurrent.Future<androidx.core.text.PrecomputedTextCompat!>! getTextFuture(CharSequence, androidx.core.text.PrecomputedTextCompat.Params, java.util.concurrent.Executor?);
+    method public int length();
+    method public int nextSpanTransition(int, int, Class!);
+    method public void removeSpan(Object!);
+    method public void setSpan(Object!, int, int, int);
+    method public CharSequence! subSequence(int, int);
+  }
+
+  public static final class PrecomputedTextCompat.Params {
+    ctor @RequiresApi(28) public PrecomputedTextCompat.Params(android.text.PrecomputedText.Params);
+    method @RequiresApi(23) public int getBreakStrategy();
+    method @RequiresApi(23) public int getHyphenationFrequency();
+    method @RequiresApi(18) public android.text.TextDirectionHeuristic? getTextDirection();
+    method public android.text.TextPaint getTextPaint();
+  }
+
+  public static class PrecomputedTextCompat.Params.Builder {
+    ctor public PrecomputedTextCompat.Params.Builder(android.text.TextPaint);
+    method public androidx.core.text.PrecomputedTextCompat.Params build();
+    method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setBreakStrategy(int);
+    method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setHyphenationFrequency(int);
+    method @RequiresApi(18) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setTextDirection(android.text.TextDirectionHeuristic);
+  }
+
+  public interface TextDirectionHeuristicCompat {
+    method public boolean isRtl(char[]!, int, int);
+    method public boolean isRtl(CharSequence!, int, int);
+  }
+
+  public final class TextDirectionHeuristicsCompat {
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! ANYRTL_LTR;
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_LTR;
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_RTL;
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! LOCALE;
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! LTR;
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! RTL;
+  }
+
+  public final class TextUtilsCompat {
+    method public static int getLayoutDirectionFromLocale(java.util.Locale?);
+    method public static String htmlEncode(String);
+  }
+
+}
+
+package androidx.core.text.util {
+
+  public final class LinkifyCompat {
+    method public static boolean addLinks(android.text.Spannable, int);
+    method public static boolean addLinks(android.widget.TextView, int);
+    method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?);
+    method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+    method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+    method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?);
+    method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+    method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+  }
+
+}
+
+package androidx.core.util {
+
+  public class AtomicFile {
+    ctor public AtomicFile(java.io.File);
+    method public void delete();
+    method public void failWrite(java.io.FileOutputStream?);
+    method public void finishWrite(java.io.FileOutputStream?);
+    method public java.io.File getBaseFile();
+    method public java.io.FileInputStream openRead() throws java.io.FileNotFoundException;
+    method public byte[] readFully() throws java.io.IOException;
+    method public java.io.FileOutputStream startWrite() throws java.io.IOException;
+  }
+
+  public interface Consumer<T> {
+    method public void accept(T!);
+  }
+
+  public class ObjectsCompat {
+    method public static boolean equals(Object?, Object?);
+    method public static int hash(java.lang.Object!...);
+    method public static int hashCode(Object?);
+    method public static String? toString(Object?, String?);
+  }
+
+  public class Pair<F, S> {
+    ctor public Pair(F!, S!);
+    method public static <A, B> androidx.core.util.Pair<A!,B!> create(A!, B!);
+    field public final F! first;
+    field public final S! second;
+  }
+
+  public final class PatternsCompat {
+    field public static final java.util.regex.Pattern DOMAIN_NAME;
+    field public static final java.util.regex.Pattern EMAIL_ADDRESS;
+    field public static final java.util.regex.Pattern IP_ADDRESS;
+    field public static final java.util.regex.Pattern WEB_URL;
+  }
+
+  public final class Pools {
+  }
+
+  public static interface Pools.Pool<T> {
+    method public T? acquire();
+    method public boolean release(T);
+  }
+
+  public static class Pools.SimplePool<T> implements androidx.core.util.Pools.Pool<T> {
+    ctor public Pools.SimplePool(int);
+    method public T! acquire();
+    method public boolean release(T);
+  }
+
+  public static class Pools.SynchronizedPool<T> extends androidx.core.util.Pools.SimplePool<T> {
+    ctor public Pools.SynchronizedPool(int);
+  }
+
+  public interface Predicate<T> {
+    method public boolean test(T!);
+  }
+
+  public interface Supplier<T> {
+    method public T! get();
+  }
+
+}
+
+package androidx.core.view {
+
+  public class AccessibilityDelegateCompat {
+    ctor public AccessibilityDelegateCompat();
+    method public boolean dispatchPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public androidx.core.view.accessibility.AccessibilityNodeProviderCompat! getAccessibilityNodeProvider(android.view.View!);
+    method public void onInitializeAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public void onInitializeAccessibilityNodeInfo(android.view.View!, androidx.core.view.accessibility.AccessibilityNodeInfoCompat!);
+    method public void onPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public boolean performAccessibilityAction(android.view.View!, int, android.os.Bundle!);
+    method public void sendAccessibilityEvent(android.view.View!, int);
+    method public void sendAccessibilityEventUnchecked(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+  }
+
+  public abstract class ActionProvider {
+    ctor public ActionProvider(android.content.Context!);
+    method public android.content.Context! getContext();
+    method public boolean hasSubMenu();
+    method public boolean isVisible();
+    method public abstract android.view.View! onCreateActionView();
+    method public android.view.View! onCreateActionView(android.view.MenuItem!);
+    method public boolean onPerformDefaultAction();
+    method public void onPrepareSubMenu(android.view.SubMenu!);
+    method public boolean overridesItemVisibility();
+    method public void refreshVisibility();
+    method public void setVisibilityListener(androidx.core.view.ActionProvider.VisibilityListener!);
+  }
+
+  public static interface ActionProvider.VisibilityListener {
+    method public void onActionProviderVisibilityChanged(boolean);
+  }
+
+  public final class ContentInfoCompat {
+    method public android.content.ClipData getClip();
+    method public android.os.Bundle? getExtras();
+    method public int getFlags();
+    method public android.net.Uri? getLinkUri();
+    method public int getSource();
+    method public android.util.Pair<androidx.core.view.ContentInfoCompat!,androidx.core.view.ContentInfoCompat!> partition(androidx.core.util.Predicate<android.content.ClipData.Item!>);
+    field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
+    field public static final int SOURCE_APP = 0; // 0x0
+    field public static final int SOURCE_CLIPBOARD = 1; // 0x1
+    field public static final int SOURCE_DRAG_AND_DROP = 3; // 0x3
+    field public static final int SOURCE_INPUT_METHOD = 2; // 0x2
+  }
+
+  public static final class ContentInfoCompat.Builder {
+    ctor public ContentInfoCompat.Builder(androidx.core.view.ContentInfoCompat);
+    ctor public ContentInfoCompat.Builder(android.content.ClipData, int);
+    method public androidx.core.view.ContentInfoCompat build();
+    method public androidx.core.view.ContentInfoCompat.Builder setClip(android.content.ClipData);
+    method public androidx.core.view.ContentInfoCompat.Builder setExtras(android.os.Bundle?);
+    method public androidx.core.view.ContentInfoCompat.Builder setFlags(int);
+    method public androidx.core.view.ContentInfoCompat.Builder setLinkUri(android.net.Uri?);
+    method public androidx.core.view.ContentInfoCompat.Builder setSource(int);
+  }
+
+  public final class DisplayCompat {
+    method public static androidx.core.view.DisplayCompat.ModeCompat![] getSupportedModes(android.content.Context, android.view.Display);
+  }
+
+  public static final class DisplayCompat.ModeCompat {
+    method public int getPhysicalHeight();
+    method public int getPhysicalWidth();
+    method public boolean isNative();
+    method @RequiresApi(android.os.Build.VERSION_CODES.M) public android.view.Display.Mode? toMode();
+  }
+
+  public final class DisplayCutoutCompat {
+    ctor public DisplayCutoutCompat(android.graphics.Rect!, java.util.List<android.graphics.Rect!>!);
+    ctor public DisplayCutoutCompat(androidx.core.graphics.Insets, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, androidx.core.graphics.Insets);
+    method public java.util.List<android.graphics.Rect!> getBoundingRects();
+    method public int getSafeInsetBottom();
+    method public int getSafeInsetLeft();
+    method public int getSafeInsetRight();
+    method public int getSafeInsetTop();
+    method public androidx.core.graphics.Insets getWaterfallInsets();
+  }
+
+  public final class DragAndDropPermissionsCompat {
+    method public void release();
+  }
+
+  public class DragStartHelper {
+    ctor public DragStartHelper(android.view.View!, androidx.core.view.DragStartHelper.OnDragStartListener!);
+    method public void attach();
+    method public void detach();
+    method public void getTouchPosition(android.graphics.Point!);
+    method public boolean onLongClick(android.view.View!);
+    method public boolean onTouch(android.view.View!, android.view.MotionEvent!);
+  }
+
+  public static interface DragStartHelper.OnDragStartListener {
+    method public boolean onDragStart(android.view.View!, androidx.core.view.DragStartHelper!);
+  }
+
+  public final class GestureDetectorCompat {
+    ctor public GestureDetectorCompat(android.content.Context!, android.view.GestureDetector.OnGestureListener!);
+    ctor public GestureDetectorCompat(android.content.Context!, android.view.GestureDetector.OnGestureListener!, android.os.Handler!);
+    method public boolean isLongpressEnabled();
+    method public boolean onTouchEvent(android.view.MotionEvent!);
+    method public void setIsLongpressEnabled(boolean);
+    method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener!);
+  }
+
+  public final class GravityCompat {
+    method public static void apply(int, int, int, android.graphics.Rect!, android.graphics.Rect!, int);
+    method public static void apply(int, int, int, android.graphics.Rect!, int, int, android.graphics.Rect!, int);
+    method public static void applyDisplay(int, android.graphics.Rect!, android.graphics.Rect!, int);
+    method public static int getAbsoluteGravity(int, int);
+    field public static final int END = 8388613; // 0x800005
+    field public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = 8388615; // 0x800007
+    field public static final int RELATIVE_LAYOUT_DIRECTION = 8388608; // 0x800000
+    field public static final int START = 8388611; // 0x800003
+  }
+
+  public final class InputDeviceCompat {
+    field public static final int SOURCE_ANY = -256; // 0xffffff00
+    field public static final int SOURCE_CLASS_BUTTON = 1; // 0x1
+    field public static final int SOURCE_CLASS_JOYSTICK = 16; // 0x10
+    field public static final int SOURCE_CLASS_MASK = 255; // 0xff
+    field public static final int SOURCE_CLASS_NONE = 0; // 0x0
+    field public static final int SOURCE_CLASS_POINTER = 2; // 0x2
+    field public static final int SOURCE_CLASS_POSITION = 8; // 0x8
+    field public static final int SOURCE_CLASS_TRACKBALL = 4; // 0x4
+    field public static final int SOURCE_DPAD = 513; // 0x201
+    field public static final int SOURCE_GAMEPAD = 1025; // 0x401
+    field public static final int SOURCE_HDMI = 33554433; // 0x2000001
+    field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
+    field public static final int SOURCE_KEYBOARD = 257; // 0x101
+    field public static final int SOURCE_MOUSE = 8194; // 0x2002
+    field public static final int SOURCE_ROTARY_ENCODER = 4194304; // 0x400000
+    field public static final int SOURCE_STYLUS = 16386; // 0x4002
+    field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
+    field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
+    field public static final int SOURCE_TOUCH_NAVIGATION = 2097152; // 0x200000
+    field public static final int SOURCE_TRACKBALL = 65540; // 0x10004
+    field public static final int SOURCE_UNKNOWN = 0; // 0x0
+  }
+
+  public final class LayoutInflaterCompat {
+    method @Deprecated public static androidx.core.view.LayoutInflaterFactory! getFactory(android.view.LayoutInflater!);
+    method @Deprecated public static void setFactory(android.view.LayoutInflater, androidx.core.view.LayoutInflaterFactory);
+    method public static void setFactory2(android.view.LayoutInflater, android.view.LayoutInflater.Factory2);
+  }
+
+  @Deprecated public interface LayoutInflaterFactory {
+    method @Deprecated public android.view.View! onCreateView(android.view.View!, String!, android.content.Context!, android.util.AttributeSet!);
+  }
+
+  public final class MarginLayoutParamsCompat {
+    method public static int getLayoutDirection(android.view.ViewGroup.MarginLayoutParams!);
+    method public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams!);
+    method public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams!);
+    method public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams!);
+    method public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams!, int);
+    method public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams!, int);
+    method public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams!, int);
+    method public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams!, int);
+  }
+
+  public final class MenuCompat {
+    method public static void setGroupDividerEnabled(android.view.Menu!, boolean);
+    method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+  }
+
+  public final class MenuItemCompat {
+    method @Deprecated public static boolean collapseActionView(android.view.MenuItem!);
+    method @Deprecated public static boolean expandActionView(android.view.MenuItem!);
+    method public static androidx.core.view.ActionProvider! getActionProvider(android.view.MenuItem!);
+    method @Deprecated public static android.view.View! getActionView(android.view.MenuItem!);
+    method public static int getAlphabeticModifiers(android.view.MenuItem!);
+    method public static CharSequence! getContentDescription(android.view.MenuItem!);
+    method public static android.content.res.ColorStateList! getIconTintList(android.view.MenuItem!);
+    method public static android.graphics.PorterDuff.Mode! getIconTintMode(android.view.MenuItem!);
+    method public static int getNumericModifiers(android.view.MenuItem!);
+    method public static CharSequence! getTooltipText(android.view.MenuItem!);
+    method @Deprecated public static boolean isActionViewExpanded(android.view.MenuItem!);
+    method public static android.view.MenuItem! setActionProvider(android.view.MenuItem!, androidx.core.view.ActionProvider!);
+    method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, android.view.View!);
+    method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, int);
+    method public static void setAlphabeticShortcut(android.view.MenuItem!, char, int);
+    method public static void setContentDescription(android.view.MenuItem!, CharSequence!);
+    method public static void setIconTintList(android.view.MenuItem!, android.content.res.ColorStateList!);
+    method public static void setIconTintMode(android.view.MenuItem!, android.graphics.PorterDuff.Mode!);
+    method public static void setNumericShortcut(android.view.MenuItem!, char, int);
+    method @Deprecated public static android.view.MenuItem! setOnActionExpandListener(android.view.MenuItem!, androidx.core.view.MenuItemCompat.OnActionExpandListener!);
+    method public static void setShortcut(android.view.MenuItem!, char, char, int, int);
+    method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+    method public static void setTooltipText(android.view.MenuItem!, CharSequence!);
+    field @Deprecated public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+    field @Deprecated public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+    field @Deprecated public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+    field @Deprecated public static final int SHOW_AS_ACTION_NEVER = 0; // 0x0
+    field @Deprecated public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+  }
+
+  @Deprecated public static interface MenuItemCompat.OnActionExpandListener {
+    method @Deprecated public boolean onMenuItemActionCollapse(android.view.MenuItem!);
+    method @Deprecated public boolean onMenuItemActionExpand(android.view.MenuItem!);
+  }
+
+  public final class MotionEventCompat {
+    method @Deprecated public static int findPointerIndex(android.view.MotionEvent!, int);
+    method @Deprecated public static int getActionIndex(android.view.MotionEvent!);
+    method @Deprecated public static int getActionMasked(android.view.MotionEvent!);
+    method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int);
+    method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int, int);
+    method @Deprecated public static int getButtonState(android.view.MotionEvent!);
+    method @Deprecated public static int getPointerCount(android.view.MotionEvent!);
+    method @Deprecated public static int getPointerId(android.view.MotionEvent!, int);
+    method @Deprecated public static int getSource(android.view.MotionEvent!);
+    method @Deprecated public static float getX(android.view.MotionEvent!, int);
+    method @Deprecated public static float getY(android.view.MotionEvent!, int);
+    method public static boolean isFromSource(android.view.MotionEvent!, int);
+    field @Deprecated public static final int ACTION_HOVER_ENTER = 9; // 0x9
+    field @Deprecated public static final int ACTION_HOVER_EXIT = 10; // 0xa
+    field @Deprecated public static final int ACTION_HOVER_MOVE = 7; // 0x7
+    field @Deprecated public static final int ACTION_MASK = 255; // 0xff
+    field @Deprecated public static final int ACTION_POINTER_DOWN = 5; // 0x5
+    field @Deprecated public static final int ACTION_POINTER_INDEX_MASK = 65280; // 0xff00
+    field @Deprecated public static final int ACTION_POINTER_INDEX_SHIFT = 8; // 0x8
+    field @Deprecated public static final int ACTION_POINTER_UP = 6; // 0x6
+    field @Deprecated public static final int ACTION_SCROLL = 8; // 0x8
+    field @Deprecated public static final int AXIS_BRAKE = 23; // 0x17
+    field @Deprecated public static final int AXIS_DISTANCE = 24; // 0x18
+    field @Deprecated public static final int AXIS_GAS = 22; // 0x16
+    field @Deprecated public static final int AXIS_GENERIC_1 = 32; // 0x20
+    field @Deprecated public static final int AXIS_GENERIC_10 = 41; // 0x29
+    field @Deprecated public static final int AXIS_GENERIC_11 = 42; // 0x2a
+    field @Deprecated public static final int AXIS_GENERIC_12 = 43; // 0x2b
+    field @Deprecated public static final int AXIS_GENERIC_13 = 44; // 0x2c
+    field @Deprecated public static final int AXIS_GENERIC_14 = 45; // 0x2d
+    field @Deprecated public static final int AXIS_GENERIC_15 = 46; // 0x2e
+    field @Deprecated public static final int AXIS_GENERIC_16 = 47; // 0x2f
+    field @Deprecated public static final int AXIS_GENERIC_2 = 33; // 0x21
+    field @Deprecated public static final int AXIS_GENERIC_3 = 34; // 0x22
+    field @Deprecated public static final int AXIS_GENERIC_4 = 35; // 0x23
+    field @Deprecated public static final int AXIS_GENERIC_5 = 36; // 0x24
+    field @Deprecated public static final int AXIS_GENERIC_6 = 37; // 0x25
+    field @Deprecated public static final int AXIS_GENERIC_7 = 38; // 0x26
+    field @Deprecated public static final int AXIS_GENERIC_8 = 39; // 0x27
+    field @Deprecated public static final int AXIS_GENERIC_9 = 40; // 0x28
+    field @Deprecated public static final int AXIS_HAT_X = 15; // 0xf
+    field @Deprecated public static final int AXIS_HAT_Y = 16; // 0x10
+    field @Deprecated public static final int AXIS_HSCROLL = 10; // 0xa
+    field @Deprecated public static final int AXIS_LTRIGGER = 17; // 0x11
+    field @Deprecated public static final int AXIS_ORIENTATION = 8; // 0x8
+    field @Deprecated public static final int AXIS_PRESSURE = 2; // 0x2
+    field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+    field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
+    field @Deprecated public static final int AXIS_RTRIGGER = 18; // 0x12
+    field @Deprecated public static final int AXIS_RUDDER = 20; // 0x14
+    field @Deprecated public static final int AXIS_RX = 12; // 0xc
+    field @Deprecated public static final int AXIS_RY = 13; // 0xd
+    field @Deprecated public static final int AXIS_RZ = 14; // 0xe
+    field public static final int AXIS_SCROLL = 26; // 0x1a
+    field @Deprecated public static final int AXIS_SIZE = 3; // 0x3
+    field @Deprecated public static final int AXIS_THROTTLE = 19; // 0x13
+    field @Deprecated public static final int AXIS_TILT = 25; // 0x19
+    field @Deprecated public static final int AXIS_TOOL_MAJOR = 6; // 0x6
+    field @Deprecated public static final int AXIS_TOOL_MINOR = 7; // 0x7
+    field @Deprecated public static final int AXIS_TOUCH_MAJOR = 4; // 0x4
+    field @Deprecated public static final int AXIS_TOUCH_MINOR = 5; // 0x5
+    field @Deprecated public static final int AXIS_VSCROLL = 9; // 0x9
+    field @Deprecated public static final int AXIS_WHEEL = 21; // 0x15
+    field @Deprecated public static final int AXIS_X = 0; // 0x0
+    field @Deprecated public static final int AXIS_Y = 1; // 0x1
+    field @Deprecated public static final int AXIS_Z = 11; // 0xb
+    field @Deprecated public static final int BUTTON_PRIMARY = 1; // 0x1
+  }
+
+  public interface NestedScrollingChild {
+    method public boolean dispatchNestedFling(float, float, boolean);
+    method public boolean dispatchNestedPreFling(float, float);
+    method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+    method public boolean hasNestedScrollingParent();
+    method public boolean isNestedScrollingEnabled();
+    method public void setNestedScrollingEnabled(boolean);
+    method public boolean startNestedScroll(int);
+    method public void stopNestedScroll();
+  }
+
+  public interface NestedScrollingChild2 extends androidx.core.view.NestedScrollingChild {
+    method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, int);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]?, int);
+    method public boolean hasNestedScrollingParent(int);
+    method public boolean startNestedScroll(int, int);
+    method public void stopNestedScroll(int);
+  }
+
+  public interface NestedScrollingChild3 extends androidx.core.view.NestedScrollingChild2 {
+    method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]);
+  }
+
+  public class NestedScrollingChildHelper {
+    ctor public NestedScrollingChildHelper(android.view.View);
+    method public boolean dispatchNestedFling(float, float, boolean);
+    method public boolean dispatchNestedPreFling(float, float);
+    method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+    method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, int);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]?, int);
+    method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]?);
+    method public boolean hasNestedScrollingParent();
+    method public boolean hasNestedScrollingParent(int);
+    method public boolean isNestedScrollingEnabled();
+    method public void onDetachedFromWindow();
+    method public void onStopNestedScroll(android.view.View);
+    method public void setNestedScrollingEnabled(boolean);
+    method public boolean startNestedScroll(int);
+    method public boolean startNestedScroll(int, int);
+    method public void stopNestedScroll();
+    method public void stopNestedScroll(int);
+  }
+
+  public interface NestedScrollingParent {
+    method public int getNestedScrollAxes();
+    method public boolean onNestedFling(android.view.View, float, float, boolean);
+    method public boolean onNestedPreFling(android.view.View, float, float);
+    method public void onNestedPreScroll(android.view.View, int, int, int[]);
+    method public void onNestedScroll(android.view.View, int, int, int, int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+    method public boolean onStartNestedScroll(android.view.View, android.view.View, int);
+    method public void onStopNestedScroll(android.view.View);
+  }
+
+  public interface NestedScrollingParent2 extends androidx.core.view.NestedScrollingParent {
+    method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+    method public void onNestedScroll(android.view.View, int, int, int, int, int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+    method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+    method public void onStopNestedScroll(android.view.View, int);
+  }
+
+  public interface NestedScrollingParent3 extends androidx.core.view.NestedScrollingParent2 {
+    method public void onNestedScroll(android.view.View, int, int, int, int, int, int[]);
+  }
+
+  public class NestedScrollingParentHelper {
+    ctor public NestedScrollingParentHelper(android.view.ViewGroup);
+    method public int getNestedScrollAxes();
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+    method public void onStopNestedScroll(android.view.View);
+    method public void onStopNestedScroll(android.view.View, int);
+  }
+
+  public interface OnApplyWindowInsetsListener {
+    method public androidx.core.view.WindowInsetsCompat! onApplyWindowInsets(android.view.View!, androidx.core.view.WindowInsetsCompat!);
+  }
+
+  public interface OnReceiveContentListener {
+    method public androidx.core.view.ContentInfoCompat? onReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+  }
+
+  public interface OnReceiveContentViewBehavior {
+    method public androidx.core.view.ContentInfoCompat? onReceiveContent(androidx.core.view.ContentInfoCompat);
+  }
+
+  public final class OneShotPreDrawListener implements android.view.View.OnAttachStateChangeListener android.view.ViewTreeObserver.OnPreDrawListener {
+    method public static androidx.core.view.OneShotPreDrawListener add(android.view.View, Runnable);
+    method public boolean onPreDraw();
+    method public void onViewAttachedToWindow(android.view.View!);
+    method public void onViewDetachedFromWindow(android.view.View!);
+    method public void removeListener();
+  }
+
+  public final class PointerIconCompat {
+    method public static androidx.core.view.PointerIconCompat! create(android.graphics.Bitmap!, float, float);
+    method public static androidx.core.view.PointerIconCompat! getSystemIcon(android.content.Context!, int);
+    method public static androidx.core.view.PointerIconCompat! load(android.content.res.Resources!, int);
+    field public static final int TYPE_ALIAS = 1010; // 0x3f2
+    field public static final int TYPE_ALL_SCROLL = 1013; // 0x3f5
+    field public static final int TYPE_ARROW = 1000; // 0x3e8
+    field public static final int TYPE_CELL = 1006; // 0x3ee
+    field public static final int TYPE_CONTEXT_MENU = 1001; // 0x3e9
+    field public static final int TYPE_COPY = 1011; // 0x3f3
+    field public static final int TYPE_CROSSHAIR = 1007; // 0x3ef
+    field public static final int TYPE_DEFAULT = 1000; // 0x3e8
+    field public static final int TYPE_GRAB = 1020; // 0x3fc
+    field public static final int TYPE_GRABBING = 1021; // 0x3fd
+    field public static final int TYPE_HAND = 1002; // 0x3ea
+    field public static final int TYPE_HELP = 1003; // 0x3eb
+    field public static final int TYPE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6
+    field public static final int TYPE_NO_DROP = 1012; // 0x3f4
+    field public static final int TYPE_NULL = 0; // 0x0
+    field public static final int TYPE_TEXT = 1008; // 0x3f0
+    field public static final int TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9
+    field public static final int TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8
+    field public static final int TYPE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7
+    field public static final int TYPE_VERTICAL_TEXT = 1009; // 0x3f1
+    field public static final int TYPE_WAIT = 1004; // 0x3ec
+    field public static final int TYPE_ZOOM_IN = 1018; // 0x3fa
+    field public static final int TYPE_ZOOM_OUT = 1019; // 0x3fb
+  }
+
+  public final class ScaleGestureDetectorCompat {
+    method @Deprecated public static boolean isQuickScaleEnabled(Object!);
+    method public static boolean isQuickScaleEnabled(android.view.ScaleGestureDetector!);
+    method @Deprecated public static void setQuickScaleEnabled(Object!, boolean);
+    method public static void setQuickScaleEnabled(android.view.ScaleGestureDetector!, boolean);
+  }
+
+  public interface ScrollingView {
+    method public int computeHorizontalScrollExtent();
+    method public int computeHorizontalScrollOffset();
+    method public int computeHorizontalScrollRange();
+    method public int computeVerticalScrollExtent();
+    method public int computeVerticalScrollOffset();
+    method public int computeVerticalScrollRange();
+  }
+
+  public interface TintableBackgroundView {
+    method public android.content.res.ColorStateList? getSupportBackgroundTintList();
+    method public android.graphics.PorterDuff.Mode? getSupportBackgroundTintMode();
+    method public void setSupportBackgroundTintList(android.content.res.ColorStateList?);
+    method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode?);
+  }
+
+  @Deprecated public final class VelocityTrackerCompat {
+    method @Deprecated public static float getXVelocity(android.view.VelocityTracker!, int);
+    method @Deprecated public static float getYVelocity(android.view.VelocityTracker!, int);
+  }
+
+  public class ViewCompat {
+    ctor @Deprecated protected ViewCompat();
+    method public static int addAccessibilityAction(android.view.View, CharSequence, androidx.core.view.accessibility.AccessibilityViewCommand);
+    method public static void addKeyboardNavigationClusters(android.view.View, java.util.Collection<android.view.View!>, int);
+    method public static void addOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+    method public static androidx.core.view.ViewPropertyAnimatorCompat animate(android.view.View);
+    method @Deprecated public static boolean canScrollHorizontally(android.view.View!, int);
+    method @Deprecated public static boolean canScrollVertically(android.view.View!, int);
+    method public static void cancelDragAndDrop(android.view.View);
+    method @Deprecated public static int combineMeasuredStates(int, int);
+    method public static androidx.core.view.WindowInsetsCompat computeSystemWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat, android.graphics.Rect);
+    method public static androidx.core.view.WindowInsetsCompat dispatchApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+    method public static void dispatchFinishTemporaryDetach(android.view.View);
+    method public static boolean dispatchNestedFling(android.view.View, float, float, boolean);
+    method public static boolean dispatchNestedPreFling(android.view.View, float, float);
+    method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?);
+    method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?, int);
+    method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?);
+    method public static void dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, int, int[]);
+    method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, int);
+    method public static void dispatchStartTemporaryDetach(android.view.View);
+    method public static void enableAccessibleClickableSpanSupport(android.view.View!);
+    method public static int generateViewId();
+    method public static androidx.core.view.AccessibilityDelegateCompat? getAccessibilityDelegate(android.view.View);
+    method public static int getAccessibilityLiveRegion(android.view.View);
+    method public static androidx.core.view.accessibility.AccessibilityNodeProviderCompat! getAccessibilityNodeProvider(android.view.View);
+    method @UiThread public static CharSequence! getAccessibilityPaneTitle(android.view.View!);
+    method @Deprecated public static float getAlpha(android.view.View!);
+    method public static android.content.res.ColorStateList! getBackgroundTintList(android.view.View);
+    method public static android.graphics.PorterDuff.Mode! getBackgroundTintMode(android.view.View);
+    method public static android.graphics.Rect? getClipBounds(android.view.View);
+    method public static android.view.Display? getDisplay(android.view.View);
+    method public static float getElevation(android.view.View);
+    method public static boolean getFitsSystemWindows(android.view.View);
+    method public static int getImportantForAccessibility(android.view.View);
+    method public static int getImportantForAutofill(android.view.View);
+    method public static int getLabelFor(android.view.View);
+    method @Deprecated public static int getLayerType(android.view.View!);
+    method public static int getLayoutDirection(android.view.View);
+    method @Deprecated public static android.graphics.Matrix? getMatrix(android.view.View!);
+    method @Deprecated public static int getMeasuredHeightAndState(android.view.View!);
+    method @Deprecated public static int getMeasuredState(android.view.View!);
+    method @Deprecated public static int getMeasuredWidthAndState(android.view.View!);
+    method public static int getMinimumHeight(android.view.View);
+    method public static int getMinimumWidth(android.view.View);
+    method public static int getNextClusterForwardId(android.view.View);
+    method public static String![]? getOnReceiveContentMimeTypes(android.view.View);
+    method @Deprecated public static int getOverScrollMode(android.view.View!);
+    method @Px public static int getPaddingEnd(android.view.View);
+    method @Px public static int getPaddingStart(android.view.View);
+    method public static android.view.ViewParent! getParentForAccessibility(android.view.View);
+    method @Deprecated public static float getPivotX(android.view.View!);
+    method @Deprecated public static float getPivotY(android.view.View!);
+    method public static androidx.core.view.WindowInsetsCompat? getRootWindowInsets(android.view.View);
+    method @Deprecated public static float getRotation(android.view.View!);
+    method @Deprecated public static float getRotationX(android.view.View!);
+    method @Deprecated public static float getRotationY(android.view.View!);
+    method @Deprecated public static float getScaleX(android.view.View!);
+    method @Deprecated public static float getScaleY(android.view.View!);
+    method public static int getScrollIndicators(android.view.View);
+    method @UiThread public static final CharSequence? getStateDescription(android.view.View);
+    method public static java.util.List<android.graphics.Rect!> getSystemGestureExclusionRects(android.view.View);
+    method public static String? getTransitionName(android.view.View);
+    method @Deprecated public static float getTranslationX(android.view.View!);
+    method @Deprecated public static float getTranslationY(android.view.View!);
+    method public static float getTranslationZ(android.view.View);
+    method public static androidx.core.view.WindowInsetsControllerCompat? getWindowInsetsController(android.view.View);
+    method public static int getWindowSystemUiVisibility(android.view.View);
+    method @Deprecated public static float getX(android.view.View!);
+    method @Deprecated public static float getY(android.view.View!);
+    method public static float getZ(android.view.View);
+    method public static boolean hasAccessibilityDelegate(android.view.View);
+    method public static boolean hasExplicitFocusable(android.view.View);
+    method public static boolean hasNestedScrollingParent(android.view.View);
+    method public static boolean hasNestedScrollingParent(android.view.View, int);
+    method public static boolean hasOnClickListeners(android.view.View);
+    method public static boolean hasOverlappingRendering(android.view.View);
+    method public static boolean hasTransientState(android.view.View);
+    method @UiThread public static boolean isAccessibilityHeading(android.view.View!);
+    method public static boolean isAttachedToWindow(android.view.View);
+    method public static boolean isFocusedByDefault(android.view.View);
+    method public static boolean isImportantForAccessibility(android.view.View);
+    method public static boolean isImportantForAutofill(android.view.View);
+    method public static boolean isInLayout(android.view.View);
+    method public static boolean isKeyboardNavigationCluster(android.view.View);
+    method public static boolean isLaidOut(android.view.View);
+    method public static boolean isLayoutDirectionResolved(android.view.View);
+    method public static boolean isNestedScrollingEnabled(android.view.View);
+    method @Deprecated public static boolean isOpaque(android.view.View!);
+    method public static boolean isPaddingRelative(android.view.View);
+    method @UiThread public static boolean isScreenReaderFocusable(android.view.View!);
+    method @Deprecated public static void jumpDrawablesToCurrentState(android.view.View!);
+    method public static android.view.View! keyboardNavigationClusterSearch(android.view.View, android.view.View!, int);
+    method public static void offsetLeftAndRight(android.view.View, int);
+    method public static void offsetTopAndBottom(android.view.View, int);
+    method public static androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+    method @Deprecated public static void onInitializeAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public static void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat!);
+    method @Deprecated public static void onPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle!);
+    method public static androidx.core.view.ContentInfoCompat? performReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+    method public static void postInvalidateOnAnimation(android.view.View);
+    method public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
+    method public static void postOnAnimation(android.view.View, Runnable!);
+    method public static void postOnAnimationDelayed(android.view.View, Runnable!, long);
+    method public static void removeAccessibilityAction(android.view.View, int);
+    method public static void removeOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+    method public static void replaceAccessibilityAction(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat, CharSequence?, androidx.core.view.accessibility.AccessibilityViewCommand?);
+    method public static void requestApplyInsets(android.view.View);
+    method public static <T extends android.view.View> T requireViewById(android.view.View, @IdRes int);
+    method @Deprecated public static int resolveSizeAndState(int, int, int);
+    method public static boolean restoreDefaultFocus(android.view.View);
+    method public static void saveAttributeDataForStyleable(android.view.View, android.content.Context, int[], android.util.AttributeSet?, android.content.res.TypedArray, int, int);
+    method public static void setAccessibilityDelegate(android.view.View, androidx.core.view.AccessibilityDelegateCompat!);
+    method @UiThread public static void setAccessibilityHeading(android.view.View!, boolean);
+    method public static void setAccessibilityLiveRegion(android.view.View, int);
+    method @UiThread public static void setAccessibilityPaneTitle(android.view.View!, CharSequence!);
+    method @Deprecated public static void setActivated(android.view.View!, boolean);
+    method @Deprecated public static void setAlpha(android.view.View!, @FloatRange(from=0.0, to=1.0) float);
+    method public static void setAutofillHints(android.view.View, java.lang.String!...);
+    method public static void setBackground(android.view.View, android.graphics.drawable.Drawable?);
+    method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList!);
+    method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode!);
+    method @Deprecated public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup!, boolean);
+    method public static void setClipBounds(android.view.View, android.graphics.Rect!);
+    method public static void setElevation(android.view.View, float);
+    method @Deprecated public static void setFitsSystemWindows(android.view.View!, boolean);
+    method public static void setFocusedByDefault(android.view.View, boolean);
+    method public static void setHasTransientState(android.view.View, boolean);
+    method public static void setImportantForAccessibility(android.view.View, int);
+    method public static void setImportantForAutofill(android.view.View, int);
+    method public static void setKeyboardNavigationCluster(android.view.View, boolean);
+    method public static void setLabelFor(android.view.View, @IdRes int);
+    method public static void setLayerPaint(android.view.View, android.graphics.Paint!);
+    method @Deprecated public static void setLayerType(android.view.View!, int, android.graphics.Paint!);
+    method public static void setLayoutDirection(android.view.View, int);
+    method public static void setNestedScrollingEnabled(android.view.View, boolean);
+    method public static void setNextClusterForwardId(android.view.View, int);
+    method public static void setOnApplyWindowInsetsListener(android.view.View, androidx.core.view.OnApplyWindowInsetsListener?);
+    method public static void setOnReceiveContentListener(android.view.View, String![]?, androidx.core.view.OnReceiveContentListener?);
+    method @Deprecated public static void setOverScrollMode(android.view.View!, int);
+    method public static void setPaddingRelative(android.view.View, @Px int, @Px int, @Px int, @Px int);
+    method @Deprecated public static void setPivotX(android.view.View!, float);
+    method @Deprecated public static void setPivotY(android.view.View!, float);
+    method public static void setPointerIcon(android.view.View, androidx.core.view.PointerIconCompat!);
+    method @Deprecated public static void setRotation(android.view.View!, float);
+    method @Deprecated public static void setRotationX(android.view.View!, float);
+    method @Deprecated public static void setRotationY(android.view.View!, float);
+    method @Deprecated public static void setSaveFromParentEnabled(android.view.View!, boolean);
+    method @Deprecated public static void setScaleX(android.view.View!, float);
+    method @Deprecated public static void setScaleY(android.view.View!, float);
+    method @UiThread public static void setScreenReaderFocusable(android.view.View!, boolean);
+    method public static void setScrollIndicators(android.view.View, int);
+    method public static void setScrollIndicators(android.view.View, int, int);
+    method @UiThread public static void setStateDescription(android.view.View, CharSequence?);
+    method public static void setSystemGestureExclusionRects(android.view.View, java.util.List<android.graphics.Rect!>);
+    method public static void setTooltipText(android.view.View, CharSequence?);
+    method public static void setTransitionName(android.view.View, String!);
+    method @Deprecated public static void setTranslationX(android.view.View!, float);
+    method @Deprecated public static void setTranslationY(android.view.View!, float);
+    method public static void setTranslationZ(android.view.View, float);
+    method public static void setWindowInsetsAnimationCallback(android.view.View, androidx.core.view.WindowInsetsAnimationCompat.Callback?);
+    method @Deprecated public static void setX(android.view.View!, float);
+    method @Deprecated public static void setY(android.view.View!, float);
+    method public static void setZ(android.view.View, float);
+    method public static boolean startDragAndDrop(android.view.View, android.content.ClipData!, android.view.View.DragShadowBuilder!, Object!, int);
+    method public static boolean startNestedScroll(android.view.View, int);
+    method public static boolean startNestedScroll(android.view.View, int, int);
+    method public static void stopNestedScroll(android.view.View);
+    method public static void stopNestedScroll(android.view.View, int);
+    method public static void updateDragShadow(android.view.View, android.view.View.DragShadowBuilder!);
+    field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
+    field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
+    field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0; // 0x0
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
+    field @Deprecated public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
+    field @Deprecated public static final int LAYER_TYPE_NONE = 0; // 0x0
+    field @Deprecated public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
+    field public static final int LAYOUT_DIRECTION_INHERIT = 2; // 0x2
+    field public static final int LAYOUT_DIRECTION_LOCALE = 3; // 0x3
+    field public static final int LAYOUT_DIRECTION_LTR = 0; // 0x0
+    field public static final int LAYOUT_DIRECTION_RTL = 1; // 0x1
+    field @Deprecated public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
+    field @Deprecated public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
+    field @Deprecated public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
+    field @Deprecated public static final int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+    field @Deprecated public static final int OVER_SCROLL_ALWAYS = 0; // 0x0
+    field @Deprecated public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
+    field @Deprecated public static final int OVER_SCROLL_NEVER = 2; // 0x2
+    field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
+    field public static final int SCROLL_AXIS_NONE = 0; // 0x0
+    field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+    field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
+    field public static final int SCROLL_INDICATOR_END = 32; // 0x20
+    field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
+    field public static final int SCROLL_INDICATOR_RIGHT = 8; // 0x8
+    field public static final int SCROLL_INDICATOR_START = 16; // 0x10
+    field public static final int SCROLL_INDICATOR_TOP = 1; // 0x1
+    field public static final int TYPE_NON_TOUCH = 1; // 0x1
+    field public static final int TYPE_TOUCH = 0; // 0x0
+  }
+
+  public static interface ViewCompat.OnUnhandledKeyEventListenerCompat {
+    method public boolean onUnhandledKeyEvent(android.view.View!, android.view.KeyEvent!);
+  }
+
+  public final class ViewConfigurationCompat {
+    method public static float getScaledHorizontalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+    method public static int getScaledHoverSlop(android.view.ViewConfiguration!);
+    method @Deprecated public static int getScaledPagingTouchSlop(android.view.ViewConfiguration!);
+    method public static float getScaledVerticalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+    method @Deprecated public static boolean hasPermanentMenuKey(android.view.ViewConfiguration!);
+    method public static boolean shouldShowMenuShortcutsWhenKeyboardPresent(android.view.ViewConfiguration!, android.content.Context);
+  }
+
+  public final class ViewGroupCompat {
+    method public static int getLayoutMode(android.view.ViewGroup);
+    method public static int getNestedScrollAxes(android.view.ViewGroup);
+    method public static boolean isTransitionGroup(android.view.ViewGroup);
+    method @Deprecated public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public static void setLayoutMode(android.view.ViewGroup, int);
+    method @Deprecated public static void setMotionEventSplittingEnabled(android.view.ViewGroup!, boolean);
+    method public static void setTransitionGroup(android.view.ViewGroup, boolean);
+    field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
+    field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
+  }
+
+  public final class ViewParentCompat {
+    method public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent!, android.view.View!, android.view.View!, int);
+    method public static boolean onNestedFling(android.view.ViewParent!, android.view.View!, float, float, boolean);
+    method public static boolean onNestedPreFling(android.view.ViewParent!, android.view.View!, float, float);
+    method public static void onNestedPreScroll(android.view.ViewParent!, android.view.View!, int, int, int[]!);
+    method public static void onNestedPreScroll(android.view.ViewParent!, android.view.View!, int, int, int[]!, int);
+    method public static void onNestedScroll(android.view.ViewParent!, android.view.View!, int, int, int, int);
+    method public static void onNestedScroll(android.view.ViewParent!, android.view.View!, int, int, int, int, int);
+    method public static void onNestedScroll(android.view.ViewParent!, android.view.View!, int, int, int, int, int, int[]);
+    method public static void onNestedScrollAccepted(android.view.ViewParent!, android.view.View!, android.view.View!, int);
+    method public static void onNestedScrollAccepted(android.view.ViewParent!, android.view.View!, android.view.View!, int, int);
+    method public static boolean onStartNestedScroll(android.view.ViewParent!, android.view.View!, android.view.View!, int);
+    method public static boolean onStartNestedScroll(android.view.ViewParent!, android.view.View!, android.view.View!, int, int);
+    method public static void onStopNestedScroll(android.view.ViewParent!, android.view.View!);
+    method public static void onStopNestedScroll(android.view.ViewParent!, android.view.View!, int);
+    method @Deprecated public static boolean requestSendAccessibilityEvent(android.view.ViewParent!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+  }
+
+  public final class ViewPropertyAnimatorCompat {
+    method public androidx.core.view.ViewPropertyAnimatorCompat! alpha(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! alphaBy(float);
+    method public void cancel();
+    method public long getDuration();
+    method public android.view.animation.Interpolator! getInterpolator();
+    method public long getStartDelay();
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotation(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotationBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotationX(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotationXBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotationY(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotationYBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! scaleX(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! scaleXBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! scaleY(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! scaleYBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! setDuration(long);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! setInterpolator(android.view.animation.Interpolator!);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! setListener(androidx.core.view.ViewPropertyAnimatorListener!);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! setStartDelay(long);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! setUpdateListener(androidx.core.view.ViewPropertyAnimatorUpdateListener!);
+    method public void start();
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationX(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationXBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationY(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationYBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationZ(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationZBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! withEndAction(Runnable!);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! withLayer();
+    method public androidx.core.view.ViewPropertyAnimatorCompat! withStartAction(Runnable!);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! x(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! xBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! y(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! yBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! z(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! zBy(float);
+  }
+
+  public interface ViewPropertyAnimatorListener {
+    method public void onAnimationCancel(android.view.View!);
+    method public void onAnimationEnd(android.view.View!);
+    method public void onAnimationStart(android.view.View!);
+  }
+
+  public class ViewPropertyAnimatorListenerAdapter implements androidx.core.view.ViewPropertyAnimatorListener {
+    ctor public ViewPropertyAnimatorListenerAdapter();
+    method public void onAnimationCancel(android.view.View!);
+    method public void onAnimationEnd(android.view.View!);
+    method public void onAnimationStart(android.view.View!);
+  }
+
+  public interface ViewPropertyAnimatorUpdateListener {
+    method public void onAnimationUpdate(android.view.View!);
+  }
+
+  public final class WindowCompat {
+    method public static androidx.core.view.WindowInsetsControllerCompat? getInsetsController(android.view.Window, android.view.View);
+    method public static <T extends android.view.View> T requireViewById(android.view.Window, @IdRes int);
+    method public static void setDecorFitsSystemWindows(android.view.Window, boolean);
+    field public static final int FEATURE_ACTION_BAR = 8; // 0x8
+    field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
+    field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+  }
+
+  public final class WindowInsetsAnimationCompat {
+    ctor public WindowInsetsAnimationCompat(int, android.view.animation.Interpolator?, long);
+    method @FloatRange(from=0.0f, to=1.0f) public float getAlpha();
+    method public long getDurationMillis();
+    method @FloatRange(from=0.0f, to=1.0f) public float getFraction();
+    method public float getInterpolatedFraction();
+    method public android.view.animation.Interpolator? getInterpolator();
+    method public int getTypeMask();
+    method public void setAlpha(@FloatRange(from=0.0f, to=1.0f) float);
+    method public void setFraction(@FloatRange(from=0.0f, to=1.0f) float);
+  }
+
+  public static final class WindowInsetsAnimationCompat.BoundsCompat {
+    ctor public WindowInsetsAnimationCompat.BoundsCompat(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+    method public androidx.core.graphics.Insets getLowerBound();
+    method public androidx.core.graphics.Insets getUpperBound();
+    method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat inset(androidx.core.graphics.Insets);
+    method @RequiresApi(30) public android.view.WindowInsetsAnimation.Bounds toBounds();
+    method @RequiresApi(30) public static androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat toBoundsCompat(android.view.WindowInsetsAnimation.Bounds);
+  }
+
+  public abstract static class WindowInsetsAnimationCompat.Callback {
+    ctor public WindowInsetsAnimationCompat.Callback(int);
+    method public final int getDispatchMode();
+    method public void onEnd(androidx.core.view.WindowInsetsAnimationCompat);
+    method public void onPrepare(androidx.core.view.WindowInsetsAnimationCompat);
+    method public abstract androidx.core.view.WindowInsetsCompat onProgress(androidx.core.view.WindowInsetsCompat, java.util.List<androidx.core.view.WindowInsetsAnimationCompat!>);
+    method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat onStart(androidx.core.view.WindowInsetsAnimationCompat, androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat);
+    field public static final int DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1; // 0x1
+    field public static final int DISPATCH_MODE_STOP = 0; // 0x0
+  }
+
+  public interface WindowInsetsAnimationControlListenerCompat {
+    method public void onCancelled(androidx.core.view.WindowInsetsAnimationControllerCompat?);
+    method public void onFinished(androidx.core.view.WindowInsetsAnimationControllerCompat);
+    method public void onReady(androidx.core.view.WindowInsetsAnimationControllerCompat, int);
+  }
+
+  public final class WindowInsetsAnimationControllerCompat {
+    method public void finish(boolean);
+    method public float getCurrentAlpha();
+    method @FloatRange(from=0.0f, to=1.0f) public float getCurrentFraction();
+    method public androidx.core.graphics.Insets getCurrentInsets();
+    method public androidx.core.graphics.Insets getHiddenStateInsets();
+    method public androidx.core.graphics.Insets getShownStateInsets();
+    method public int getTypes();
+    method public boolean isCancelled();
+    method public boolean isFinished();
+    method public boolean isReady();
+    method public void setInsetsAndAlpha(androidx.core.graphics.Insets?, @FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float);
+  }
+
+  public class WindowInsetsCompat {
+    ctor public WindowInsetsCompat(androidx.core.view.WindowInsetsCompat?);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat consumeDisplayCutout();
+    method @Deprecated public androidx.core.view.WindowInsetsCompat consumeStableInsets();
+    method @Deprecated public androidx.core.view.WindowInsetsCompat consumeSystemWindowInsets();
+    method public androidx.core.view.DisplayCutoutCompat? getDisplayCutout();
+    method public androidx.core.graphics.Insets getInsets(int);
+    method public androidx.core.graphics.Insets getInsetsIgnoringVisibility(int);
+    method @Deprecated public androidx.core.graphics.Insets getMandatorySystemGestureInsets();
+    method @Deprecated public int getStableInsetBottom();
+    method @Deprecated public int getStableInsetLeft();
+    method @Deprecated public int getStableInsetRight();
+    method @Deprecated public int getStableInsetTop();
+    method @Deprecated public androidx.core.graphics.Insets getStableInsets();
+    method @Deprecated public androidx.core.graphics.Insets getSystemGestureInsets();
+    method @Deprecated public int getSystemWindowInsetBottom();
+    method @Deprecated public int getSystemWindowInsetLeft();
+    method @Deprecated public int getSystemWindowInsetRight();
+    method @Deprecated public int getSystemWindowInsetTop();
+    method @Deprecated public androidx.core.graphics.Insets getSystemWindowInsets();
+    method @Deprecated public androidx.core.graphics.Insets getTappableElementInsets();
+    method public boolean hasInsets();
+    method @Deprecated public boolean hasStableInsets();
+    method @Deprecated public boolean hasSystemWindowInsets();
+    method public androidx.core.view.WindowInsetsCompat inset(androidx.core.graphics.Insets);
+    method public androidx.core.view.WindowInsetsCompat inset(@IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+    method public boolean isConsumed();
+    method public boolean isRound();
+    method public boolean isVisible(int);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(int, int, int, int);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(android.graphics.Rect);
+    method @RequiresApi(20) public android.view.WindowInsets? toWindowInsets();
+    method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets);
+    method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets, android.view.View?);
+    field public static final androidx.core.view.WindowInsetsCompat CONSUMED;
+  }
+
+  public static final class WindowInsetsCompat.Builder {
+    ctor public WindowInsetsCompat.Builder();
+    ctor public WindowInsetsCompat.Builder(androidx.core.view.WindowInsetsCompat);
+    method public androidx.core.view.WindowInsetsCompat build();
+    method public androidx.core.view.WindowInsetsCompat.Builder setDisplayCutout(androidx.core.view.DisplayCutoutCompat?);
+    method public androidx.core.view.WindowInsetsCompat.Builder setInsets(int, androidx.core.graphics.Insets);
+    method public androidx.core.view.WindowInsetsCompat.Builder setInsetsIgnoringVisibility(int, androidx.core.graphics.Insets);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setMandatorySystemGestureInsets(androidx.core.graphics.Insets);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setStableInsets(androidx.core.graphics.Insets);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemGestureInsets(androidx.core.graphics.Insets);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemWindowInsets(androidx.core.graphics.Insets);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setTappableElementInsets(androidx.core.graphics.Insets);
+    method public androidx.core.view.WindowInsetsCompat.Builder setVisible(int, boolean);
+  }
+
+  public static final class WindowInsetsCompat.Type {
+    method public static int captionBar();
+    method public static int displayCutout();
+    method public static int ime();
+    method public static int mandatorySystemGestures();
+    method public static int navigationBars();
+    method public static int statusBars();
+    method public static int systemBars();
+    method public static int systemGestures();
+    method public static int tappableElement();
+  }
+
+  public final class WindowInsetsControllerCompat {
+    ctor public WindowInsetsControllerCompat(android.view.Window, android.view.View);
+    method public void addOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+    method public void controlWindowInsetsAnimation(int, long, android.view.animation.Interpolator?, android.os.CancellationSignal?, androidx.core.view.WindowInsetsAnimationControlListenerCompat);
+    method public int getSystemBarsBehavior();
+    method public void hide(int);
+    method public boolean isAppearanceLightNavigationBars();
+    method public boolean isAppearanceLightStatusBars();
+    method public void removeOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+    method public void setAppearanceLightNavigationBars(boolean);
+    method public void setAppearanceLightStatusBars(boolean);
+    method public void setSystemBarsBehavior(int);
+    method public void show(int);
+    method @RequiresApi(30) public static androidx.core.view.WindowInsetsControllerCompat toWindowInsetsControllerCompat(android.view.WindowInsetsController);
+    field public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
+    field public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0; // 0x0
+    field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2
+  }
+
+  public static interface WindowInsetsControllerCompat.OnControllableInsetsChangedListener {
+    method public void onControllableInsetsChanged(androidx.core.view.WindowInsetsControllerCompat, int);
+  }
+
+}
+
+package androidx.core.view.accessibility {
+
+  public final class AccessibilityClickableSpanCompat extends android.text.style.ClickableSpan {
+    method public void onClick(android.view.View);
+  }
+
+  public final class AccessibilityEventCompat {
+    method @Deprecated public static void appendRecord(android.view.accessibility.AccessibilityEvent!, androidx.core.view.accessibility.AccessibilityRecordCompat!);
+    method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! asRecord(android.view.accessibility.AccessibilityEvent!);
+    method public static int getAction(android.view.accessibility.AccessibilityEvent!);
+    method public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent!);
+    method public static int getMovementGranularity(android.view.accessibility.AccessibilityEvent!);
+    method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! getRecord(android.view.accessibility.AccessibilityEvent!, int);
+    method @Deprecated public static int getRecordCount(android.view.accessibility.AccessibilityEvent!);
+    method public static void setAction(android.view.accessibility.AccessibilityEvent!, int);
+    method public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent!, int);
+    method public static void setMovementGranularity(android.view.accessibility.AccessibilityEvent!, int);
+    field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+    field public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 16; // 0x10
+    field public static final int CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 32; // 0x20
+    field public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 8; // 0x8
+    field public static final int CONTENT_CHANGE_TYPE_STATE_DESCRIPTION = 64; // 0x40
+    field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
+    field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
+    field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
+    field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
+    field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
+    field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000
+    field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000
+    field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000
+    field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
+    field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
+    field public static final int TYPE_TOUCH_INTERACTION_END = 2097152; // 0x200000
+    field public static final int TYPE_TOUCH_INTERACTION_START = 1048576; // 0x100000
+    field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 32768; // 0x8000
+    field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 65536; // 0x10000
+    field public static final int TYPE_VIEW_CONTEXT_CLICKED = 8388608; // 0x800000
+    field @Deprecated public static final int TYPE_VIEW_HOVER_ENTER = 128; // 0x80
+    field @Deprecated public static final int TYPE_VIEW_HOVER_EXIT = 256; // 0x100
+    field @Deprecated public static final int TYPE_VIEW_SCROLLED = 4096; // 0x1000
+    field @Deprecated public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192; // 0x2000
+    field public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072; // 0x20000
+    field public static final int TYPE_WINDOWS_CHANGED = 4194304; // 0x400000
+    field @Deprecated public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
+  }
+
+  public final class AccessibilityManagerCompat {
+    method @Deprecated public static boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+    method public static boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener!);
+    method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!, int);
+    method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!);
+    method @Deprecated public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager!);
+    method @Deprecated public static boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+    method public static boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener!);
+  }
+
+  @Deprecated public static interface AccessibilityManagerCompat.AccessibilityStateChangeListener {
+    method @Deprecated public void onAccessibilityStateChanged(boolean);
+  }
+
+  @Deprecated public abstract static class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat implements androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener {
+    ctor @Deprecated public AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat();
+  }
+
+  public static interface AccessibilityManagerCompat.TouchExplorationStateChangeListener {
+    method public void onTouchExplorationStateChanged(boolean);
+  }
+
+  public class AccessibilityNodeInfoCompat {
+    ctor @Deprecated public AccessibilityNodeInfoCompat(Object!);
+    method public void addAction(int);
+    method public void addAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+    method public void addChild(android.view.View!);
+    method public void addChild(android.view.View!, int);
+    method public boolean canOpenPopup();
+    method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByText(String!);
+    method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByViewId(String!);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! findFocus(int);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! focusSearch(int);
+    method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!>! getActionList();
+    method public int getActions();
+    method @Deprecated public void getBoundsInParent(android.graphics.Rect!);
+    method public void getBoundsInScreen(android.graphics.Rect!);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getChild(int);
+    method public int getChildCount();
+    method public CharSequence! getClassName();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! getCollectionInfo();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! getCollectionItemInfo();
+    method public CharSequence! getContentDescription();
+    method public int getDrawingOrder();
+    method public CharSequence! getError();
+    method public android.os.Bundle! getExtras();
+    method public CharSequence? getHintText();
+    method @Deprecated public Object! getInfo();
+    method public int getInputType();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabelFor();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabeledBy();
+    method public int getLiveRegion();
+    method public int getMaxTextLength();
+    method public int getMovementGranularities();
+    method public CharSequence! getPackageName();
+    method public CharSequence? getPaneTitle();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getParent();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! getRangeInfo();
+    method public CharSequence? getRoleDescription();
+    method public CharSequence? getStateDescription();
+    method public CharSequence! getText();
+    method public int getTextSelectionEnd();
+    method public int getTextSelectionStart();
+    method public CharSequence? getTooltipText();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat? getTouchDelegateInfo();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalAfter();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalBefore();
+    method public String! getViewIdResourceName();
+    method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat! getWindow();
+    method public int getWindowId();
+    method public boolean isAccessibilityFocused();
+    method public boolean isCheckable();
+    method public boolean isChecked();
+    method public boolean isClickable();
+    method public boolean isContentInvalid();
+    method public boolean isContextClickable();
+    method public boolean isDismissable();
+    method public boolean isEditable();
+    method public boolean isEnabled();
+    method public boolean isFocusable();
+    method public boolean isFocused();
+    method public boolean isHeading();
+    method public boolean isImportantForAccessibility();
+    method public boolean isLongClickable();
+    method public boolean isMultiLine();
+    method public boolean isPassword();
+    method public boolean isScreenReaderFocusable();
+    method public boolean isScrollable();
+    method public boolean isSelected();
+    method public boolean isShowingHintText();
+    method public boolean isTextEntryKey();
+    method public boolean isVisibleToUser();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!);
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!, int);
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(androidx.core.view.accessibility.AccessibilityNodeInfoCompat!);
+    method public boolean performAction(int);
+    method public boolean performAction(int, android.os.Bundle!);
+    method public void recycle();
+    method public boolean refresh();
+    method public boolean removeAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+    method public boolean removeChild(android.view.View!);
+    method public boolean removeChild(android.view.View!, int);
+    method public void setAccessibilityFocused(boolean);
+    method @Deprecated public void setBoundsInParent(android.graphics.Rect!);
+    method public void setBoundsInScreen(android.graphics.Rect!);
+    method public void setCanOpenPopup(boolean);
+    method public void setCheckable(boolean);
+    method public void setChecked(boolean);
+    method public void setClassName(CharSequence!);
+    method public void setClickable(boolean);
+    method public void setCollectionInfo(Object!);
+    method public void setCollectionItemInfo(Object!);
+    method public void setContentDescription(CharSequence!);
+    method public void setContentInvalid(boolean);
+    method public void setContextClickable(boolean);
+    method public void setDismissable(boolean);
+    method public void setDrawingOrder(int);
+    method public void setEditable(boolean);
+    method public void setEnabled(boolean);
+    method public void setError(CharSequence!);
+    method public void setFocusable(boolean);
+    method public void setFocused(boolean);
+    method public void setHeading(boolean);
+    method public void setHintText(CharSequence?);
+    method public void setImportantForAccessibility(boolean);
+    method public void setInputType(int);
+    method public void setLabelFor(android.view.View!);
+    method public void setLabelFor(android.view.View!, int);
+    method public void setLabeledBy(android.view.View!);
+    method public void setLabeledBy(android.view.View!, int);
+    method public void setLiveRegion(int);
+    method public void setLongClickable(boolean);
+    method public void setMaxTextLength(int);
+    method public void setMovementGranularities(int);
+    method public void setMultiLine(boolean);
+    method public void setPackageName(CharSequence!);
+    method public void setPaneTitle(CharSequence?);
+    method public void setParent(android.view.View!);
+    method public void setParent(android.view.View!, int);
+    method public void setPassword(boolean);
+    method public void setRangeInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat!);
+    method public void setRoleDescription(CharSequence?);
+    method public void setScreenReaderFocusable(boolean);
+    method public void setScrollable(boolean);
+    method public void setSelected(boolean);
+    method public void setShowingHintText(boolean);
+    method public void setSource(android.view.View!);
+    method public void setSource(android.view.View!, int);
+    method public void setStateDescription(CharSequence?);
+    method public void setText(CharSequence!);
+    method public void setTextEntryKey(boolean);
+    method public void setTextSelection(int, int);
+    method public void setTooltipText(CharSequence?);
+    method public void setTouchDelegateInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat);
+    method public void setTraversalAfter(android.view.View!);
+    method public void setTraversalAfter(android.view.View!, int);
+    method public void setTraversalBefore(android.view.View!);
+    method public void setTraversalBefore(android.view.View!, int);
+    method public void setViewIdResourceName(String!);
+    method public void setVisibleToUser(boolean);
+    method public android.view.accessibility.AccessibilityNodeInfo! unwrap();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! wrap(android.view.accessibility.AccessibilityNodeInfo);
+    field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
+    field public static final String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
+    field public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
+    field public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
+    field public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
+    field public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = "ACTION_ARGUMENT_MOVE_WINDOW_X";
+    field public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = "ACTION_ARGUMENT_MOVE_WINDOW_Y";
+    field public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT = "android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT";
+    field public static final String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
+    field public static final String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
+    field public static final String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
+    field public static final String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
+    field public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
+    field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
+    field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
+    field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
+    field public static final int ACTION_CLICK = 16; // 0x10
+    field public static final int ACTION_COLLAPSE = 524288; // 0x80000
+    field public static final int ACTION_COPY = 16384; // 0x4000
+    field public static final int ACTION_CUT = 65536; // 0x10000
+    field public static final int ACTION_DISMISS = 1048576; // 0x100000
+    field public static final int ACTION_EXPAND = 262144; // 0x40000
+    field public static final int ACTION_FOCUS = 1; // 0x1
+    field public static final int ACTION_LONG_CLICK = 32; // 0x20
+    field public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 256; // 0x100
+    field public static final int ACTION_NEXT_HTML_ELEMENT = 1024; // 0x400
+    field public static final int ACTION_PASTE = 32768; // 0x8000
+    field public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 512; // 0x200
+    field public static final int ACTION_PREVIOUS_HTML_ELEMENT = 2048; // 0x800
+    field public static final int ACTION_SCROLL_BACKWARD = 8192; // 0x2000
+    field public static final int ACTION_SCROLL_FORWARD = 4096; // 0x1000
+    field public static final int ACTION_SELECT = 4; // 0x4
+    field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
+    field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
+    field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
+    field public static final int FOCUS_INPUT = 1; // 0x1
+    field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
+    field public static final int MOVEMENT_GRANULARITY_LINE = 4; // 0x4
+    field public static final int MOVEMENT_GRANULARITY_PAGE = 16; // 0x10
+    field public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 8; // 0x8
+    field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
+  }
+
+  public static class AccessibilityNodeInfoCompat.AccessibilityActionCompat {
+    ctor public AccessibilityNodeInfoCompat.AccessibilityActionCompat(int, CharSequence!);
+    method public int getId();
+    method public CharSequence! getLabel();
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_ACCESSIBILITY_FOCUS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_FOCUS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_SELECTION;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLICK;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COLLAPSE;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CONTEXT_CLICK;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COPY;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CUT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_DISMISS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_EXPAND;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_FOCUS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_HIDE_TOOLTIP;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_IME_ENTER;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_LONG_CLICK;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_MOVE_WINDOW;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_HTML_ELEMENT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_DOWN;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_LEFT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_RIGHT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_UP;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PASTE;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PRESS_AND_HOLD;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_HTML_ELEMENT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_BACKWARD;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_DOWN;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_FORWARD;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_LEFT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_RIGHT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_TO_POSITION;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_UP;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SELECT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_PROGRESS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_SELECTION;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_TEXT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_ON_SCREEN;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_TOOLTIP;
+  }
+
+  public static class AccessibilityNodeInfoCompat.CollectionInfoCompat {
+    method public int getColumnCount();
+    method public int getRowCount();
+    method public int getSelectionMode();
+    method public boolean isHierarchical();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean, int);
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean);
+    field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
+    field public static final int SELECTION_MODE_NONE = 0; // 0x0
+    field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
+  }
+
+  public static class AccessibilityNodeInfoCompat.CollectionItemInfoCompat {
+    method public int getColumnIndex();
+    method public int getColumnSpan();
+    method public int getRowIndex();
+    method public int getRowSpan();
+    method @Deprecated public boolean isHeading();
+    method public boolean isSelected();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean, boolean);
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean);
+  }
+
+  public static class AccessibilityNodeInfoCompat.RangeInfoCompat {
+    method public float getCurrent();
+    method public float getMax();
+    method public float getMin();
+    method public int getType();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! obtain(int, float, float, float);
+    field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
+    field public static final int RANGE_TYPE_INT = 0; // 0x0
+    field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
+  }
+
+  public static final class AccessibilityNodeInfoCompat.TouchDelegateInfoCompat {
+    ctor public AccessibilityNodeInfoCompat.TouchDelegateInfoCompat(java.util.Map<android.graphics.Region!,android.view.View!>);
+    method public android.graphics.Region? getRegionAt(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getRegionCount();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getTargetForRegion(android.graphics.Region);
+  }
+
+  public class AccessibilityNodeProviderCompat {
+    ctor public AccessibilityNodeProviderCompat();
+    ctor public AccessibilityNodeProviderCompat(Object!);
+    method public void addExtraDataToAccessibilityNodeInfo(int, androidx.core.view.accessibility.AccessibilityNodeInfoCompat, String, android.os.Bundle?);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? createAccessibilityNodeInfo(int);
+    method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>? findAccessibilityNodeInfosByText(String!, int);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? findFocus(int);
+    method public Object! getProvider();
+    method public boolean performAction(int, int, android.os.Bundle!);
+    field public static final int HOST_VIEW_ID = -1; // 0xffffffff
+  }
+
+  public class AccessibilityRecordCompat {
+    ctor @Deprecated public AccessibilityRecordCompat(Object!);
+    method @Deprecated public boolean equals(Object?);
+    method @Deprecated public int getAddedCount();
+    method @Deprecated public CharSequence! getBeforeText();
+    method @Deprecated public CharSequence! getClassName();
+    method @Deprecated public CharSequence! getContentDescription();
+    method @Deprecated public int getCurrentItemIndex();
+    method @Deprecated public int getFromIndex();
+    method @Deprecated public Object! getImpl();
+    method @Deprecated public int getItemCount();
+    method @Deprecated public int getMaxScrollX();
+    method public static int getMaxScrollX(android.view.accessibility.AccessibilityRecord!);
+    method @Deprecated public int getMaxScrollY();
+    method public static int getMaxScrollY(android.view.accessibility.AccessibilityRecord!);
+    method @Deprecated public android.os.Parcelable! getParcelableData();
+    method @Deprecated public int getRemovedCount();
+    method @Deprecated public int getScrollX();
+    method @Deprecated public int getScrollY();
+    method @Deprecated public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getSource();
+    method @Deprecated public java.util.List<java.lang.CharSequence!>! getText();
+    method @Deprecated public int getToIndex();
+    method @Deprecated public int getWindowId();
+    method @Deprecated public int hashCode();
+    method @Deprecated public boolean isChecked();
+    method @Deprecated public boolean isEnabled();
+    method @Deprecated public boolean isFullScreen();
+    method @Deprecated public boolean isPassword();
+    method @Deprecated public boolean isScrollable();
+    method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain(androidx.core.view.accessibility.AccessibilityRecordCompat!);
+    method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain();
+    method @Deprecated public void recycle();
+    method @Deprecated public void setAddedCount(int);
+    method @Deprecated public void setBeforeText(CharSequence!);
+    method @Deprecated public void setChecked(boolean);
+    method @Deprecated public void setClassName(CharSequence!);
+    method @Deprecated public void setContentDescription(CharSequence!);
+    method @Deprecated public void setCurrentItemIndex(int);
+    method @Deprecated public void setEnabled(boolean);
+    method @Deprecated public void setFromIndex(int);
+    method @Deprecated public void setFullScreen(boolean);
+    method @Deprecated public void setItemCount(int);
+    method @Deprecated public void setMaxScrollX(int);
+    method public static void setMaxScrollX(android.view.accessibility.AccessibilityRecord!, int);
+    method @Deprecated public void setMaxScrollY(int);
+    method public static void setMaxScrollY(android.view.accessibility.AccessibilityRecord!, int);
+    method @Deprecated public void setParcelableData(android.os.Parcelable!);
+    method @Deprecated public void setPassword(boolean);
+    method @Deprecated public void setRemovedCount(int);
+    method @Deprecated public void setScrollX(int);
+    method @Deprecated public void setScrollY(int);
+    method @Deprecated public void setScrollable(boolean);
+    method @Deprecated public void setSource(android.view.View!);
+    method @Deprecated public void setSource(android.view.View!, int);
+    method public static void setSource(android.view.accessibility.AccessibilityRecord, android.view.View!, int);
+    method @Deprecated public void setToIndex(int);
+  }
+
+  public interface AccessibilityViewCommand {
+    method public boolean perform(android.view.View, androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments?);
+  }
+
+  public abstract static class AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.CommandArguments();
+  }
+
+  public static final class AccessibilityViewCommand.MoveAtGranularityArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.MoveAtGranularityArguments();
+    method public boolean getExtendSelection();
+    method public int getGranularity();
+  }
+
+  public static final class AccessibilityViewCommand.MoveHtmlArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.MoveHtmlArguments();
+    method public String! getHTMLElement();
+  }
+
+  public static final class AccessibilityViewCommand.MoveWindowArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.MoveWindowArguments();
+    method public int getX();
+    method public int getY();
+  }
+
+  public static final class AccessibilityViewCommand.ScrollToPositionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.ScrollToPositionArguments();
+    method public int getColumn();
+    method public int getRow();
+  }
+
+  public static final class AccessibilityViewCommand.SetProgressArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.SetProgressArguments();
+    method public float getProgress();
+  }
+
+  public static final class AccessibilityViewCommand.SetSelectionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.SetSelectionArguments();
+    method public int getEnd();
+    method public int getStart();
+  }
+
+  public static final class AccessibilityViewCommand.SetTextArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.SetTextArguments();
+    method public CharSequence! getText();
+  }
+
+  public class AccessibilityWindowInfoCompat {
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getAnchor();
+    method public void getBoundsInScreen(android.graphics.Rect!);
+    method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat! getChild(int);
+    method public int getChildCount();
+    method public int getId();
+    method public int getLayer();
+    method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat! getParent();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getRoot();
+    method public CharSequence! getTitle();
+    method public int getType();
+    method public boolean isAccessibilityFocused();
+    method public boolean isActive();
+    method public boolean isFocused();
+    method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat! obtain();
+    method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat! obtain(androidx.core.view.accessibility.AccessibilityWindowInfoCompat!);
+    method public void recycle();
+    field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
+    field public static final int TYPE_APPLICATION = 1; // 0x1
+    field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+    field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
+    field public static final int TYPE_SYSTEM = 3; // 0x3
+  }
+
+}
+
+package androidx.core.view.animation {
+
+  public final class PathInterpolatorCompat {
+    method public static android.view.animation.Interpolator! create(android.graphics.Path!);
+    method public static android.view.animation.Interpolator! create(float, float);
+    method public static android.view.animation.Interpolator! create(float, float, float, float);
+  }
+
+}
+
+package androidx.core.view.inputmethod {
+
+  public final class EditorInfoCompat {
+    ctor @Deprecated public EditorInfoCompat();
+    method public static String![] getContentMimeTypes(android.view.inputmethod.EditorInfo!);
+    method public static CharSequence? getInitialSelectedText(android.view.inputmethod.EditorInfo, int);
+    method public static CharSequence? getInitialTextAfterCursor(android.view.inputmethod.EditorInfo, int, int);
+    method public static CharSequence? getInitialTextBeforeCursor(android.view.inputmethod.EditorInfo, int, int);
+    method public static void setContentMimeTypes(android.view.inputmethod.EditorInfo, String![]?);
+    method public static void setInitialSurroundingSubText(android.view.inputmethod.EditorInfo, CharSequence, int);
+    method public static void setInitialSurroundingText(android.view.inputmethod.EditorInfo, CharSequence);
+    field public static final int IME_FLAG_FORCE_ASCII = -2147483648; // 0x80000000
+    field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
+  }
+
+  public final class InputConnectionCompat {
+    ctor @Deprecated public InputConnectionCompat();
+    method public static boolean commitContent(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
+    method public static android.view.inputmethod.InputConnection createWrapper(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputConnectionCompat.OnCommitContentListener);
+    field public static final int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 1; // 0x1
+  }
+
+  public static interface InputConnectionCompat.OnCommitContentListener {
+    method public boolean onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat!, int, android.os.Bundle!);
+  }
+
+  public final class InputContentInfoCompat {
+    ctor public InputContentInfoCompat(android.net.Uri, android.content.ClipDescription, android.net.Uri?);
+    method public android.net.Uri getContentUri();
+    method public android.content.ClipDescription getDescription();
+    method public android.net.Uri? getLinkUri();
+    method public void releasePermission();
+    method public void requestPermission();
+    method public Object? unwrap();
+    method public static androidx.core.view.inputmethod.InputContentInfoCompat? wrap(Object?);
+  }
+
+}
+
+package androidx.core.widget {
+
+  public abstract class AutoScrollHelper implements android.view.View.OnTouchListener {
+    ctor public AutoScrollHelper(android.view.View);
+    method public abstract boolean canTargetScrollHorizontally(int);
+    method public abstract boolean canTargetScrollVertically(int);
+    method public boolean isEnabled();
+    method public boolean isExclusive();
+    method public boolean onTouch(android.view.View!, android.view.MotionEvent!);
+    method public abstract void scrollTargetBy(int, int);
+    method public androidx.core.widget.AutoScrollHelper setActivationDelay(int);
+    method public androidx.core.widget.AutoScrollHelper setEdgeType(int);
+    method public androidx.core.widget.AutoScrollHelper! setEnabled(boolean);
+    method public androidx.core.widget.AutoScrollHelper! setExclusive(boolean);
+    method public androidx.core.widget.AutoScrollHelper setMaximumEdges(float, float);
+    method public androidx.core.widget.AutoScrollHelper setMaximumVelocity(float, float);
+    method public androidx.core.widget.AutoScrollHelper setMinimumVelocity(float, float);
+    method public androidx.core.widget.AutoScrollHelper setRampDownDuration(int);
+    method public androidx.core.widget.AutoScrollHelper setRampUpDuration(int);
+    method public androidx.core.widget.AutoScrollHelper setRelativeEdges(float, float);
+    method public androidx.core.widget.AutoScrollHelper setRelativeVelocity(float, float);
+    field public static final int EDGE_TYPE_INSIDE = 0; // 0x0
+    field public static final int EDGE_TYPE_INSIDE_EXTEND = 1; // 0x1
+    field public static final int EDGE_TYPE_OUTSIDE = 2; // 0x2
+    field public static final float NO_MAX = 3.4028235E38f;
+    field public static final float NO_MIN = 0.0f;
+    field public static final float RELATIVE_UNSPECIFIED = 0.0f;
+  }
+
+  public final class CompoundButtonCompat {
+    method public static android.graphics.drawable.Drawable? getButtonDrawable(android.widget.CompoundButton);
+    method public static android.content.res.ColorStateList? getButtonTintList(android.widget.CompoundButton);
+    method public static android.graphics.PorterDuff.Mode? getButtonTintMode(android.widget.CompoundButton);
+    method public static void setButtonTintList(android.widget.CompoundButton, android.content.res.ColorStateList?);
+    method public static void setButtonTintMode(android.widget.CompoundButton, android.graphics.PorterDuff.Mode?);
+  }
+
+  public class ContentLoadingProgressBar extends android.widget.ProgressBar {
+    ctor public ContentLoadingProgressBar(android.content.Context);
+    ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet?);
+    method public void hide();
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public void show();
+  }
+
+  public final class EdgeEffectCompat {
+    ctor @Deprecated public EdgeEffectCompat(android.content.Context!);
+    method @Deprecated public boolean draw(android.graphics.Canvas!);
+    method @Deprecated public void finish();
+    method @Deprecated public boolean isFinished();
+    method @Deprecated public boolean onAbsorb(int);
+    method @Deprecated public boolean onPull(float);
+    method @Deprecated public boolean onPull(float, float);
+    method public static void onPull(android.widget.EdgeEffect, float, float);
+    method @Deprecated public boolean onRelease();
+    method @Deprecated public void setSize(int, int);
+  }
+
+  public class ImageViewCompat {
+    method public static android.content.res.ColorStateList? getImageTintList(android.widget.ImageView);
+    method public static android.graphics.PorterDuff.Mode? getImageTintMode(android.widget.ImageView);
+    method public static void setImageTintList(android.widget.ImageView, android.content.res.ColorStateList?);
+    method public static void setImageTintMode(android.widget.ImageView, android.graphics.PorterDuff.Mode?);
+  }
+
+  public final class ListPopupWindowCompat {
+    method @Deprecated public static android.view.View.OnTouchListener! createDragToOpenListener(Object!, android.view.View!);
+    method public static android.view.View.OnTouchListener? createDragToOpenListener(android.widget.ListPopupWindow, android.view.View);
+  }
+
+  public class ListViewAutoScrollHelper extends androidx.core.widget.AutoScrollHelper {
+    ctor public ListViewAutoScrollHelper(android.widget.ListView);
+    method public boolean canTargetScrollHorizontally(int);
+    method public boolean canTargetScrollVertically(int);
+    method public void scrollTargetBy(int, int);
+  }
+
+  public final class ListViewCompat {
+    method public static boolean canScrollList(android.widget.ListView, int);
+    method public static void scrollListBy(android.widget.ListView, int);
+  }
+
+  public class NestedScrollView extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingChild3 androidx.core.view.NestedScrollingParent3 androidx.core.view.ScrollingView {
+    ctor public NestedScrollView(android.content.Context);
+    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?);
+    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?, int);
+    method public boolean arrowScroll(int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollExtent();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollOffset();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollRange();
+    method protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollExtent();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollOffset();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollRange();
+    method public boolean dispatchNestedPreScroll(int, int, int[]!, int[]!, int);
+    method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]!, int);
+    method public boolean executeKeyEvent(android.view.KeyEvent);
+    method public void fling(int);
+    method public boolean fullScroll(int);
+    method public int getMaxScrollAmount();
+    method public boolean hasNestedScrollingParent(int);
+    method public boolean isFillViewport();
+    method public boolean isSmoothScrollingEnabled();
+    method public void onAttachedToWindow();
+    method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+    method public void onNestedScroll(android.view.View, int, int, int, int, int, int[]);
+    method public void onNestedScroll(android.view.View, int, int, int, int, int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+    method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+    method public void onStopNestedScroll(android.view.View, int);
+    method public boolean pageScroll(int);
+    method public void setFillViewport(boolean);
+    method public void setOnScrollChangeListener(androidx.core.widget.NestedScrollView.OnScrollChangeListener?);
+    method public void setSmoothScrollingEnabled(boolean);
+    method public final void smoothScrollBy(int, int);
+    method public final void smoothScrollBy(int, int, int);
+    method public final void smoothScrollTo(int, int);
+    method public final void smoothScrollTo(int, int, int);
+    method public boolean startNestedScroll(int, int);
+    method public void stopNestedScroll(int);
+  }
+
+  public static interface NestedScrollView.OnScrollChangeListener {
+    method public void onScrollChange(androidx.core.widget.NestedScrollView!, int, int, int, int);
+  }
+
+  public final class PopupMenuCompat {
+    method public static android.view.View.OnTouchListener? getDragToOpenListener(Object);
+  }
+
+  public final class PopupWindowCompat {
+    method public static boolean getOverlapAnchor(android.widget.PopupWindow);
+    method public static int getWindowLayoutType(android.widget.PopupWindow);
+    method public static void setOverlapAnchor(android.widget.PopupWindow, boolean);
+    method public static void setWindowLayoutType(android.widget.PopupWindow, int);
+    method public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
+  }
+
+  @Deprecated public final class ScrollerCompat {
+    method @Deprecated public void abortAnimation();
+    method @Deprecated public boolean computeScrollOffset();
+    method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!);
+    method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!, android.view.animation.Interpolator!);
+    method @Deprecated public void fling(int, int, int, int, int, int, int, int);
+    method @Deprecated public void fling(int, int, int, int, int, int, int, int, int, int);
+    method @Deprecated public float getCurrVelocity();
+    method @Deprecated public int getCurrX();
+    method @Deprecated public int getCurrY();
+    method @Deprecated public int getFinalX();
+    method @Deprecated public int getFinalY();
+    method @Deprecated public boolean isFinished();
+    method @Deprecated public boolean isOverScrolled();
+    method @Deprecated public void notifyHorizontalEdgeReached(int, int, int);
+    method @Deprecated public void notifyVerticalEdgeReached(int, int, int);
+    method @Deprecated public boolean springBack(int, int, int, int, int, int);
+    method @Deprecated public void startScroll(int, int, int, int);
+    method @Deprecated public void startScroll(int, int, int, int, int);
+  }
+
+  public final class TextViewCompat {
+    method public static int getAutoSizeMaxTextSize(android.widget.TextView);
+    method public static int getAutoSizeMinTextSize(android.widget.TextView);
+    method public static int getAutoSizeStepGranularity(android.widget.TextView);
+    method public static int[] getAutoSizeTextAvailableSizes(android.widget.TextView);
+    method public static int getAutoSizeTextType(android.widget.TextView);
+    method public static android.content.res.ColorStateList? getCompoundDrawableTintList(android.widget.TextView);
+    method public static android.graphics.PorterDuff.Mode? getCompoundDrawableTintMode(android.widget.TextView);
+    method public static android.graphics.drawable.Drawable![] getCompoundDrawablesRelative(android.widget.TextView);
+    method public static int getFirstBaselineToTopHeight(android.widget.TextView);
+    method public static int getLastBaselineToBottomHeight(android.widget.TextView);
+    method public static int getMaxLines(android.widget.TextView);
+    method public static int getMinLines(android.widget.TextView);
+    method public static androidx.core.text.PrecomputedTextCompat.Params getTextMetricsParams(android.widget.TextView);
+    method public static void setAutoSizeTextTypeUniformWithConfiguration(android.widget.TextView, int, int, int, int) throws java.lang.IllegalArgumentException;
+    method public static void setAutoSizeTextTypeUniformWithPresetSizes(android.widget.TextView, int[], int) throws java.lang.IllegalArgumentException;
+    method public static void setAutoSizeTextTypeWithDefaults(android.widget.TextView, int);
+    method public static void setCompoundDrawableTintList(android.widget.TextView, android.content.res.ColorStateList?);
+    method public static void setCompoundDrawableTintMode(android.widget.TextView, android.graphics.PorterDuff.Mode?);
+    method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, @DrawableRes int, @DrawableRes int, @DrawableRes int, @DrawableRes int);
+    method public static void setCustomSelectionActionModeCallback(android.widget.TextView, android.view.ActionMode.Callback);
+    method public static void setFirstBaselineToTopHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+    method public static void setLastBaselineToBottomHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+    method public static void setLineHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+    method public static void setPrecomputedText(android.widget.TextView, androidx.core.text.PrecomputedTextCompat);
+    method public static void setTextAppearance(android.widget.TextView, @StyleRes int);
+    method public static void setTextMetricsParams(android.widget.TextView, androidx.core.text.PrecomputedTextCompat.Params);
+    field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
+    field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1
+  }
+
+  public interface TintableCompoundButton {
+    method public android.content.res.ColorStateList? getSupportButtonTintList();
+    method public android.graphics.PorterDuff.Mode? getSupportButtonTintMode();
+    method public void setSupportButtonTintList(android.content.res.ColorStateList?);
+    method public void setSupportButtonTintMode(android.graphics.PorterDuff.Mode?);
+  }
+
+  public interface TintableCompoundDrawablesView {
+    method public android.content.res.ColorStateList? getSupportCompoundDrawablesTintList();
+    method public android.graphics.PorterDuff.Mode? getSupportCompoundDrawablesTintMode();
+    method public void setSupportCompoundDrawablesTintList(android.content.res.ColorStateList?);
+    method public void setSupportCompoundDrawablesTintMode(android.graphics.PorterDuff.Mode?);
+  }
+
+}
+
diff --git a/core/core/api/public_plus_experimental_current.txt b/core/core/api/public_plus_experimental_current.txt
index aad528b..28165c4 100644
--- a/core/core/api/public_plus_experimental_current.txt
+++ b/core/core/api/public_plus_experimental_current.txt
@@ -1550,17 +1550,16 @@
     field public static final String MEDIA_UNKNOWN = "unknown";
   }
 
+  public final class ExecutorCompat {
+    method public static java.util.concurrent.Executor create(android.os.Handler);
+  }
+
   public final class HandlerCompat {
     method public static android.os.Handler createAsync(android.os.Looper);
     method public static android.os.Handler createAsync(android.os.Looper, android.os.Handler.Callback);
     method public static boolean postDelayed(android.os.Handler, Runnable, Object?, long);
   }
 
-  public class HandlerExecutor implements java.util.concurrent.Executor {
-    ctor public HandlerExecutor(android.os.Handler);
-    method public void execute(Runnable);
-  }
-
   public final class LocaleListCompat {
     method public static androidx.core.os.LocaleListCompat create(java.util.Locale!...);
     method public static androidx.core.os.LocaleListCompat forLanguageTags(String?);
diff --git a/core/core/api/res-1.5.0-beta03.txt b/core/core/api/res-1.5.0-beta03.txt
new file mode 100644
index 0000000..43cbfa4
--- /dev/null
+++ b/core/core/api/res-1.5.0-beta03.txt
@@ -0,0 +1,18 @@
+attr alpha
+attr font
+attr fontProviderAuthority
+attr fontProviderCerts
+attr fontProviderFetchStrategy
+attr fontProviderFetchTimeout
+attr fontProviderPackage
+attr fontProviderQuery
+attr fontProviderSystemFontFamily
+attr fontStyle
+attr fontVariationSettings
+attr fontWeight
+attr ttcIndex
+style TextAppearance_Compat_Notification
+style TextAppearance_Compat_Notification_Info
+style TextAppearance_Compat_Notification_Line2
+style TextAppearance_Compat_Notification_Time
+style TextAppearance_Compat_Notification_Title
diff --git a/core/core/api/restricted_1.5.0-beta03.txt b/core/core/api/restricted_1.5.0-beta03.txt
new file mode 100644
index 0000000..edda7df
--- /dev/null
+++ b/core/core/api/restricted_1.5.0-beta03.txt
@@ -0,0 +1,3970 @@
+// Signature format: 4.0
+package android.support.v4.os {
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ResultReceiver implements android.os.Parcelable {
+    ctor public ResultReceiver(android.os.Handler!);
+    method public int describeContents();
+    method protected void onReceiveResult(int, android.os.Bundle!);
+    method public void send(int, android.os.Bundle!);
+    method public void writeToParcel(android.os.Parcel!, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.os.ResultReceiver!>! CREATOR;
+  }
+
+}
+
+package androidx.core.accessibilityservice {
+
+  public final class AccessibilityServiceInfoCompat {
+    method public static String capabilityToString(int);
+    method public static String feedbackTypeToString(int);
+    method public static String? flagToString(int);
+    method public static int getCapabilities(android.accessibilityservice.AccessibilityServiceInfo);
+    method public static String? loadDescription(android.accessibilityservice.AccessibilityServiceInfo, android.content.pm.PackageManager);
+    field public static final int CAPABILITY_CAN_FILTER_KEY_EVENTS = 8; // 0x8
+    field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+    field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
+    field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
+    field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff
+    field public static final int FEEDBACK_BRAILLE = 32; // 0x20
+    field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
+    field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
+    field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+    field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
+    field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
+  }
+
+}
+
+package androidx.core.app {
+
+  public class ActivityCompat extends androidx.core.content.ContextCompat {
+    ctor protected ActivityCompat();
+    method public static void finishAffinity(android.app.Activity);
+    method public static void finishAfterTransition(android.app.Activity);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.ActivityCompat.PermissionCompatDelegate! getPermissionCompatDelegate();
+    method public static android.net.Uri? getReferrer(android.app.Activity);
+    method @Deprecated public static boolean invalidateOptionsMenu(android.app.Activity!);
+    method public static void postponeEnterTransition(android.app.Activity);
+    method public static void recreate(android.app.Activity);
+    method public static androidx.core.view.DragAndDropPermissionsCompat? requestDragAndDropPermissions(android.app.Activity!, android.view.DragEvent!);
+    method public static void requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+    method public static <T extends android.view.View> T requireViewById(android.app.Activity, @IdRes int);
+    method public static void setEnterSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+    method public static void setExitSharedElementCallback(android.app.Activity, androidx.core.app.SharedElementCallback?);
+    method public static void setLocusContext(android.app.Activity, androidx.core.content.LocusIdCompat?, android.os.Bundle?);
+    method public static void setPermissionCompatDelegate(androidx.core.app.ActivityCompat.PermissionCompatDelegate?);
+    method public static boolean shouldShowRequestPermissionRationale(android.app.Activity, String);
+    method public static void startActivityForResult(android.app.Activity, android.content.Intent, int, android.os.Bundle?);
+    method public static void startIntentSenderForResult(android.app.Activity, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+    method public static void startPostponedEnterTransition(android.app.Activity);
+  }
+
+  public static interface ActivityCompat.OnRequestPermissionsResultCallback {
+    method public void onRequestPermissionsResult(int, String![], int[]);
+  }
+
+  public static interface ActivityCompat.PermissionCompatDelegate {
+    method public boolean onActivityResult(android.app.Activity, @IntRange(from=0) int, int, android.content.Intent?);
+    method public boolean requestPermissions(android.app.Activity, String![], @IntRange(from=0) int);
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static interface ActivityCompat.RequestPermissionsRequestCodeValidator {
+    method public void validateRequestPermissionsRequestCode(int);
+  }
+
+  public final class ActivityManagerCompat {
+    method public static boolean isLowRamDevice(android.app.ActivityManager);
+  }
+
+  public class ActivityOptionsCompat {
+    ctor protected ActivityOptionsCompat();
+    method public android.graphics.Rect? getLaunchBounds();
+    method public static androidx.core.app.ActivityOptionsCompat makeBasic();
+    method public static androidx.core.app.ActivityOptionsCompat makeClipRevealAnimation(android.view.View, int, int, int, int);
+    method public static androidx.core.app.ActivityOptionsCompat makeCustomAnimation(android.content.Context, int, int);
+    method public static androidx.core.app.ActivityOptionsCompat makeScaleUpAnimation(android.view.View, int, int, int, int);
+    method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, android.view.View, String);
+    method public static androidx.core.app.ActivityOptionsCompat makeSceneTransitionAnimation(android.app.Activity, androidx.core.util.Pair<android.view.View!,java.lang.String!>!...);
+    method public static androidx.core.app.ActivityOptionsCompat makeTaskLaunchBehind();
+    method public static androidx.core.app.ActivityOptionsCompat makeThumbnailScaleUpAnimation(android.view.View, android.graphics.Bitmap, int, int);
+    method public void requestUsageTimeReport(android.app.PendingIntent);
+    method public androidx.core.app.ActivityOptionsCompat setLaunchBounds(android.graphics.Rect?);
+    method public android.os.Bundle? toBundle();
+    method public void update(androidx.core.app.ActivityOptionsCompat);
+    field public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time";
+    field public static final String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages";
+  }
+
+  public final class AlarmManagerCompat {
+    method public static void setAlarmClock(android.app.AlarmManager, long, android.app.PendingIntent, android.app.PendingIntent);
+    method public static void setAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+    method public static void setExact(android.app.AlarmManager, int, long, android.app.PendingIntent);
+    method public static void setExactAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
+  }
+
+  @RequiresApi(28) public class AppComponentFactory extends android.app.AppComponentFactory {
+    ctor public AppComponentFactory();
+    method public final android.app.Activity instantiateActivity(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.app.Activity instantiateActivityCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public final android.app.Application instantiateApplication(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.app.Application instantiateApplicationCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public final android.content.ContentProvider instantiateProvider(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.content.ContentProvider instantiateProviderCompat(ClassLoader, String) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public final android.content.BroadcastReceiver instantiateReceiver(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.content.BroadcastReceiver instantiateReceiverCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public final android.app.Service instantiateService(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+    method public android.app.Service instantiateServiceCompat(ClassLoader, String, android.content.Intent?) throws java.lang.ClassNotFoundException, java.lang.IllegalAccessException, java.lang.InstantiationException;
+  }
+
+  public class AppLaunchChecker {
+    ctor @Deprecated public AppLaunchChecker();
+    method public static boolean hasStartedFromLauncher(android.content.Context);
+    method public static void onActivityCreate(android.app.Activity);
+  }
+
+  public final class AppOpsManagerCompat {
+    method public static int noteOp(android.content.Context, String, int, String);
+    method public static int noteOpNoThrow(android.content.Context, String, int, String);
+    method public static int noteProxyOp(android.content.Context, String, String);
+    method public static int noteProxyOpNoThrow(android.content.Context, String, String);
+    method public static String? permissionToOp(String);
+    field public static final int MODE_ALLOWED = 0; // 0x0
+    field public static final int MODE_DEFAULT = 3; // 0x3
+    field public static final int MODE_ERRORED = 2; // 0x2
+    field public static final int MODE_IGNORED = 1; // 0x1
+  }
+
+  public final class BundleCompat {
+    method public static android.os.IBinder? getBinder(android.os.Bundle, String?);
+    method public static void putBinder(android.os.Bundle, String?, android.os.IBinder?);
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ComponentActivity extends android.app.Activity implements androidx.core.view.KeyEventDispatcher.Component androidx.lifecycle.LifecycleOwner {
+    ctor public ComponentActivity();
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public <T extends androidx.core.app.ComponentActivity.ExtraData> T! getExtraData(Class<T!>!);
+    method public androidx.lifecycle.Lifecycle getLifecycle();
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void putExtraData(androidx.core.app.ComponentActivity.ExtraData!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean superDispatchKeyEvent(android.view.KeyEvent!);
+  }
+
+  @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static class ComponentActivity.ExtraData {
+    ctor @Deprecated public ComponentActivity.ExtraData();
+  }
+
+  @RequiresApi(api=28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class CoreComponentFactory extends android.app.AppComponentFactory {
+    ctor public CoreComponentFactory();
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static interface CoreComponentFactory.CompatWrapped {
+    method public Object! getWrapper();
+  }
+
+  public class DialogCompat {
+    method public static android.view.View requireViewById(android.app.Dialog, int);
+  }
+
+  public class FrameMetricsAggregator {
+    ctor public FrameMetricsAggregator();
+    ctor public FrameMetricsAggregator(@androidx.core.app.FrameMetricsAggregator.MetricType int);
+    method public void add(android.app.Activity);
+    method public android.util.SparseIntArray![]? getMetrics();
+    method public android.util.SparseIntArray![]? remove(android.app.Activity);
+    method public android.util.SparseIntArray![]? reset();
+    method public android.util.SparseIntArray![]? stop();
+    field public static final int ANIMATION_DURATION = 256; // 0x100
+    field public static final int ANIMATION_INDEX = 8; // 0x8
+    field public static final int COMMAND_DURATION = 32; // 0x20
+    field public static final int COMMAND_INDEX = 5; // 0x5
+    field public static final int DELAY_DURATION = 128; // 0x80
+    field public static final int DELAY_INDEX = 7; // 0x7
+    field public static final int DRAW_DURATION = 8; // 0x8
+    field public static final int DRAW_INDEX = 3; // 0x3
+    field public static final int EVERY_DURATION = 511; // 0x1ff
+    field public static final int INPUT_DURATION = 2; // 0x2
+    field public static final int INPUT_INDEX = 1; // 0x1
+    field public static final int LAYOUT_MEASURE_DURATION = 4; // 0x4
+    field public static final int LAYOUT_MEASURE_INDEX = 2; // 0x2
+    field public static final int SWAP_DURATION = 64; // 0x40
+    field public static final int SWAP_INDEX = 6; // 0x6
+    field public static final int SYNC_DURATION = 16; // 0x10
+    field public static final int SYNC_INDEX = 4; // 0x4
+    field public static final int TOTAL_DURATION = 1; // 0x1
+    field public static final int TOTAL_INDEX = 0; // 0x0
+  }
+
+  @IntDef(flag=true, value={androidx.core.app.FrameMetricsAggregator.TOTAL_DURATION, androidx.core.app.FrameMetricsAggregator.INPUT_DURATION, androidx.core.app.FrameMetricsAggregator.LAYOUT_MEASURE_DURATION, androidx.core.app.FrameMetricsAggregator.DRAW_DURATION, androidx.core.app.FrameMetricsAggregator.SYNC_DURATION, androidx.core.app.FrameMetricsAggregator.COMMAND_DURATION, androidx.core.app.FrameMetricsAggregator.SWAP_DURATION, androidx.core.app.FrameMetricsAggregator.DELAY_DURATION, androidx.core.app.FrameMetricsAggregator.ANIMATION_DURATION, androidx.core.app.FrameMetricsAggregator.EVERY_DURATION}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface FrameMetricsAggregator.MetricType {
+  }
+
+  public abstract class JobIntentService extends android.app.Service {
+    ctor public JobIntentService();
+    method public static void enqueueWork(android.content.Context, Class<?>, int, android.content.Intent);
+    method public static void enqueueWork(android.content.Context, android.content.ComponentName, int, android.content.Intent);
+    method public boolean isStopped();
+    method public android.os.IBinder! onBind(android.content.Intent);
+    method protected abstract void onHandleWork(android.content.Intent);
+    method public boolean onStopCurrentWork();
+    method public void setInterruptIfStopped(boolean);
+  }
+
+  public final class NavUtils {
+    method public static android.content.Intent? getParentActivityIntent(android.app.Activity);
+    method public static android.content.Intent? getParentActivityIntent(android.content.Context, Class<?>) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static android.content.Intent? getParentActivityIntent(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static String? getParentActivityName(android.app.Activity);
+    method public static String? getParentActivityName(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static void navigateUpFromSameTask(android.app.Activity);
+    method public static void navigateUpTo(android.app.Activity, android.content.Intent);
+    method public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
+    field public static final String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface NotificationBuilderWithBuilderAccessor {
+    method public android.app.Notification.Builder! getBuilder();
+  }
+
+  public class NotificationChannelCompat {
+    method public boolean canBubble();
+    method public boolean canBypassDnd();
+    method public boolean canShowBadge();
+    method public android.media.AudioAttributes? getAudioAttributes();
+    method public String? getConversationId();
+    method public String? getDescription();
+    method public String? getGroup();
+    method public String getId();
+    method public int getImportance();
+    method public int getLightColor();
+    method @androidx.core.app.NotificationCompat.NotificationVisibility public int getLockscreenVisibility();
+    method public CharSequence? getName();
+    method public String? getParentChannelId();
+    method public android.net.Uri? getSound();
+    method public long[]? getVibrationPattern();
+    method public boolean isImportantConversation();
+    method public boolean shouldShowLights();
+    method public boolean shouldVibrate();
+    method public androidx.core.app.NotificationChannelCompat.Builder toBuilder();
+    field public static final String DEFAULT_CHANNEL_ID = "miscellaneous";
+  }
+
+  public static class NotificationChannelCompat.Builder {
+    ctor public NotificationChannelCompat.Builder(String, int);
+    method public androidx.core.app.NotificationChannelCompat build();
+    method public androidx.core.app.NotificationChannelCompat.Builder setConversationId(String, String);
+    method public androidx.core.app.NotificationChannelCompat.Builder setDescription(String?);
+    method public androidx.core.app.NotificationChannelCompat.Builder setGroup(String?);
+    method public androidx.core.app.NotificationChannelCompat.Builder setImportance(int);
+    method public androidx.core.app.NotificationChannelCompat.Builder setLightColor(int);
+    method public androidx.core.app.NotificationChannelCompat.Builder setLightsEnabled(boolean);
+    method public androidx.core.app.NotificationChannelCompat.Builder setName(CharSequence?);
+    method public androidx.core.app.NotificationChannelCompat.Builder setShowBadge(boolean);
+    method public androidx.core.app.NotificationChannelCompat.Builder setSound(android.net.Uri?, android.media.AudioAttributes?);
+    method public androidx.core.app.NotificationChannelCompat.Builder setVibrationEnabled(boolean);
+    method public androidx.core.app.NotificationChannelCompat.Builder setVibrationPattern(long[]?);
+  }
+
+  public class NotificationChannelGroupCompat {
+    method public java.util.List<androidx.core.app.NotificationChannelCompat!> getChannels();
+    method public String? getDescription();
+    method public String getId();
+    method public CharSequence? getName();
+    method public boolean isBlocked();
+    method public androidx.core.app.NotificationChannelGroupCompat.Builder toBuilder();
+  }
+
+  public static class NotificationChannelGroupCompat.Builder {
+    ctor public NotificationChannelGroupCompat.Builder(String);
+    method public androidx.core.app.NotificationChannelGroupCompat build();
+    method public androidx.core.app.NotificationChannelGroupCompat.Builder setDescription(String?);
+    method public androidx.core.app.NotificationChannelGroupCompat.Builder setName(CharSequence?);
+  }
+
+  public class NotificationCompat {
+    ctor @Deprecated public NotificationCompat();
+    method public static androidx.core.app.NotificationCompat.Action? getAction(android.app.Notification, int);
+    method public static int getActionCount(android.app.Notification);
+    method public static boolean getAllowSystemGeneratedContextualActions(android.app.Notification);
+    method public static boolean getAutoCancel(android.app.Notification);
+    method public static int getBadgeIconType(android.app.Notification);
+    method public static androidx.core.app.NotificationCompat.BubbleMetadata? getBubbleMetadata(android.app.Notification);
+    method public static String? getCategory(android.app.Notification);
+    method public static String? getChannelId(android.app.Notification);
+    method public static int getColor(android.app.Notification);
+    method @RequiresApi(19) public static CharSequence? getContentInfo(android.app.Notification);
+    method @RequiresApi(19) public static CharSequence? getContentText(android.app.Notification);
+    method @RequiresApi(19) public static CharSequence? getContentTitle(android.app.Notification);
+    method public static android.os.Bundle? getExtras(android.app.Notification);
+    method public static String? getGroup(android.app.Notification);
+    method @androidx.core.app.NotificationCompat.GroupAlertBehavior public static int getGroupAlertBehavior(android.app.Notification);
+    method @RequiresApi(21) public static java.util.List<androidx.core.app.NotificationCompat.Action!> getInvisibleActions(android.app.Notification);
+    method public static boolean getLocalOnly(android.app.Notification);
+    method public static androidx.core.content.LocusIdCompat? getLocusId(android.app.Notification);
+    method public static boolean getOngoing(android.app.Notification);
+    method public static boolean getOnlyAlertOnce(android.app.Notification);
+    method public static java.util.List<androidx.core.app.Person!> getPeople(android.app.Notification);
+    method public static android.app.Notification? getPublicVersion(android.app.Notification);
+    method public static CharSequence? getSettingsText(android.app.Notification);
+    method public static String? getShortcutId(android.app.Notification);
+    method @RequiresApi(19) public static boolean getShowWhen(android.app.Notification);
+    method public static String? getSortKey(android.app.Notification);
+    method @RequiresApi(19) public static CharSequence? getSubText(android.app.Notification);
+    method public static long getTimeoutAfter(android.app.Notification);
+    method @RequiresApi(19) public static boolean getUsesChronometer(android.app.Notification);
+    method @androidx.core.app.NotificationCompat.NotificationVisibility public static int getVisibility(android.app.Notification);
+    method public static boolean isGroupSummary(android.app.Notification);
+    field public static final int BADGE_ICON_LARGE = 2; // 0x2
+    field public static final int BADGE_ICON_NONE = 0; // 0x0
+    field public static final int BADGE_ICON_SMALL = 1; // 0x1
+    field public static final String CATEGORY_ALARM = "alarm";
+    field public static final String CATEGORY_CALL = "call";
+    field public static final String CATEGORY_EMAIL = "email";
+    field public static final String CATEGORY_ERROR = "err";
+    field public static final String CATEGORY_EVENT = "event";
+    field public static final String CATEGORY_LOCATION_SHARING = "location_sharing";
+    field public static final String CATEGORY_MESSAGE = "msg";
+    field public static final String CATEGORY_MISSED_CALL = "missed_call";
+    field public static final String CATEGORY_NAVIGATION = "navigation";
+    field public static final String CATEGORY_PROGRESS = "progress";
+    field public static final String CATEGORY_PROMO = "promo";
+    field public static final String CATEGORY_RECOMMENDATION = "recommendation";
+    field public static final String CATEGORY_REMINDER = "reminder";
+    field public static final String CATEGORY_SERVICE = "service";
+    field public static final String CATEGORY_SOCIAL = "social";
+    field public static final String CATEGORY_STATUS = "status";
+    field public static final String CATEGORY_STOPWATCH = "stopwatch";
+    field public static final String CATEGORY_SYSTEM = "sys";
+    field public static final String CATEGORY_TRANSPORT = "transport";
+    field public static final String CATEGORY_WORKOUT = "workout";
+    field @ColorInt public static final int COLOR_DEFAULT = 0; // 0x0
+    field public static final int DEFAULT_ALL = -1; // 0xffffffff
+    field public static final int DEFAULT_LIGHTS = 4; // 0x4
+    field public static final int DEFAULT_SOUND = 1; // 0x1
+    field public static final int DEFAULT_VIBRATE = 2; // 0x2
+    field public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
+    field public static final String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
+    field public static final String EXTRA_BIG_TEXT = "android.bigText";
+    field public static final String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
+    field public static final String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID";
+    field public static final String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
+    field public static final String EXTRA_COLORIZED = "android.colorized";
+    field public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+    field public static final String EXTRA_COMPAT_TEMPLATE = "androidx.core.app.extra.COMPAT_TEMPLATE";
+    field public static final String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
+    field public static final String EXTRA_HIDDEN_CONVERSATION_TITLE = "android.hiddenConversationTitle";
+    field public static final String EXTRA_HISTORIC_MESSAGES = "android.messages.historic";
+    field public static final String EXTRA_INFO_TEXT = "android.infoText";
+    field public static final String EXTRA_IS_GROUP_CONVERSATION = "android.isGroupConversation";
+    field public static final String EXTRA_LARGE_ICON = "android.largeIcon";
+    field public static final String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
+    field public static final String EXTRA_MEDIA_SESSION = "android.mediaSession";
+    field public static final String EXTRA_MESSAGES = "android.messages";
+    field public static final String EXTRA_MESSAGING_STYLE_USER = "android.messagingStyleUser";
+    field public static final String EXTRA_NOTIFICATION_ID = "android.intent.extra.NOTIFICATION_ID";
+    field public static final String EXTRA_NOTIFICATION_TAG = "android.intent.extra.NOTIFICATION_TAG";
+    field @Deprecated public static final String EXTRA_PEOPLE = "android.people";
+    field public static final String EXTRA_PEOPLE_LIST = "android.people.list";
+    field public static final String EXTRA_PICTURE = "android.picture";
+    field public static final String EXTRA_PROGRESS = "android.progress";
+    field public static final String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
+    field public static final String EXTRA_PROGRESS_MAX = "android.progressMax";
+    field public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
+    field public static final String EXTRA_SELF_DISPLAY_NAME = "android.selfDisplayName";
+    field public static final String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
+    field public static final String EXTRA_SHOW_WHEN = "android.showWhen";
+    field public static final String EXTRA_SMALL_ICON = "android.icon";
+    field public static final String EXTRA_SUB_TEXT = "android.subText";
+    field public static final String EXTRA_SUMMARY_TEXT = "android.summaryText";
+    field public static final String EXTRA_TEMPLATE = "android.template";
+    field public static final String EXTRA_TEXT = "android.text";
+    field public static final String EXTRA_TEXT_LINES = "android.textLines";
+    field public static final String EXTRA_TITLE = "android.title";
+    field public static final String EXTRA_TITLE_BIG = "android.title.big";
+    field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
+    field public static final int FLAG_BUBBLE = 4096; // 0x1000
+    field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
+    field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
+    field @Deprecated public static final int FLAG_HIGH_PRIORITY = 128; // 0x80
+    field public static final int FLAG_INSISTENT = 4; // 0x4
+    field public static final int FLAG_LOCAL_ONLY = 256; // 0x100
+    field public static final int FLAG_NO_CLEAR = 32; // 0x20
+    field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
+    field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
+    field public static final int FLAG_SHOW_LIGHTS = 1; // 0x1
+    field public static final int GROUP_ALERT_ALL = 0; // 0x0
+    field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
+    field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
+    field public static final String GROUP_KEY_SILENT = "silent";
+    field public static final String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
+    field public static final int PRIORITY_DEFAULT = 0; // 0x0
+    field public static final int PRIORITY_HIGH = 1; // 0x1
+    field public static final int PRIORITY_LOW = -1; // 0xffffffff
+    field public static final int PRIORITY_MAX = 2; // 0x2
+    field public static final int PRIORITY_MIN = -2; // 0xfffffffe
+    field public static final int STREAM_DEFAULT = -1; // 0xffffffff
+    field public static final int VISIBILITY_PRIVATE = 0; // 0x0
+    field public static final int VISIBILITY_PUBLIC = 1; // 0x1
+    field public static final int VISIBILITY_SECRET = -1; // 0xffffffff
+  }
+
+  public static class NotificationCompat.Action {
+    ctor public NotificationCompat.Action(int, CharSequence?, android.app.PendingIntent?);
+    ctor public NotificationCompat.Action(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+    method public android.app.PendingIntent? getActionIntent();
+    method public boolean getAllowGeneratedReplies();
+    method public androidx.core.app.RemoteInput![]? getDataOnlyRemoteInputs();
+    method public android.os.Bundle getExtras();
+    method @Deprecated public int getIcon();
+    method public androidx.core.graphics.drawable.IconCompat? getIconCompat();
+    method public androidx.core.app.RemoteInput![]? getRemoteInputs();
+    method @androidx.core.app.NotificationCompat.Action.SemanticAction public int getSemanticAction();
+    method public boolean getShowsUserInterface();
+    method public CharSequence? getTitle();
+    method public boolean isContextual();
+    field public static final int SEMANTIC_ACTION_ARCHIVE = 5; // 0x5
+    field public static final int SEMANTIC_ACTION_CALL = 10; // 0xa
+    field public static final int SEMANTIC_ACTION_DELETE = 4; // 0x4
+    field public static final int SEMANTIC_ACTION_MARK_AS_READ = 2; // 0x2
+    field public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3; // 0x3
+    field public static final int SEMANTIC_ACTION_MUTE = 6; // 0x6
+    field public static final int SEMANTIC_ACTION_NONE = 0; // 0x0
+    field public static final int SEMANTIC_ACTION_REPLY = 1; // 0x1
+    field public static final int SEMANTIC_ACTION_THUMBS_DOWN = 9; // 0x9
+    field public static final int SEMANTIC_ACTION_THUMBS_UP = 8; // 0x8
+    field public static final int SEMANTIC_ACTION_UNMUTE = 7; // 0x7
+    field public android.app.PendingIntent! actionIntent;
+    field @Deprecated public int icon;
+    field public CharSequence! title;
+  }
+
+  public static final class NotificationCompat.Action.Builder {
+    ctor public NotificationCompat.Action.Builder(androidx.core.graphics.drawable.IconCompat?, CharSequence?, android.app.PendingIntent?);
+    ctor public NotificationCompat.Action.Builder(int, CharSequence?, android.app.PendingIntent?);
+    ctor public NotificationCompat.Action.Builder(androidx.core.app.NotificationCompat.Action);
+    method public androidx.core.app.NotificationCompat.Action.Builder addExtras(android.os.Bundle?);
+    method public androidx.core.app.NotificationCompat.Action.Builder addRemoteInput(androidx.core.app.RemoteInput?);
+    method public androidx.core.app.NotificationCompat.Action build();
+    method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Extender);
+    method @RequiresApi(19) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.NotificationCompat.Action.Builder fromAndroidAction(android.app.Notification.Action);
+    method public android.os.Bundle getExtras();
+    method public androidx.core.app.NotificationCompat.Action.Builder setAllowGeneratedReplies(boolean);
+    method public androidx.core.app.NotificationCompat.Action.Builder setContextual(boolean);
+    method public androidx.core.app.NotificationCompat.Action.Builder setSemanticAction(@androidx.core.app.NotificationCompat.Action.SemanticAction int);
+    method public androidx.core.app.NotificationCompat.Action.Builder setShowsUserInterface(boolean);
+  }
+
+  public static interface NotificationCompat.Action.Extender {
+    method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+  }
+
+  @IntDef({androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_NONE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_REPLY, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_READ, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MARK_AS_UNREAD, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_DELETE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_ARCHIVE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_MUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_UNMUTE, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_UP, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_THUMBS_DOWN, androidx.core.app.NotificationCompat.Action.SEMANTIC_ACTION_CALL}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.Action.SemanticAction {
+  }
+
+  public static final class NotificationCompat.Action.WearableExtender implements androidx.core.app.NotificationCompat.Action.Extender {
+    ctor public NotificationCompat.Action.WearableExtender();
+    ctor public NotificationCompat.Action.WearableExtender(androidx.core.app.NotificationCompat.Action);
+    method public androidx.core.app.NotificationCompat.Action.WearableExtender clone();
+    method public androidx.core.app.NotificationCompat.Action.Builder extend(androidx.core.app.NotificationCompat.Action.Builder);
+    method @Deprecated public CharSequence? getCancelLabel();
+    method @Deprecated public CharSequence? getConfirmLabel();
+    method public boolean getHintDisplayActionInline();
+    method public boolean getHintLaunchesActivity();
+    method @Deprecated public CharSequence? getInProgressLabel();
+    method public boolean isAvailableOffline();
+    method public androidx.core.app.NotificationCompat.Action.WearableExtender setAvailableOffline(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setCancelLabel(CharSequence?);
+    method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setConfirmLabel(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintDisplayActionInline(boolean);
+    method public androidx.core.app.NotificationCompat.Action.WearableExtender setHintLaunchesActivity(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.Action.WearableExtender setInProgressLabel(CharSequence?);
+  }
+
+  @IntDef({androidx.core.app.NotificationCompat.BADGE_ICON_NONE, androidx.core.app.NotificationCompat.BADGE_ICON_SMALL, androidx.core.app.NotificationCompat.BADGE_ICON_LARGE}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.BadgeIconType {
+  }
+
+  public static class NotificationCompat.BigPictureStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor public NotificationCompat.BigPictureStyle();
+    ctor public NotificationCompat.BigPictureStyle(androidx.core.app.NotificationCompat.Builder?);
+    method public androidx.core.app.NotificationCompat.BigPictureStyle bigLargeIcon(android.graphics.Bitmap?);
+    method public androidx.core.app.NotificationCompat.BigPictureStyle bigPicture(android.graphics.Bitmap?);
+    method public androidx.core.app.NotificationCompat.BigPictureStyle setBigContentTitle(CharSequence?);
+    method public androidx.core.app.NotificationCompat.BigPictureStyle setSummaryText(CharSequence?);
+  }
+
+  public static class NotificationCompat.BigTextStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor public NotificationCompat.BigTextStyle();
+    ctor public NotificationCompat.BigTextStyle(androidx.core.app.NotificationCompat.Builder?);
+    method public androidx.core.app.NotificationCompat.BigTextStyle bigText(CharSequence?);
+    method public androidx.core.app.NotificationCompat.BigTextStyle setBigContentTitle(CharSequence?);
+    method public androidx.core.app.NotificationCompat.BigTextStyle setSummaryText(CharSequence?);
+  }
+
+  public static final class NotificationCompat.BubbleMetadata {
+    method public static androidx.core.app.NotificationCompat.BubbleMetadata? fromPlatform(android.app.Notification.BubbleMetadata?);
+    method public boolean getAutoExpandBubble();
+    method public android.app.PendingIntent? getDeleteIntent();
+    method @Dimension(unit=androidx.annotation.Dimension.DP) public int getDesiredHeight();
+    method @DimenRes public int getDesiredHeightResId();
+    method public androidx.core.graphics.drawable.IconCompat? getIcon();
+    method public android.app.PendingIntent? getIntent();
+    method public String? getShortcutId();
+    method public boolean isNotificationSuppressed();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setFlags(int);
+    method public static android.app.Notification.BubbleMetadata? toPlatform(androidx.core.app.NotificationCompat.BubbleMetadata?);
+  }
+
+  public static final class NotificationCompat.BubbleMetadata.Builder {
+    ctor @Deprecated public NotificationCompat.BubbleMetadata.Builder();
+    ctor @RequiresApi(30) public NotificationCompat.BubbleMetadata.Builder(String);
+    ctor public NotificationCompat.BubbleMetadata.Builder(android.app.PendingIntent, androidx.core.graphics.drawable.IconCompat);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata build();
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setAutoExpandBubble(boolean);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDeleteIntent(android.app.PendingIntent?);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeight(@Dimension(unit=androidx.annotation.Dimension.DP) int);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIcon(androidx.core.graphics.drawable.IconCompat);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setIntent(android.app.PendingIntent);
+    method public androidx.core.app.NotificationCompat.BubbleMetadata.Builder setSuppressNotification(boolean);
+  }
+
+  public static class NotificationCompat.Builder {
+    ctor @RequiresApi(19) public NotificationCompat.Builder(android.content.Context, android.app.Notification);
+    ctor public NotificationCompat.Builder(android.content.Context, String);
+    ctor @Deprecated public NotificationCompat.Builder(android.content.Context);
+    method public androidx.core.app.NotificationCompat.Builder addAction(int, CharSequence?, android.app.PendingIntent?);
+    method public androidx.core.app.NotificationCompat.Builder addAction(androidx.core.app.NotificationCompat.Action?);
+    method public androidx.core.app.NotificationCompat.Builder addExtras(android.os.Bundle?);
+    method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(int, CharSequence?, android.app.PendingIntent?);
+    method @RequiresApi(21) public androidx.core.app.NotificationCompat.Builder addInvisibleAction(androidx.core.app.NotificationCompat.Action?);
+    method @Deprecated public androidx.core.app.NotificationCompat.Builder addPerson(String?);
+    method public androidx.core.app.NotificationCompat.Builder addPerson(androidx.core.app.Person?);
+    method public android.app.Notification build();
+    method public androidx.core.app.NotificationCompat.Builder clearActions();
+    method public androidx.core.app.NotificationCompat.Builder clearInvisibleActions();
+    method public androidx.core.app.NotificationCompat.Builder clearPeople();
+    method public android.widget.RemoteViews? createBigContentView();
+    method public android.widget.RemoteViews? createContentView();
+    method public android.widget.RemoteViews? createHeadsUpContentView();
+    method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Extender);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! getBigContentView();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.core.app.NotificationCompat.BubbleMetadata? getBubbleMetadata();
+    method @ColorInt @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int getColor();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! getContentView();
+    method public android.os.Bundle getExtras();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! getHeadsUpContentView();
+    method @Deprecated public android.app.Notification getNotification();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int getPriority();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public long getWhenIfShowing();
+    method protected static CharSequence? limitCharSequenceLength(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setAllowSystemGeneratedContextualActions(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setAutoCancel(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setBadgeIconType(@androidx.core.app.NotificationCompat.BadgeIconType int);
+    method public androidx.core.app.NotificationCompat.Builder setBubbleMetadata(androidx.core.app.NotificationCompat.BubbleMetadata?);
+    method public androidx.core.app.NotificationCompat.Builder setCategory(String?);
+    method public androidx.core.app.NotificationCompat.Builder setChannelId(String);
+    method @RequiresApi(24) public androidx.core.app.NotificationCompat.Builder setChronometerCountDown(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setColor(@ColorInt int);
+    method public androidx.core.app.NotificationCompat.Builder setColorized(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setContent(android.widget.RemoteViews?);
+    method public androidx.core.app.NotificationCompat.Builder setContentInfo(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setContentIntent(android.app.PendingIntent?);
+    method public androidx.core.app.NotificationCompat.Builder setContentText(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setContentTitle(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setCustomBigContentView(android.widget.RemoteViews?);
+    method public androidx.core.app.NotificationCompat.Builder setCustomContentView(android.widget.RemoteViews?);
+    method public androidx.core.app.NotificationCompat.Builder setCustomHeadsUpContentView(android.widget.RemoteViews?);
+    method public androidx.core.app.NotificationCompat.Builder setDefaults(int);
+    method public androidx.core.app.NotificationCompat.Builder setDeleteIntent(android.app.PendingIntent?);
+    method public androidx.core.app.NotificationCompat.Builder setExtras(android.os.Bundle?);
+    method public androidx.core.app.NotificationCompat.Builder setFullScreenIntent(android.app.PendingIntent?, boolean);
+    method public androidx.core.app.NotificationCompat.Builder setGroup(String?);
+    method public androidx.core.app.NotificationCompat.Builder setGroupAlertBehavior(@androidx.core.app.NotificationCompat.GroupAlertBehavior int);
+    method public androidx.core.app.NotificationCompat.Builder setGroupSummary(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setLargeIcon(android.graphics.Bitmap?);
+    method public androidx.core.app.NotificationCompat.Builder setLights(@ColorInt int, int, int);
+    method public androidx.core.app.NotificationCompat.Builder setLocalOnly(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+    method @Deprecated public androidx.core.app.NotificationCompat.Builder setNotificationSilent();
+    method public androidx.core.app.NotificationCompat.Builder setNumber(int);
+    method public androidx.core.app.NotificationCompat.Builder setOngoing(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setOnlyAlertOnce(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setPriority(int);
+    method public androidx.core.app.NotificationCompat.Builder setProgress(int, int, boolean);
+    method public androidx.core.app.NotificationCompat.Builder setPublicVersion(android.app.Notification?);
+    method public androidx.core.app.NotificationCompat.Builder setRemoteInputHistory(CharSequence![]?);
+    method public androidx.core.app.NotificationCompat.Builder setSettingsText(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setShortcutId(String?);
+    method public androidx.core.app.NotificationCompat.Builder setShortcutInfo(androidx.core.content.pm.ShortcutInfoCompat?);
+    method public androidx.core.app.NotificationCompat.Builder setShowWhen(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setSilent(boolean);
+    method @RequiresApi(23) public androidx.core.app.NotificationCompat.Builder setSmallIcon(androidx.core.graphics.drawable.IconCompat);
+    method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int);
+    method public androidx.core.app.NotificationCompat.Builder setSmallIcon(int, int);
+    method public androidx.core.app.NotificationCompat.Builder setSortKey(String?);
+    method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?);
+    method public androidx.core.app.NotificationCompat.Builder setSound(android.net.Uri?, @androidx.core.app.NotificationCompat.StreamType int);
+    method public androidx.core.app.NotificationCompat.Builder setStyle(androidx.core.app.NotificationCompat.Style?);
+    method public androidx.core.app.NotificationCompat.Builder setSubText(CharSequence?);
+    method public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?);
+    method @Deprecated public androidx.core.app.NotificationCompat.Builder setTicker(CharSequence?, android.widget.RemoteViews?);
+    method public androidx.core.app.NotificationCompat.Builder setTimeoutAfter(long);
+    method public androidx.core.app.NotificationCompat.Builder setUsesChronometer(boolean);
+    method public androidx.core.app.NotificationCompat.Builder setVibrate(long[]?);
+    method public androidx.core.app.NotificationCompat.Builder setVisibility(@androidx.core.app.NotificationCompat.NotificationVisibility int);
+    method public androidx.core.app.NotificationCompat.Builder setWhen(long);
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public java.util.ArrayList<androidx.core.app.NotificationCompat.Action!>! mActions;
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.content.Context! mContext;
+    field @Deprecated public java.util.ArrayList<java.lang.String!>! mPeople;
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public java.util.ArrayList<androidx.core.app.Person!> mPersonList;
+  }
+
+  public static final class NotificationCompat.CarExtender implements androidx.core.app.NotificationCompat.Extender {
+    ctor public NotificationCompat.CarExtender();
+    ctor public NotificationCompat.CarExtender(android.app.Notification);
+    method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+    method @ColorInt public int getColor();
+    method public android.graphics.Bitmap? getLargeIcon();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation? getUnreadConversation();
+    method public androidx.core.app.NotificationCompat.CarExtender setColor(@ColorInt int);
+    method public androidx.core.app.NotificationCompat.CarExtender setLargeIcon(android.graphics.Bitmap?);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation?);
+  }
+
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+    method @Deprecated public long getLatestTimestamp();
+    method @Deprecated public String![]? getMessages();
+    method @Deprecated public String? getParticipant();
+    method @Deprecated public String![]? getParticipants();
+    method @Deprecated public android.app.PendingIntent? getReadPendingIntent();
+    method @Deprecated public androidx.core.app.RemoteInput? getRemoteInput();
+    method @Deprecated public android.app.PendingIntent? getReplyPendingIntent();
+  }
+
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+    ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder addMessage(String?);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation build();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setLatestTimestamp(long);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReadPendingIntent(android.app.PendingIntent?);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder setReplyAction(android.app.PendingIntent?, androidx.core.app.RemoteInput?);
+  }
+
+  public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor public NotificationCompat.DecoratedCustomViewStyle();
+  }
+
+  public static interface NotificationCompat.Extender {
+    method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+  }
+
+  @IntDef({androidx.core.app.NotificationCompat.GROUP_ALERT_ALL, androidx.core.app.NotificationCompat.GROUP_ALERT_SUMMARY, androidx.core.app.NotificationCompat.GROUP_ALERT_CHILDREN}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.GroupAlertBehavior {
+  }
+
+  public static class NotificationCompat.InboxStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor public NotificationCompat.InboxStyle();
+    ctor public NotificationCompat.InboxStyle(androidx.core.app.NotificationCompat.Builder?);
+    method public androidx.core.app.NotificationCompat.InboxStyle addLine(CharSequence?);
+    method public androidx.core.app.NotificationCompat.InboxStyle setBigContentTitle(CharSequence?);
+    method public androidx.core.app.NotificationCompat.InboxStyle setSummaryText(CharSequence?);
+  }
+
+  public static class NotificationCompat.MessagingStyle extends androidx.core.app.NotificationCompat.Style {
+    ctor @Deprecated public NotificationCompat.MessagingStyle(CharSequence);
+    ctor public NotificationCompat.MessagingStyle(androidx.core.app.Person);
+    method public androidx.core.app.NotificationCompat.MessagingStyle addHistoricMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+    method @Deprecated public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, CharSequence?);
+    method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(CharSequence?, long, androidx.core.app.Person?);
+    method public androidx.core.app.NotificationCompat.MessagingStyle addMessage(androidx.core.app.NotificationCompat.MessagingStyle.Message?);
+    method public static androidx.core.app.NotificationCompat.MessagingStyle? extractMessagingStyleFromNotification(android.app.Notification);
+    method public CharSequence? getConversationTitle();
+    method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getHistoricMessages();
+    method public java.util.List<androidx.core.app.NotificationCompat.MessagingStyle.Message!> getMessages();
+    method public androidx.core.app.Person getUser();
+    method @Deprecated public CharSequence? getUserDisplayName();
+    method public boolean isGroupConversation();
+    method public androidx.core.app.NotificationCompat.MessagingStyle setConversationTitle(CharSequence?);
+    method public androidx.core.app.NotificationCompat.MessagingStyle setGroupConversation(boolean);
+    field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19
+  }
+
+  public static final class NotificationCompat.MessagingStyle.Message {
+    ctor public NotificationCompat.MessagingStyle.Message(CharSequence?, long, androidx.core.app.Person?);
+    ctor @Deprecated public NotificationCompat.MessagingStyle.Message(CharSequence?, long, CharSequence?);
+    method public String? getDataMimeType();
+    method public android.net.Uri? getDataUri();
+    method public android.os.Bundle getExtras();
+    method public androidx.core.app.Person? getPerson();
+    method @Deprecated public CharSequence? getSender();
+    method public CharSequence? getText();
+    method public long getTimestamp();
+    method public androidx.core.app.NotificationCompat.MessagingStyle.Message setData(String?, android.net.Uri?);
+  }
+
+  @IntDef({androidx.core.app.NotificationCompat.VISIBILITY_PUBLIC, androidx.core.app.NotificationCompat.VISIBILITY_PRIVATE, androidx.core.app.NotificationCompat.VISIBILITY_SECRET}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.NotificationVisibility {
+  }
+
+  @IntDef({android.media.AudioManager.STREAM_VOICE_CALL, android.media.AudioManager.STREAM_SYSTEM, android.media.AudioManager.STREAM_RING, android.media.AudioManager.STREAM_MUSIC, android.media.AudioManager.STREAM_ALARM, android.media.AudioManager.STREAM_NOTIFICATION, android.media.AudioManager.STREAM_DTMF, android.media.AudioManager.STREAM_ACCESSIBILITY}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface NotificationCompat.StreamType {
+  }
+
+  public abstract static class NotificationCompat.Style {
+    ctor public NotificationCompat.Style();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void addCompatExtras(android.os.Bundle);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void apply(androidx.core.app.NotificationBuilderWithBuilderAccessor!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews applyStandardTemplate(boolean, int, boolean);
+    method public android.app.Notification? build();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void buildIntoRemoteViews(android.widget.RemoteViews!, android.widget.RemoteViews!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected void clearCompatExtraKeys(android.os.Bundle);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.graphics.Bitmap! createColoredBitmap(int, int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean displayCustomViewInline();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.NotificationCompat.Style? extractStyleFromNotification(android.app.Notification);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected String? getClassName();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! makeBigContentView(androidx.core.app.NotificationBuilderWithBuilderAccessor!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! makeContentView(androidx.core.app.NotificationBuilderWithBuilderAccessor!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.widget.RemoteViews! makeHeadsUpContentView(androidx.core.app.NotificationBuilderWithBuilderAccessor!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected void restoreFromCompatExtras(android.os.Bundle);
+    method public void setBuilder(androidx.core.app.NotificationCompat.Builder?);
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected androidx.core.app.NotificationCompat.Builder! mBuilder;
+  }
+
+  public static final class NotificationCompat.WearableExtender implements androidx.core.app.NotificationCompat.Extender {
+    ctor public NotificationCompat.WearableExtender();
+    ctor public NotificationCompat.WearableExtender(android.app.Notification);
+    method public androidx.core.app.NotificationCompat.WearableExtender addAction(androidx.core.app.NotificationCompat.Action);
+    method public androidx.core.app.NotificationCompat.WearableExtender addActions(java.util.List<androidx.core.app.NotificationCompat.Action!>);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPage(android.app.Notification);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender addPages(java.util.List<android.app.Notification!>);
+    method public androidx.core.app.NotificationCompat.WearableExtender clearActions();
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender clearPages();
+    method public androidx.core.app.NotificationCompat.WearableExtender clone();
+    method public androidx.core.app.NotificationCompat.Builder extend(androidx.core.app.NotificationCompat.Builder);
+    method public java.util.List<androidx.core.app.NotificationCompat.Action!> getActions();
+    method @Deprecated public android.graphics.Bitmap? getBackground();
+    method public String? getBridgeTag();
+    method public int getContentAction();
+    method @Deprecated public int getContentIcon();
+    method @Deprecated public int getContentIconGravity();
+    method public boolean getContentIntentAvailableOffline();
+    method @Deprecated public int getCustomContentHeight();
+    method @Deprecated public int getCustomSizePreset();
+    method public String? getDismissalId();
+    method @Deprecated public android.app.PendingIntent? getDisplayIntent();
+    method @Deprecated public int getGravity();
+    method @Deprecated public boolean getHintAmbientBigPicture();
+    method @Deprecated public boolean getHintAvoidBackgroundClipping();
+    method public boolean getHintContentIntentLaunchesActivity();
+    method @Deprecated public boolean getHintHideIcon();
+    method @Deprecated public int getHintScreenTimeout();
+    method @Deprecated public boolean getHintShowBackgroundOnly();
+    method @Deprecated public java.util.List<android.app.Notification!> getPages();
+    method public boolean getStartScrollBottom();
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setBackground(android.graphics.Bitmap?);
+    method public androidx.core.app.NotificationCompat.WearableExtender setBridgeTag(String?);
+    method public androidx.core.app.NotificationCompat.WearableExtender setContentAction(int);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIcon(int);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setContentIconGravity(int);
+    method public androidx.core.app.NotificationCompat.WearableExtender setContentIntentAvailableOffline(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomContentHeight(int);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setCustomSizePreset(int);
+    method public androidx.core.app.NotificationCompat.WearableExtender setDismissalId(String?);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setDisplayIntent(android.app.PendingIntent?);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setGravity(int);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAmbientBigPicture(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintAvoidBackgroundClipping(boolean);
+    method public androidx.core.app.NotificationCompat.WearableExtender setHintContentIntentLaunchesActivity(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintHideIcon(boolean);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintScreenTimeout(int);
+    method @Deprecated public androidx.core.app.NotificationCompat.WearableExtender setHintShowBackgroundOnly(boolean);
+    method public androidx.core.app.NotificationCompat.WearableExtender setStartScrollBottom(boolean);
+    field @Deprecated public static final int SCREEN_TIMEOUT_LONG = -1; // 0xffffffff
+    field @Deprecated public static final int SCREEN_TIMEOUT_SHORT = 0; // 0x0
+    field @Deprecated public static final int SIZE_DEFAULT = 0; // 0x0
+    field @Deprecated public static final int SIZE_FULL_SCREEN = 5; // 0x5
+    field @Deprecated public static final int SIZE_LARGE = 4; // 0x4
+    field @Deprecated public static final int SIZE_MEDIUM = 3; // 0x3
+    field @Deprecated public static final int SIZE_SMALL = 2; // 0x2
+    field @Deprecated public static final int SIZE_XSMALL = 1; // 0x1
+    field public static final int UNSET_ACTION_INDEX = -1; // 0xffffffff
+  }
+
+  public final class NotificationCompatExtras {
+    field public static final String EXTRA_ACTION_EXTRAS = "android.support.actionExtras";
+    field public static final String EXTRA_GROUP_KEY = "android.support.groupKey";
+    field public static final String EXTRA_GROUP_SUMMARY = "android.support.isGroupSummary";
+    field public static final String EXTRA_LOCAL_ONLY = "android.support.localOnly";
+    field public static final String EXTRA_REMOTE_INPUTS = "android.support.remoteInputs";
+    field public static final String EXTRA_SORT_KEY = "android.support.sortKey";
+  }
+
+  public abstract class NotificationCompatSideChannelService extends android.app.Service {
+    ctor public NotificationCompatSideChannelService();
+    method public abstract void cancel(String!, int, String!);
+    method public abstract void cancelAll(String!);
+    method public abstract void notify(String!, int, String!, android.app.Notification!);
+    method public android.os.IBinder! onBind(android.content.Intent!);
+  }
+
+  public final class NotificationManagerCompat {
+    method public boolean areNotificationsEnabled();
+    method public void cancel(int);
+    method public void cancel(String?, int);
+    method public void cancelAll();
+    method public void createNotificationChannel(android.app.NotificationChannel);
+    method public void createNotificationChannel(androidx.core.app.NotificationChannelCompat);
+    method public void createNotificationChannelGroup(android.app.NotificationChannelGroup);
+    method public void createNotificationChannelGroup(androidx.core.app.NotificationChannelGroupCompat);
+    method public void createNotificationChannelGroups(java.util.List<android.app.NotificationChannelGroup!>);
+    method public void createNotificationChannelGroupsCompat(java.util.List<androidx.core.app.NotificationChannelGroupCompat!>);
+    method public void createNotificationChannels(java.util.List<android.app.NotificationChannel!>);
+    method public void createNotificationChannelsCompat(java.util.List<androidx.core.app.NotificationChannelCompat!>);
+    method public void deleteNotificationChannel(String);
+    method public void deleteNotificationChannelGroup(String);
+    method public void deleteUnlistedNotificationChannels(java.util.Collection<java.lang.String!>);
+    method public static androidx.core.app.NotificationManagerCompat from(android.content.Context);
+    method public static java.util.Set<java.lang.String!> getEnabledListenerPackages(android.content.Context);
+    method public int getImportance();
+    method public android.app.NotificationChannel? getNotificationChannel(String);
+    method public android.app.NotificationChannel? getNotificationChannel(String, String);
+    method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String);
+    method public androidx.core.app.NotificationChannelCompat? getNotificationChannelCompat(String, String);
+    method public android.app.NotificationChannelGroup? getNotificationChannelGroup(String);
+    method public androidx.core.app.NotificationChannelGroupCompat? getNotificationChannelGroupCompat(String);
+    method public java.util.List<android.app.NotificationChannelGroup!> getNotificationChannelGroups();
+    method public java.util.List<androidx.core.app.NotificationChannelGroupCompat!> getNotificationChannelGroupsCompat();
+    method public java.util.List<android.app.NotificationChannel!> getNotificationChannels();
+    method public java.util.List<androidx.core.app.NotificationChannelCompat!> getNotificationChannelsCompat();
+    method public void notify(int, android.app.Notification);
+    method public void notify(String?, int, android.app.Notification);
+    field public static final String ACTION_BIND_SIDE_CHANNEL = "android.support.BIND_NOTIFICATION_SIDE_CHANNEL";
+    field public static final String EXTRA_USE_SIDE_CHANNEL = "android.support.useSideChannel";
+    field public static final int IMPORTANCE_DEFAULT = 3; // 0x3
+    field public static final int IMPORTANCE_HIGH = 4; // 0x4
+    field public static final int IMPORTANCE_LOW = 2; // 0x2
+    field public static final int IMPORTANCE_MAX = 5; // 0x5
+    field public static final int IMPORTANCE_MIN = 1; // 0x1
+    field public static final int IMPORTANCE_NONE = 0; // 0x0
+    field public static final int IMPORTANCE_UNSPECIFIED = -1000; // 0xfffffc18
+  }
+
+  public class Person {
+    method @RequiresApi(28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.Person fromAndroidPerson(android.app.Person);
+    method public static androidx.core.app.Person fromBundle(android.os.Bundle);
+    method @RequiresApi(22) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.app.Person fromPersistableBundle(android.os.PersistableBundle);
+    method public androidx.core.graphics.drawable.IconCompat? getIcon();
+    method public String? getKey();
+    method public CharSequence? getName();
+    method public String? getUri();
+    method public boolean isBot();
+    method public boolean isImportant();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public String resolveToLegacyUri();
+    method @RequiresApi(28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.app.Person toAndroidPerson();
+    method public androidx.core.app.Person.Builder toBuilder();
+    method public android.os.Bundle toBundle();
+    method @RequiresApi(22) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.os.PersistableBundle toPersistableBundle();
+  }
+
+  public static class Person.Builder {
+    ctor public Person.Builder();
+    method public androidx.core.app.Person build();
+    method public androidx.core.app.Person.Builder setBot(boolean);
+    method public androidx.core.app.Person.Builder setIcon(androidx.core.graphics.drawable.IconCompat?);
+    method public androidx.core.app.Person.Builder setImportant(boolean);
+    method public androidx.core.app.Person.Builder setKey(String?);
+    method public androidx.core.app.Person.Builder setName(CharSequence?);
+    method public androidx.core.app.Person.Builder setUri(String?);
+  }
+
+  @androidx.versionedparcelable.VersionedParcelize(jetifyAs="android.support.v4.app.RemoteActionCompat") public final class RemoteActionCompat implements androidx.versionedparcelable.VersionedParcelable {
+    ctor public RemoteActionCompat(androidx.core.graphics.drawable.IconCompat, CharSequence, CharSequence, android.app.PendingIntent);
+    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public RemoteActionCompat();
+    ctor public RemoteActionCompat(androidx.core.app.RemoteActionCompat);
+    method @RequiresApi(26) public static androidx.core.app.RemoteActionCompat createFromRemoteAction(android.app.RemoteAction);
+    method public android.app.PendingIntent getActionIntent();
+    method public CharSequence getContentDescription();
+    method public androidx.core.graphics.drawable.IconCompat getIcon();
+    method public CharSequence getTitle();
+    method public boolean isEnabled();
+    method public void setEnabled(boolean);
+    method public void setShouldShowIcon(boolean);
+    method public boolean shouldShowIcon();
+    method @RequiresApi(26) public android.app.RemoteAction toRemoteAction();
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(4) public android.app.PendingIntent! mActionIntent;
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(3) public CharSequence! mContentDescription;
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(5) public boolean mEnabled;
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(1) public androidx.core.graphics.drawable.IconCompat! mIcon;
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(6) public boolean mShouldShowIcon;
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @androidx.versionedparcelable.ParcelField(2) public CharSequence! mTitle;
+  }
+
+  public final class RemoteInput {
+    method public static void addDataResultToIntent(androidx.core.app.RemoteInput!, android.content.Intent!, java.util.Map<java.lang.String!,android.net.Uri!>!);
+    method public static void addResultsToIntent(androidx.core.app.RemoteInput![]!, android.content.Intent!, android.os.Bundle!);
+    method public boolean getAllowFreeFormInput();
+    method public java.util.Set<java.lang.String!>! getAllowedDataTypes();
+    method public CharSequence![]! getChoices();
+    method public static java.util.Map<java.lang.String!,android.net.Uri!>! getDataResultsFromIntent(android.content.Intent!, String!);
+    method @androidx.core.app.RemoteInput.EditChoicesBeforeSending public int getEditChoicesBeforeSending();
+    method public android.os.Bundle! getExtras();
+    method public CharSequence! getLabel();
+    method public String! getResultKey();
+    method public static android.os.Bundle! getResultsFromIntent(android.content.Intent!);
+    method @androidx.core.app.RemoteInput.Source public static int getResultsSource(android.content.Intent);
+    method public boolean isDataOnly();
+    method public static void setResultsSource(android.content.Intent, @androidx.core.app.RemoteInput.Source int);
+    field public static final int EDIT_CHOICES_BEFORE_SENDING_AUTO = 0; // 0x0
+    field public static final int EDIT_CHOICES_BEFORE_SENDING_DISABLED = 1; // 0x1
+    field public static final int EDIT_CHOICES_BEFORE_SENDING_ENABLED = 2; // 0x2
+    field public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
+    field public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results";
+    field public static final int SOURCE_CHOICE = 1; // 0x1
+    field public static final int SOURCE_FREE_FORM_INPUT = 0; // 0x0
+  }
+
+  public static final class RemoteInput.Builder {
+    ctor public RemoteInput.Builder(String);
+    method public androidx.core.app.RemoteInput.Builder addExtras(android.os.Bundle);
+    method public androidx.core.app.RemoteInput build();
+    method public android.os.Bundle getExtras();
+    method public androidx.core.app.RemoteInput.Builder setAllowDataType(String, boolean);
+    method public androidx.core.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
+    method public androidx.core.app.RemoteInput.Builder setChoices(CharSequence![]?);
+    method public androidx.core.app.RemoteInput.Builder setEditChoicesBeforeSending(@androidx.core.app.RemoteInput.EditChoicesBeforeSending int);
+    method public androidx.core.app.RemoteInput.Builder setLabel(CharSequence?);
+  }
+
+  @IntDef({androidx.core.app.RemoteInput.EDIT_CHOICES_BEFORE_SENDING_AUTO, androidx.core.app.RemoteInput.EDIT_CHOICES_BEFORE_SENDING_DISABLED, androidx.core.app.RemoteInput.EDIT_CHOICES_BEFORE_SENDING_ENABLED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RemoteInput.EditChoicesBeforeSending {
+  }
+
+  @IntDef({androidx.core.app.RemoteInput.SOURCE_FREE_FORM_INPUT, androidx.core.app.RemoteInput.SOURCE_CHOICE}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface RemoteInput.Source {
+  }
+
+  public final class ServiceCompat {
+    method public static void stopForeground(android.app.Service, @androidx.core.app.ServiceCompat.StopForegroundFlags int);
+    field public static final int START_STICKY = 1; // 0x1
+    field public static final int STOP_FOREGROUND_DETACH = 2; // 0x2
+    field public static final int STOP_FOREGROUND_REMOVE = 1; // 0x1
+  }
+
+  @IntDef(flag=true, value={androidx.core.app.ServiceCompat.STOP_FOREGROUND_REMOVE, androidx.core.app.ServiceCompat.STOP_FOREGROUND_DETACH}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ServiceCompat.StopForegroundFlags {
+  }
+
+  public final class ShareCompat {
+    method @Deprecated public static void configureMenuItem(android.view.MenuItem, androidx.core.app.ShareCompat.IntentBuilder);
+    method @Deprecated public static void configureMenuItem(android.view.Menu, @IdRes int, androidx.core.app.ShareCompat.IntentBuilder);
+    method public static android.content.ComponentName? getCallingActivity(android.app.Activity);
+    method public static String? getCallingPackage(android.app.Activity);
+    field public static final String EXTRA_CALLING_ACTIVITY = "androidx.core.app.EXTRA_CALLING_ACTIVITY";
+    field public static final String EXTRA_CALLING_ACTIVITY_INTEROP = "android.support.v4.app.EXTRA_CALLING_ACTIVITY";
+    field public static final String EXTRA_CALLING_PACKAGE = "androidx.core.app.EXTRA_CALLING_PACKAGE";
+    field public static final String EXTRA_CALLING_PACKAGE_INTEROP = "android.support.v4.app.EXTRA_CALLING_PACKAGE";
+  }
+
+  public static class ShareCompat.IntentBuilder {
+    ctor public ShareCompat.IntentBuilder(android.content.Context);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailBcc(String![]);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailCc(String![]);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String);
+    method public androidx.core.app.ShareCompat.IntentBuilder addEmailTo(String![]);
+    method public androidx.core.app.ShareCompat.IntentBuilder addStream(android.net.Uri);
+    method public android.content.Intent createChooserIntent();
+    method @Deprecated public static androidx.core.app.ShareCompat.IntentBuilder from(android.app.Activity);
+    method public android.content.Intent getIntent();
+    method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(CharSequence?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setChooserTitle(@StringRes int);
+    method public androidx.core.app.ShareCompat.IntentBuilder setEmailBcc(String![]?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setEmailCc(String![]?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setEmailTo(String![]?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setHtmlText(String?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setStream(android.net.Uri?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setSubject(String?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setText(CharSequence?);
+    method public androidx.core.app.ShareCompat.IntentBuilder setType(String?);
+    method public void startChooser();
+  }
+
+  public static class ShareCompat.IntentReader {
+    ctor public ShareCompat.IntentReader(android.app.Activity);
+    ctor public ShareCompat.IntentReader(android.content.Context, android.content.Intent);
+    method @Deprecated public static androidx.core.app.ShareCompat.IntentReader from(android.app.Activity);
+    method public android.content.ComponentName? getCallingActivity();
+    method public android.graphics.drawable.Drawable? getCallingActivityIcon();
+    method public android.graphics.drawable.Drawable? getCallingApplicationIcon();
+    method public CharSequence? getCallingApplicationLabel();
+    method public String? getCallingPackage();
+    method public String![]? getEmailBcc();
+    method public String![]? getEmailCc();
+    method public String![]? getEmailTo();
+    method public String? getHtmlText();
+    method public android.net.Uri? getStream();
+    method public android.net.Uri? getStream(int);
+    method public int getStreamCount();
+    method public String? getSubject();
+    method public CharSequence? getText();
+    method public String? getType();
+    method public boolean isMultipleShare();
+    method public boolean isShareIntent();
+    method public boolean isSingleShare();
+  }
+
+  public abstract class SharedElementCallback {
+    ctor public SharedElementCallback();
+    method public android.os.Parcelable! onCaptureSharedElementSnapshot(android.view.View!, android.graphics.Matrix!, android.graphics.RectF!);
+    method public android.view.View! onCreateSnapshotView(android.content.Context!, android.os.Parcelable!);
+    method public void onMapSharedElements(java.util.List<java.lang.String!>!, java.util.Map<java.lang.String!,android.view.View!>!);
+    method public void onRejectSharedElements(java.util.List<android.view.View!>!);
+    method public void onSharedElementEnd(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+    method public void onSharedElementStart(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, java.util.List<android.view.View!>!);
+    method public void onSharedElementsArrived(java.util.List<java.lang.String!>!, java.util.List<android.view.View!>!, androidx.core.app.SharedElementCallback.OnSharedElementsReadyListener!);
+  }
+
+  public static interface SharedElementCallback.OnSharedElementsReadyListener {
+    method public void onSharedElementsReady();
+  }
+
+  public final class TaskStackBuilder implements java.lang.Iterable<android.content.Intent> {
+    method public androidx.core.app.TaskStackBuilder addNextIntent(android.content.Intent);
+    method public androidx.core.app.TaskStackBuilder addNextIntentWithParentStack(android.content.Intent);
+    method public androidx.core.app.TaskStackBuilder addParentStack(android.app.Activity);
+    method public androidx.core.app.TaskStackBuilder addParentStack(Class<?>);
+    method public androidx.core.app.TaskStackBuilder! addParentStack(android.content.ComponentName!);
+    method public static androidx.core.app.TaskStackBuilder create(android.content.Context);
+    method public android.content.Intent? editIntentAt(int);
+    method @Deprecated public static androidx.core.app.TaskStackBuilder! from(android.content.Context!);
+    method @Deprecated public android.content.Intent! getIntent(int);
+    method public int getIntentCount();
+    method public android.content.Intent![] getIntents();
+    method public android.app.PendingIntent? getPendingIntent(int, int);
+    method public android.app.PendingIntent? getPendingIntent(int, int, android.os.Bundle?);
+    method @Deprecated public java.util.Iterator<android.content.Intent!>! iterator();
+    method public void startActivities();
+    method public void startActivities(android.os.Bundle?);
+  }
+
+  public static interface TaskStackBuilder.SupportParentable {
+    method public android.content.Intent? getSupportParentActivityIntent();
+  }
+
+}
+
+package androidx.core.content {
+
+  public final class ContentProviderCompat {
+    method public static android.content.Context requireContext(android.content.ContentProvider);
+  }
+
+  public final class ContentResolverCompat {
+    method public static android.database.Cursor! query(android.content.ContentResolver!, android.net.Uri!, String![]!, String!, String![]!, String!, androidx.core.os.CancellationSignal!);
+  }
+
+  public class ContextCompat {
+    ctor protected ContextCompat();
+    method public static int checkSelfPermission(android.content.Context, String);
+    method public static android.content.Context? createDeviceProtectedStorageContext(android.content.Context);
+    method public static java.io.File! getCodeCacheDir(android.content.Context);
+    method @ColorInt public static int getColor(android.content.Context, @ColorRes int);
+    method public static android.content.res.ColorStateList? getColorStateList(android.content.Context, @ColorRes int);
+    method public static java.io.File? getDataDir(android.content.Context);
+    method public static android.graphics.drawable.Drawable? getDrawable(android.content.Context, @DrawableRes int);
+    method public static java.io.File![] getExternalCacheDirs(android.content.Context);
+    method public static java.io.File![] getExternalFilesDirs(android.content.Context, String?);
+    method public static java.util.concurrent.Executor! getMainExecutor(android.content.Context!);
+    method public static java.io.File? getNoBackupFilesDir(android.content.Context);
+    method public static java.io.File![] getObbDirs(android.content.Context);
+    method public static <T> T? getSystemService(android.content.Context, Class<T!>);
+    method public static String? getSystemServiceName(android.content.Context, Class<?>);
+    method public static boolean isDeviceProtectedStorage(android.content.Context);
+    method public static boolean startActivities(android.content.Context, android.content.Intent![]);
+    method public static boolean startActivities(android.content.Context, android.content.Intent![], android.os.Bundle?);
+    method public static void startActivity(android.content.Context, android.content.Intent, android.os.Bundle?);
+    method public static void startForegroundService(android.content.Context, android.content.Intent);
+  }
+
+  public class FileProvider extends android.content.ContentProvider {
+    ctor public FileProvider();
+    method public int delete(android.net.Uri, String?, String![]?);
+    method public String! getType(android.net.Uri);
+    method public static android.net.Uri! getUriForFile(android.content.Context, String, java.io.File);
+    method public static android.net.Uri getUriForFile(android.content.Context, String, java.io.File, String);
+    method public android.net.Uri! insert(android.net.Uri, android.content.ContentValues!);
+    method public boolean onCreate();
+    method public android.database.Cursor! query(android.net.Uri, String![]?, String?, String![]?, String?);
+    method public int update(android.net.Uri, android.content.ContentValues!, String?, String![]?);
+  }
+
+  public final class IntentCompat {
+    method public static android.content.Intent makeMainSelectorActivity(String, String);
+    field public static final String ACTION_CREATE_REMINDER = "android.intent.action.CREATE_REMINDER";
+    field public static final String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
+    field public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
+    field public static final String EXTRA_START_PLAYBACK = "android.intent.extra.START_PLAYBACK";
+    field public static final String EXTRA_TIME = "android.intent.extra.TIME";
+  }
+
+  public final class LocusIdCompat {
+    ctor public LocusIdCompat(String);
+    method public String getId();
+    method @RequiresApi(29) public android.content.LocusId toLocusId();
+    method @RequiresApi(29) public static androidx.core.content.LocusIdCompat toLocusIdCompat(android.content.LocusId);
+  }
+
+  public final class MimeTypeFilter {
+    method public static boolean matches(String?, String);
+    method public static String? matches(String?, String![]);
+    method public static String? matches(String![]?, String);
+    method public static String![] matchesMany(String![]?, String);
+  }
+
+  public final class PermissionChecker {
+    method @androidx.core.content.PermissionChecker.PermissionResult public static int checkCallingOrSelfPermission(android.content.Context, String);
+    method @androidx.core.content.PermissionChecker.PermissionResult public static int checkCallingPermission(android.content.Context, String, String?);
+    method @androidx.core.content.PermissionChecker.PermissionResult public static int checkPermission(android.content.Context, String, int, int, String?);
+    method @androidx.core.content.PermissionChecker.PermissionResult public static int checkSelfPermission(android.content.Context, String);
+    field public static final int PERMISSION_DENIED = -1; // 0xffffffff
+    field public static final int PERMISSION_DENIED_APP_OP = -2; // 0xfffffffe
+    field public static final int PERMISSION_GRANTED = 0; // 0x0
+  }
+
+  @IntDef({androidx.core.content.PermissionChecker.PERMISSION_GRANTED, androidx.core.content.PermissionChecker.PERMISSION_DENIED, androidx.core.content.PermissionChecker.PERMISSION_DENIED_APP_OP}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PermissionChecker.PermissionResult {
+  }
+
+  @Deprecated public final class SharedPreferencesCompat {
+  }
+
+  @Deprecated public static final class SharedPreferencesCompat.EditorCompat {
+    method @Deprecated public void apply(android.content.SharedPreferences.Editor);
+    method @Deprecated public static androidx.core.content.SharedPreferencesCompat.EditorCompat! getInstance();
+  }
+
+}
+
+package androidx.core.content.pm {
+
+  @Deprecated public final class ActivityInfoCompat {
+    field @Deprecated public static final int CONFIG_UI_MODE = 512; // 0x200
+  }
+
+  public final class PackageInfoCompat {
+    method public static long getLongVersionCode(android.content.pm.PackageInfo);
+    method public static java.util.List<android.content.pm.Signature!> getSignatures(android.content.pm.PackageManager, String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static boolean hasSignatures(android.content.pm.PackageManager, String, @Size(min=1) java.util.Map<byte[]!,java.lang.Integer!>, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
+  }
+
+  public final class PermissionInfoCompat {
+    method public static int getProtection(android.content.pm.PermissionInfo);
+    method public static int getProtectionFlags(android.content.pm.PermissionInfo);
+  }
+
+  public class ShortcutInfoCompat {
+    method public android.content.ComponentName? getActivity();
+    method public java.util.Set<java.lang.String!>? getCategories();
+    method public CharSequence? getDisabledMessage();
+    method public int getDisabledReason();
+    method public android.os.PersistableBundle? getExtras();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.core.graphics.drawable.IconCompat! getIcon();
+    method public String getId();
+    method public android.content.Intent getIntent();
+    method public android.content.Intent![] getIntents();
+    method public long getLastChangedTimestamp();
+    method public androidx.core.content.LocusIdCompat? getLocusId();
+    method public CharSequence? getLongLabel();
+    method public String getPackage();
+    method public int getRank();
+    method public CharSequence getShortLabel();
+    method public android.os.UserHandle? getUserHandle();
+    method public boolean hasKeyFieldsOnly();
+    method public boolean isCached();
+    method public boolean isDeclaredInManifest();
+    method public boolean isDynamic();
+    method public boolean isEnabled();
+    method public boolean isImmutable();
+    method public boolean isPinned();
+    method @RequiresApi(25) public android.content.pm.ShortcutInfo! toShortcutInfo();
+  }
+
+  public static class ShortcutInfoCompat.Builder {
+    ctor public ShortcutInfoCompat.Builder(android.content.Context, String);
+    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public ShortcutInfoCompat.Builder(androidx.core.content.pm.ShortcutInfoCompat);
+    ctor @RequiresApi(25) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public ShortcutInfoCompat.Builder(android.content.Context, android.content.pm.ShortcutInfo);
+    method public androidx.core.content.pm.ShortcutInfoCompat build();
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setActivity(android.content.ComponentName);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setAlwaysBadged();
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setCategories(java.util.Set<java.lang.String!>);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setDisabledMessage(CharSequence);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setExtras(android.os.PersistableBundle);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIcon(androidx.core.graphics.drawable.IconCompat!);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntent(android.content.Intent);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIntents(android.content.Intent![]);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setIsConversation();
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLocusId(androidx.core.content.LocusIdCompat?);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLabel(CharSequence);
+    method @Deprecated public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived();
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setLongLived(boolean);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPerson(androidx.core.app.Person);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setPersons(androidx.core.app.Person![]);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setRank(int);
+    method public androidx.core.content.pm.ShortcutInfoCompat.Builder setShortLabel(CharSequence);
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public abstract class ShortcutInfoCompatSaver<T> {
+    ctor public ShortcutInfoCompatSaver();
+    method @AnyThread public abstract T! addShortcuts(java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>!);
+    method @WorkerThread public java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>! getShortcuts() throws java.lang.Exception;
+    method @AnyThread public abstract T! removeAllShortcuts();
+    method @AnyThread public abstract T! removeShortcuts(java.util.List<java.lang.String!>!);
+  }
+
+  public class ShortcutManagerCompat {
+    method public static boolean addDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+    method public static android.content.Intent createShortcutResultIntent(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+    method public static void disableShortcuts(android.content.Context, java.util.List<java.lang.String!>, CharSequence?);
+    method public static void enableShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+    method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getDynamicShortcuts(android.content.Context);
+    method public static int getIconMaxHeight(android.content.Context);
+    method public static int getIconMaxWidth(android.content.Context);
+    method public static int getMaxShortcutCountPerActivity(android.content.Context);
+    method public static java.util.List<androidx.core.content.pm.ShortcutInfoCompat!> getShortcuts(android.content.Context, @androidx.core.content.pm.ShortcutManagerCompat.ShortcutMatchFlags int);
+    method public static boolean isRateLimitingActive(android.content.Context);
+    method public static boolean isRequestPinShortcutSupported(android.content.Context);
+    method public static boolean pushDynamicShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat);
+    method public static void removeAllDynamicShortcuts(android.content.Context);
+    method public static void removeDynamicShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+    method public static void removeLongLivedShortcuts(android.content.Context, java.util.List<java.lang.String!>);
+    method public static void reportShortcutUsed(android.content.Context, String);
+    method public static boolean requestPinShortcut(android.content.Context, androidx.core.content.pm.ShortcutInfoCompat, android.content.IntentSender?);
+    method public static boolean setDynamicShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+    method public static boolean updateShortcuts(android.content.Context, java.util.List<androidx.core.content.pm.ShortcutInfoCompat!>);
+    field public static final String EXTRA_SHORTCUT_ID = "android.intent.extra.shortcut.ID";
+    field public static final int FLAG_MATCH_CACHED = 8; // 0x8
+    field public static final int FLAG_MATCH_DYNAMIC = 2; // 0x2
+    field public static final int FLAG_MATCH_MANIFEST = 1; // 0x1
+    field public static final int FLAG_MATCH_PINNED = 4; // 0x4
+  }
+
+  @IntDef(flag=true, value={androidx.core.content.pm.ShortcutManagerCompat.FLAG_MATCH_MANIFEST, androidx.core.content.pm.ShortcutManagerCompat.FLAG_MATCH_DYNAMIC, androidx.core.content.pm.ShortcutManagerCompat.FLAG_MATCH_PINNED, androidx.core.content.pm.ShortcutManagerCompat.FLAG_MATCH_CACHED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ShortcutManagerCompat.ShortcutMatchFlags {
+  }
+
+}
+
+package androidx.core.content.res {
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class ColorStateListInflaterCompat {
+    method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static android.content.res.ColorStateList createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static android.content.res.ColorStateList? inflate(android.content.res.Resources, @XmlRes int, android.content.res.Resources.Theme?);
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class ComplexColorCompat {
+    method @ColorInt public int getColor();
+    method public android.graphics.Shader? getShader();
+    method public static androidx.core.content.res.ComplexColorCompat? inflate(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?);
+    method public boolean isGradient();
+    method public boolean isStateful();
+    method public boolean onStateChanged(int[]!);
+    method public void setColor(@ColorInt int);
+    method public boolean willDraw();
+  }
+
+  public final class ConfigurationHelper {
+    method public static int getDensityDpi(android.content.res.Resources);
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class FontResourcesParserCompat {
+    method public static androidx.core.content.res.FontResourcesParserCompat.FamilyResourceEntry? parse(org.xmlpull.v1.XmlPullParser!, android.content.res.Resources!) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static java.util.List<java.util.List<byte[]!>!>! readCerts(android.content.res.Resources!, @ArrayRes int);
+    field public static final int FETCH_STRATEGY_ASYNC = 1; // 0x1
+    field public static final int FETCH_STRATEGY_BLOCKING = 0; // 0x0
+    field public static final int INFINITE_TIMEOUT_VALUE = -1; // 0xffffffff
+  }
+
+  public static interface FontResourcesParserCompat.FamilyResourceEntry {
+  }
+
+  @IntDef({androidx.core.content.res.FontResourcesParserCompat.FETCH_STRATEGY_BLOCKING, androidx.core.content.res.FontResourcesParserCompat.FETCH_STRATEGY_ASYNC}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface FontResourcesParserCompat.FetchStrategy {
+  }
+
+  public static final class FontResourcesParserCompat.FontFamilyFilesResourceEntry implements androidx.core.content.res.FontResourcesParserCompat.FamilyResourceEntry {
+    ctor public FontResourcesParserCompat.FontFamilyFilesResourceEntry(androidx.core.content.res.FontResourcesParserCompat.FontFileResourceEntry![]);
+    method public androidx.core.content.res.FontResourcesParserCompat.FontFileResourceEntry![] getEntries();
+  }
+
+  public static final class FontResourcesParserCompat.FontFileResourceEntry {
+    ctor public FontResourcesParserCompat.FontFileResourceEntry(String, int, boolean, String?, int, int);
+    method public String getFileName();
+    method public int getResourceId();
+    method public int getTtcIndex();
+    method public String? getVariationSettings();
+    method public int getWeight();
+    method public boolean isItalic();
+  }
+
+  public static final class FontResourcesParserCompat.ProviderResourceEntry implements androidx.core.content.res.FontResourcesParserCompat.FamilyResourceEntry {
+    ctor public FontResourcesParserCompat.ProviderResourceEntry(androidx.core.provider.FontRequest, @androidx.core.content.res.FontResourcesParserCompat.FetchStrategy int, int);
+    method @androidx.core.content.res.FontResourcesParserCompat.FetchStrategy public int getFetchStrategy();
+    method public androidx.core.provider.FontRequest getRequest();
+    method public int getTimeout();
+  }
+
+  public final class ResourcesCompat {
+    method public static android.graphics.Typeface? getCachedFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+    method @ColorInt public static int getColor(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+    method public static android.content.res.ColorStateList? getColorStateList(android.content.res.Resources, @ColorRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+    method public static android.graphics.drawable.Drawable? getDrawable(android.content.res.Resources, @DrawableRes int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+    method public static android.graphics.drawable.Drawable? getDrawableForDensity(android.content.res.Resources, @DrawableRes int, int, android.content.res.Resources.Theme?) throws android.content.res.Resources.NotFoundException;
+    method public static float getFloat(android.content.res.Resources, @DimenRes int);
+    method public static android.graphics.Typeface? getFont(android.content.Context, @FontRes int) throws android.content.res.Resources.NotFoundException;
+    method public static void getFont(android.content.Context, @FontRes int, androidx.core.content.res.ResourcesCompat.FontCallback, android.os.Handler?) throws android.content.res.Resources.NotFoundException;
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface! getFont(android.content.Context, @FontRes int, android.util.TypedValue!, int, androidx.core.content.res.ResourcesCompat.FontCallback?) throws android.content.res.Resources.NotFoundException;
+    field @AnyRes public static final int ID_NULL = 0; // 0x0
+  }
+
+  public abstract static class ResourcesCompat.FontCallback {
+    ctor public ResourcesCompat.FontCallback();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final void callbackFailAsync(@androidx.core.provider.FontsContractCompat.FontRequestCallback.FontRequestFailReason int, android.os.Handler?);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final void callbackSuccessAsync(android.graphics.Typeface!, android.os.Handler?);
+    method public abstract void onFontRetrievalFailed(@androidx.core.provider.FontsContractCompat.FontRequestCallback.FontRequestFailReason int);
+    method public abstract void onFontRetrieved(android.graphics.Typeface);
+  }
+
+  public static final class ResourcesCompat.ThemeCompat {
+    method public static void rebase(android.content.res.Resources.Theme);
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class TypedArrayUtils {
+    method public static int getAttr(android.content.Context, int, int);
+    method public static boolean getBoolean(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int, boolean);
+    method public static android.graphics.drawable.Drawable? getDrawable(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int);
+    method public static int getInt(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int, int);
+    method public static boolean getNamedBoolean(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int, boolean);
+    method @ColorInt public static int getNamedColor(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int, @ColorInt int);
+    method public static android.content.res.ColorStateList? getNamedColorStateList(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme?, String, @StyleableRes int);
+    method public static androidx.core.content.res.ComplexColorCompat! getNamedComplexColor(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme?, String, @StyleableRes int, @ColorInt int);
+    method public static float getNamedFloat(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int, float);
+    method public static int getNamedInt(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int, int);
+    method @AnyRes public static int getNamedResourceId(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int, @AnyRes int);
+    method public static String? getNamedString(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, @StyleableRes int);
+    method @AnyRes public static int getResourceId(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int, @AnyRes int);
+    method public static String? getString(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int);
+    method public static CharSequence? getText(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int);
+    method public static CharSequence![]? getTextArray(android.content.res.TypedArray, @StyleableRes int, @StyleableRes int);
+    method public static boolean hasAttribute(org.xmlpull.v1.XmlPullParser, String);
+    method public static android.content.res.TypedArray obtainAttributes(android.content.res.Resources, android.content.res.Resources.Theme?, android.util.AttributeSet, int[]);
+    method public static android.util.TypedValue? peekNamedValue(android.content.res.TypedArray, org.xmlpull.v1.XmlPullParser, String, int);
+  }
+
+}
+
+package androidx.core.database {
+
+  public final class CursorWindowCompat {
+    method public static android.database.CursorWindow create(String?, long);
+  }
+
+  @Deprecated public final class DatabaseUtilsCompat {
+    method @Deprecated public static String![]! appendSelectionArgs(String![]!, String![]!);
+    method @Deprecated public static String! concatenateWhere(String!, String!);
+  }
+
+}
+
+package androidx.core.database.sqlite {
+
+  public final class SQLiteCursorCompat {
+    method public static void setFillWindowForwardOnly(android.database.sqlite.SQLiteCursor, boolean);
+  }
+
+}
+
+package androidx.core.graphics {
+
+  public final class BitmapCompat {
+    method public static int getAllocationByteCount(android.graphics.Bitmap);
+    method public static boolean hasMipMap(android.graphics.Bitmap);
+    method public static void setHasMipMap(android.graphics.Bitmap, boolean);
+  }
+
+  public class BlendModeColorFilterCompat {
+    method public static android.graphics.ColorFilter? createBlendModeColorFilterCompat(int, androidx.core.graphics.BlendModeCompat);
+  }
+
+  public enum BlendModeCompat {
+    enum_constant public static final androidx.core.graphics.BlendModeCompat CLEAR;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_BURN;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat COLOR_DODGE;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DARKEN;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat DIFFERENCE;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DST;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DST_ATOP;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DST_IN;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OUT;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat DST_OVER;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat EXCLUSION;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HARD_LIGHT;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat HUE;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat LIGHTEN;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat LUMINOSITY;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat MODULATE;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat MULTIPLY;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat OVERLAY;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat PLUS;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SATURATION;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SCREEN;
+    enum_constant @RequiresApi(android.os.Build.VERSION_CODES.Q) public static final androidx.core.graphics.BlendModeCompat SOFT_LIGHT;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SRC;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_ATOP;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_IN;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OUT;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat SRC_OVER;
+    enum_constant public static final androidx.core.graphics.BlendModeCompat XOR;
+  }
+
+  public final class ColorUtils {
+    method @ColorInt public static int HSLToColor(float[]);
+    method @ColorInt public static int LABToColor(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double);
+    method public static void LABToXYZ(@FloatRange(from=0.0f, to=100) double, @FloatRange(from=0xffffff80, to=127) double, @FloatRange(from=0xffffff80, to=127) double, double[]);
+    method public static void RGBToHSL(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, float[]);
+    method public static void RGBToLAB(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+    method public static void RGBToXYZ(@IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, @IntRange(from=0, to=255) int, double[]);
+    method @ColorInt public static int XYZToColor(@FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_X) double, @FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_Y) double, @FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_Z) double);
+    method public static void XYZToLAB(@FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_X) double, @FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_Y) double, @FloatRange(from=0.0f, to=androidx.core.graphics.ColorUtils.XYZ_WHITE_REFERENCE_Z) double, double[]);
+    method @ColorInt public static int blendARGB(@ColorInt int, @ColorInt int, @FloatRange(from=0.0, to=1.0) float);
+    method public static void blendHSL(float[], float[], @FloatRange(from=0.0, to=1.0) float, float[]);
+    method public static void blendLAB(double[], double[], @FloatRange(from=0.0, to=1.0) double, double[]);
+    method public static double calculateContrast(@ColorInt int, @ColorInt int);
+    method @FloatRange(from=0.0, to=1.0) public static double calculateLuminance(@ColorInt int);
+    method public static int calculateMinimumAlpha(@ColorInt int, @ColorInt int, float);
+    method public static void colorToHSL(@ColorInt int, float[]);
+    method public static void colorToLAB(@ColorInt int, double[]);
+    method public static void colorToXYZ(@ColorInt int, double[]);
+    method public static int compositeColors(@ColorInt int, @ColorInt int);
+    method @RequiresApi(26) public static android.graphics.Color compositeColors(android.graphics.Color, android.graphics.Color);
+    method public static double distanceEuclidean(double[], double[]);
+    method @ColorInt public static int setAlphaComponent(@ColorInt int, @IntRange(from=0, to=255) int);
+  }
+
+  public final class Insets {
+    method public static androidx.core.graphics.Insets add(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+    method public static androidx.core.graphics.Insets max(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+    method public static androidx.core.graphics.Insets min(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+    method public static androidx.core.graphics.Insets of(int, int, int, int);
+    method public static androidx.core.graphics.Insets of(android.graphics.Rect);
+    method public static androidx.core.graphics.Insets subtract(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+    method @RequiresApi(api=29) public static androidx.core.graphics.Insets toCompatInsets(android.graphics.Insets);
+    method @RequiresApi(api=29) public android.graphics.Insets toPlatformInsets();
+    method @Deprecated @RequiresApi(api=29) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.graphics.Insets wrap(android.graphics.Insets);
+    field public static final androidx.core.graphics.Insets NONE;
+    field public final int bottom;
+    field public final int left;
+    field public final int right;
+    field public final int top;
+  }
+
+  public final class PaintCompat {
+    method public static boolean hasGlyph(android.graphics.Paint, String);
+    method public static boolean setBlendMode(android.graphics.Paint, androidx.core.graphics.BlendModeCompat?);
+  }
+
+  public final class PathSegment {
+    ctor public PathSegment(android.graphics.PointF, float, android.graphics.PointF, float);
+    method public android.graphics.PointF getEnd();
+    method public float getEndFraction();
+    method public android.graphics.PointF getStart();
+    method public float getStartFraction();
+  }
+
+  public final class PathUtils {
+    method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path);
+    method @RequiresApi(26) public static java.util.Collection<androidx.core.graphics.PathSegment!> flatten(android.graphics.Path, @FloatRange(from=0) float);
+  }
+
+  public class TypefaceCompat {
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @VisibleForTesting public static void clearCache();
+    method public static android.graphics.Typeface create(android.content.Context, android.graphics.Typeface?, int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface? createFromFontInfo(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![], int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface? createFromResourcesFamilyXml(android.content.Context, androidx.core.content.res.FontResourcesParserCompat.FamilyResourceEntry, android.content.res.Resources, int, int, androidx.core.content.res.ResourcesCompat.FontCallback?, android.os.Handler?, boolean);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface? createFromResourcesFontFile(android.content.Context, android.content.res.Resources, int, String!, int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface? findFromCache(android.content.res.Resources, int, int);
+  }
+
+  @RequiresApi(26) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class TypefaceCompatApi26Impl {
+    ctor public TypefaceCompatApi26Impl();
+    method protected android.graphics.Typeface? createFromFamiliesWithDefault(Object!);
+    method public android.graphics.Typeface? createFromFontFamilyFilesResourceEntry(android.content.Context!, androidx.core.content.res.FontResourcesParserCompat.FontFamilyFilesResourceEntry!, android.content.res.Resources!, int);
+    method public android.graphics.Typeface? createFromFontInfo(android.content.Context!, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![], int);
+    method public android.graphics.Typeface? createFromResourcesFontFile(android.content.Context!, android.content.res.Resources!, int, String!, int);
+    method protected java.lang.reflect.Method! obtainAbortCreationMethod(Class<?>!) throws java.lang.NoSuchMethodException;
+    method protected java.lang.reflect.Method! obtainAddFontFromAssetManagerMethod(Class<?>!) throws java.lang.NoSuchMethodException;
+    method protected java.lang.reflect.Method! obtainAddFontFromBufferMethod(Class<?>!) throws java.lang.NoSuchMethodException;
+    method protected java.lang.reflect.Method! obtainCreateFromFamiliesWithDefaultMethod(Class<?>!) throws java.lang.NoSuchMethodException;
+    method protected Class<?>! obtainFontFamily() throws java.lang.ClassNotFoundException;
+    method protected java.lang.reflect.Constructor<?>! obtainFontFamilyCtor(Class<?>!) throws java.lang.NoSuchMethodException;
+    method protected java.lang.reflect.Method! obtainFreezeMethod(Class<?>!) throws java.lang.NoSuchMethodException;
+    field protected final java.lang.reflect.Method! mAbortCreation;
+    field protected final java.lang.reflect.Method! mAddFontFromAssetManager;
+    field protected final java.lang.reflect.Method! mAddFontFromBuffer;
+    field protected final java.lang.reflect.Method! mCreateFromFamiliesWithDefault;
+    field protected final Class<?>! mFontFamily;
+    field protected final java.lang.reflect.Constructor<?>! mFontFamilyCtor;
+    field protected final java.lang.reflect.Method! mFreeze;
+  }
+
+  @RequiresApi(28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class TypefaceCompatApi28Impl extends androidx.core.graphics.TypefaceCompatApi26Impl {
+    ctor public TypefaceCompatApi28Impl();
+  }
+
+  @RequiresApi(29) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public class TypefaceCompatApi29Impl {
+    ctor public TypefaceCompatApi29Impl();
+    method public android.graphics.Typeface? createFromFontFamilyFilesResourceEntry(android.content.Context!, androidx.core.content.res.FontResourcesParserCompat.FontFamilyFilesResourceEntry!, android.content.res.Resources!, int);
+    method public android.graphics.Typeface? createFromFontInfo(android.content.Context!, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![], int);
+    method protected android.graphics.Typeface! createFromInputStream(android.content.Context!, java.io.InputStream!);
+    method public android.graphics.Typeface? createFromResourcesFontFile(android.content.Context!, android.content.res.Resources!, int, String!, int);
+    method protected androidx.core.provider.FontsContractCompat.FontInfo! findBestInfo(androidx.core.provider.FontsContractCompat.FontInfo![]!, int);
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class TypefaceCompatUtil {
+    method public static void closeQuietly(java.io.Closeable!);
+    method @RequiresApi(19) public static java.nio.ByteBuffer? copyToDirectBuffer(android.content.Context!, android.content.res.Resources!, int);
+    method public static boolean copyToFile(java.io.File!, java.io.InputStream!);
+    method public static boolean copyToFile(java.io.File!, android.content.res.Resources!, int);
+    method public static java.io.File? getTempFile(android.content.Context!);
+    method @RequiresApi(19) public static java.nio.ByteBuffer? mmap(android.content.Context!, android.os.CancellationSignal!, android.net.Uri!);
+  }
+
+}
+
+package androidx.core.graphics.drawable {
+
+  public final class DrawableCompat {
+    method public static void applyTheme(android.graphics.drawable.Drawable, android.content.res.Resources.Theme);
+    method public static boolean canApplyTheme(android.graphics.drawable.Drawable);
+    method public static void clearColorFilter(android.graphics.drawable.Drawable);
+    method public static int getAlpha(android.graphics.drawable.Drawable);
+    method public static android.graphics.ColorFilter! getColorFilter(android.graphics.drawable.Drawable);
+    method public static int getLayoutDirection(android.graphics.drawable.Drawable);
+    method public static void inflate(android.graphics.drawable.Drawable, android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme?) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static boolean isAutoMirrored(android.graphics.drawable.Drawable);
+    method @Deprecated public static void jumpToCurrentState(android.graphics.drawable.Drawable);
+    method public static void setAutoMirrored(android.graphics.drawable.Drawable, boolean);
+    method public static void setHotspot(android.graphics.drawable.Drawable, float, float);
+    method public static void setHotspotBounds(android.graphics.drawable.Drawable, int, int, int, int);
+    method public static boolean setLayoutDirection(android.graphics.drawable.Drawable, int);
+    method public static void setTint(android.graphics.drawable.Drawable, @ColorInt int);
+    method public static void setTintList(android.graphics.drawable.Drawable, android.content.res.ColorStateList?);
+    method public static void setTintMode(android.graphics.drawable.Drawable, android.graphics.PorterDuff.Mode);
+    method public static <T extends android.graphics.drawable.Drawable> T! unwrap(android.graphics.drawable.Drawable);
+    method public static android.graphics.drawable.Drawable! wrap(android.graphics.drawable.Drawable);
+  }
+
+  @androidx.versionedparcelable.VersionedParcelize(allowSerialization=true, ignoreParcelables=true, isCustom=true, jetifyAs="android.support.v4.graphics.drawable.IconCompat") public class IconCompat extends androidx.versionedparcelable.CustomVersionedParcelable {
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void addToShortcutIntent(android.content.Intent, android.graphics.drawable.Drawable?, android.content.Context);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void checkResource(android.content.Context);
+    method public static androidx.core.graphics.drawable.IconCompat? createFromBundle(android.os.Bundle);
+    method @RequiresApi(23) public static androidx.core.graphics.drawable.IconCompat? createFromIcon(android.content.Context, android.graphics.drawable.Icon);
+    method @RequiresApi(23) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.graphics.drawable.IconCompat? createFromIcon(android.graphics.drawable.Icon);
+    method @RequiresApi(23) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.graphics.drawable.IconCompat? createFromIconOrNullIfZeroResId(android.graphics.drawable.Icon);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithAdaptiveBitmap(android.graphics.Bitmap!);
+    method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(String);
+    method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmapContentUri(android.net.Uri);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithBitmap(android.graphics.Bitmap!);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithContentUri(String!);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithContentUri(android.net.Uri!);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithData(byte[]!, int, int);
+    method public static androidx.core.graphics.drawable.IconCompat! createWithResource(android.content.Context!, @DrawableRes int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.graphics.drawable.IconCompat! createWithResource(android.content.res.Resources!, String!, @DrawableRes int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.graphics.Bitmap? getBitmap();
+    method @IdRes public int getResId();
+    method public String getResPackage();
+    method public int getType();
+    method public android.net.Uri getUri();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public java.io.InputStream? getUriInputStream(android.content.Context);
+    method public android.graphics.drawable.Drawable? loadDrawable(android.content.Context);
+    method public androidx.core.graphics.drawable.IconCompat! setTint(@ColorInt int);
+    method public androidx.core.graphics.drawable.IconCompat! setTintList(android.content.res.ColorStateList!);
+    method public androidx.core.graphics.drawable.IconCompat! setTintMode(android.graphics.PorterDuff.Mode!);
+    method public android.os.Bundle toBundle();
+    method @Deprecated @RequiresApi(23) public android.graphics.drawable.Icon toIcon();
+    method @RequiresApi(23) public android.graphics.drawable.Icon toIcon(android.content.Context?);
+    field public static final int TYPE_ADAPTIVE_BITMAP = 5; // 0x5
+    field public static final int TYPE_BITMAP = 1; // 0x1
+    field public static final int TYPE_DATA = 3; // 0x3
+    field public static final int TYPE_RESOURCE = 2; // 0x2
+    field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
+    field public static final int TYPE_URI = 4; // 0x4
+    field public static final int TYPE_URI_ADAPTIVE_BITMAP = 6; // 0x6
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @androidx.versionedparcelable.ParcelField(value=1, defaultValue="androidx.core.graphics.drawable.IconCompat.TYPE_UNKNOWN") public int mType;
+  }
+
+  public abstract class RoundedBitmapDrawable extends android.graphics.drawable.Drawable {
+    method public void draw(android.graphics.Canvas);
+    method public final android.graphics.Bitmap? getBitmap();
+    method public float getCornerRadius();
+    method public int getGravity();
+    method public int getOpacity();
+    method public final android.graphics.Paint getPaint();
+    method public boolean hasAntiAlias();
+    method public boolean hasMipMap();
+    method public boolean isCircular();
+    method public void setAlpha(int);
+    method public void setAntiAlias(boolean);
+    method public void setCircular(boolean);
+    method public void setColorFilter(android.graphics.ColorFilter!);
+    method public void setCornerRadius(float);
+    method public void setDither(boolean);
+    method public void setGravity(int);
+    method public void setMipMap(boolean);
+    method public void setTargetDensity(android.graphics.Canvas);
+    method public void setTargetDensity(android.util.DisplayMetrics);
+    method public void setTargetDensity(int);
+  }
+
+  public final class RoundedBitmapDrawableFactory {
+    method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, android.graphics.Bitmap?);
+    method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, String);
+    method public static androidx.core.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.io.InputStream);
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface TintAwareDrawable {
+    method public void setTint(@ColorInt int);
+    method public void setTintList(android.content.res.ColorStateList!);
+    method public void setTintMode(android.graphics.PorterDuff.Mode!);
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface WrappedDrawable {
+    method public android.graphics.drawable.Drawable! getWrappedDrawable();
+    method public void setWrappedDrawable(android.graphics.drawable.Drawable!);
+  }
+
+}
+
+package androidx.core.hardware.display {
+
+  public final class DisplayManagerCompat {
+    method public android.view.Display? getDisplay(int);
+    method public android.view.Display![] getDisplays();
+    method public android.view.Display![] getDisplays(String?);
+    method public static androidx.core.hardware.display.DisplayManagerCompat getInstance(android.content.Context);
+    field public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
+  }
+
+}
+
+package androidx.core.hardware.fingerprint {
+
+  @Deprecated public class FingerprintManagerCompat {
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public void authenticate(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject?, int, androidx.core.os.CancellationSignal?, androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationCallback, android.os.Handler?);
+    method @Deprecated public static androidx.core.hardware.fingerprint.FingerprintManagerCompat from(android.content.Context);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
+  }
+
+  @Deprecated public abstract static class FingerprintManagerCompat.AuthenticationCallback {
+    ctor @Deprecated public FingerprintManagerCompat.AuthenticationCallback();
+    method @Deprecated public void onAuthenticationError(int, CharSequence!);
+    method @Deprecated public void onAuthenticationFailed();
+    method @Deprecated public void onAuthenticationHelp(int, CharSequence!);
+    method @Deprecated public void onAuthenticationSucceeded(androidx.core.hardware.fingerprint.FingerprintManagerCompat.AuthenticationResult!);
+  }
+
+  @Deprecated public static final class FingerprintManagerCompat.AuthenticationResult {
+    ctor @Deprecated public FingerprintManagerCompat.AuthenticationResult(androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject!);
+    method @Deprecated public androidx.core.hardware.fingerprint.FingerprintManagerCompat.CryptoObject! getCryptoObject();
+  }
+
+  @Deprecated public static class FingerprintManagerCompat.CryptoObject {
+    ctor @Deprecated public FingerprintManagerCompat.CryptoObject(java.security.Signature);
+    ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Cipher);
+    ctor @Deprecated public FingerprintManagerCompat.CryptoObject(javax.crypto.Mac);
+    method @Deprecated public javax.crypto.Cipher? getCipher();
+    method @Deprecated public javax.crypto.Mac? getMac();
+    method @Deprecated public java.security.Signature? getSignature();
+  }
+
+}
+
+package androidx.core.internal.view {
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface SupportMenu extends android.view.Menu {
+    method public void setGroupDividerEnabled(boolean);
+    field public static final int CATEGORY_MASK = -65536; // 0xffff0000
+    field public static final int CATEGORY_SHIFT = 16; // 0x10
+    field public static final int FLAG_KEEP_OPEN_ON_SUBMENU_OPENED = 4; // 0x4
+    field public static final int SUPPORTED_MODIFIERS_MASK = 69647; // 0x1100f
+    field public static final int USER_MASK = 65535; // 0xffff
+    field public static final int USER_SHIFT = 0; // 0x0
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface SupportMenuItem extends android.view.MenuItem {
+    method public int getAlphabeticModifiers();
+    method public CharSequence! getContentDescription();
+    method public android.content.res.ColorStateList! getIconTintList();
+    method public android.graphics.PorterDuff.Mode! getIconTintMode();
+    method public int getNumericModifiers();
+    method public androidx.core.view.ActionProvider! getSupportActionProvider();
+    method public CharSequence! getTooltipText();
+    method public boolean requiresActionButton();
+    method public boolean requiresOverflow();
+    method public android.view.MenuItem! setAlphabeticShortcut(char, int);
+    method public androidx.core.internal.view.SupportMenuItem! setContentDescription(CharSequence!);
+    method public android.view.MenuItem! setIconTintList(android.content.res.ColorStateList!);
+    method public android.view.MenuItem! setIconTintMode(android.graphics.PorterDuff.Mode!);
+    method public android.view.MenuItem! setNumericShortcut(char, int);
+    method public android.view.MenuItem! setShortcut(char, char, int, int);
+    method public androidx.core.internal.view.SupportMenuItem! setSupportActionProvider(androidx.core.view.ActionProvider!);
+    method public androidx.core.internal.view.SupportMenuItem! setTooltipText(CharSequence!);
+    field public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+    field public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+    field public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+    field public static final int SHOW_AS_ACTION_NEVER = 0; // 0x0
+    field public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface SupportSubMenu extends androidx.core.internal.view.SupportMenu android.view.SubMenu {
+  }
+
+}
+
+package androidx.core.location {
+
+  public abstract class GnssStatusCompat {
+    method @FloatRange(from=0, to=360) public abstract float getAzimuthDegrees(@IntRange(from=0) int);
+    method @FloatRange(from=0, to=63) public abstract float getBasebandCn0DbHz(@IntRange(from=0) int);
+    method @FloatRange(from=0) public abstract float getCarrierFrequencyHz(@IntRange(from=0) int);
+    method @FloatRange(from=0, to=63) public abstract float getCn0DbHz(@IntRange(from=0) int);
+    method public abstract int getConstellationType(@IntRange(from=0) int);
+    method @FloatRange(from=0xffffffa6, to=90) public abstract float getElevationDegrees(@IntRange(from=0) int);
+    method @IntRange(from=0) public abstract int getSatelliteCount();
+    method @IntRange(from=1, to=200) public abstract int getSvid(@IntRange(from=0) int);
+    method public abstract boolean hasAlmanacData(@IntRange(from=0) int);
+    method public abstract boolean hasBasebandCn0DbHz(@IntRange(from=0) int);
+    method public abstract boolean hasCarrierFrequencyHz(@IntRange(from=0) int);
+    method public abstract boolean hasEphemerisData(@IntRange(from=0) int);
+    method public abstract boolean usedInFix(@IntRange(from=0) int);
+    method @RequiresApi(android.os.Build.VERSION_CODES.N) public static androidx.core.location.GnssStatusCompat wrap(android.location.GnssStatus);
+    method public static androidx.core.location.GnssStatusCompat wrap(android.location.GpsStatus);
+    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+    field public static final int CONSTELLATION_GPS = 1; // 0x1
+    field public static final int CONSTELLATION_IRNSS = 7; // 0x7
+    field public static final int CONSTELLATION_QZSS = 4; // 0x4
+    field public static final int CONSTELLATION_SBAS = 2; // 0x2
+    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
+  }
+
+  public abstract static class GnssStatusCompat.Callback {
+    ctor public GnssStatusCompat.Callback();
+    method public void onFirstFix(@IntRange(from=0) int);
+    method public void onSatelliteStatusChanged(androidx.core.location.GnssStatusCompat);
+    method public void onStarted();
+    method public void onStopped();
+  }
+
+  public final class LocationManagerCompat {
+    method public static boolean isLocationEnabled(android.location.LocationManager);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback, android.os.Handler);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static boolean registerGnssStatusCallback(android.location.LocationManager, java.util.concurrent.Executor, androidx.core.location.GnssStatusCompat.Callback);
+    method public static void unregisterGnssStatusCallback(android.location.LocationManager, androidx.core.location.GnssStatusCompat.Callback);
+  }
+
+}
+
+package androidx.core.math {
+
+  public class MathUtils {
+    method public static float clamp(float, float, float);
+    method public static double clamp(double, double, double);
+    method public static int clamp(int, int, int);
+    method public static long clamp(long, long, long);
+  }
+
+}
+
+package androidx.core.net {
+
+  public final class ConnectivityManagerCompat {
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static android.net.NetworkInfo? getNetworkInfoFromBroadcast(android.net.ConnectivityManager, android.content.Intent);
+    method @androidx.core.net.ConnectivityManagerCompat.RestrictBackgroundStatus public static int getRestrictBackgroundStatus(android.net.ConnectivityManager);
+    method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public static boolean isActiveNetworkMetered(android.net.ConnectivityManager);
+    field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+    field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+    field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
+  }
+
+  @IntDef({androidx.core.net.ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_DISABLED, androidx.core.net.ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_WHITELISTED, androidx.core.net.ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_ENABLED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ConnectivityManagerCompat.RestrictBackgroundStatus {
+  }
+
+  public final class MailTo {
+    method public String? getBcc();
+    method public String? getBody();
+    method public String? getCc();
+    method public java.util.Map<java.lang.String!,java.lang.String!>? getHeaders();
+    method public String? getSubject();
+    method public String? getTo();
+    method public static boolean isMailTo(String?);
+    method public static boolean isMailTo(android.net.Uri?);
+    method public static androidx.core.net.MailTo parse(String) throws androidx.core.net.ParseException;
+    method public static androidx.core.net.MailTo parse(android.net.Uri) throws androidx.core.net.ParseException;
+    field public static final String MAILTO_SCHEME = "mailto:";
+  }
+
+  public class ParseException extends java.lang.RuntimeException {
+    field public final String response;
+  }
+
+  public final class TrafficStatsCompat {
+    method @Deprecated public static void clearThreadStatsTag();
+    method @Deprecated public static int getThreadStatsTag();
+    method @Deprecated public static void incrementOperationCount(int);
+    method @Deprecated public static void incrementOperationCount(int, int);
+    method @Deprecated public static void setThreadStatsTag(int);
+    method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+    method @Deprecated public static void tagSocket(java.net.Socket!) throws java.net.SocketException;
+    method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
+    method @Deprecated public static void untagSocket(java.net.Socket!) throws java.net.SocketException;
+  }
+
+  public final class UriCompat {
+    method public static String toSafeString(android.net.Uri);
+  }
+
+}
+
+package androidx.core.os {
+
+  public class BuildCompat {
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N) public static boolean isAtLeastN();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.N_MR1) public static boolean isAtLeastNMR1();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O) public static boolean isAtLeastO();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.O_MR1) public static boolean isAtLeastOMR1();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.P) public static boolean isAtLeastP();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.Q) public static boolean isAtLeastQ();
+    method @Deprecated @ChecksSdkIntAtLeast(api=android.os.Build.VERSION_CODES.R) public static boolean isAtLeastR();
+    method @ChecksSdkIntAtLeast(codename="S") public static boolean isAtLeastS();
+  }
+
+  public final class CancellationSignal {
+    ctor public CancellationSignal();
+    method public void cancel();
+    method public Object? getCancellationSignalObject();
+    method public boolean isCanceled();
+    method public void setOnCancelListener(androidx.core.os.CancellationSignal.OnCancelListener?);
+    method public void throwIfCanceled();
+  }
+
+  public static interface CancellationSignal.OnCancelListener {
+    method public void onCancel();
+  }
+
+  public final class ConfigurationCompat {
+    method public static androidx.core.os.LocaleListCompat getLocales(android.content.res.Configuration);
+  }
+
+  public final class EnvironmentCompat {
+    method public static String getStorageState(java.io.File);
+    field public static final String MEDIA_UNKNOWN = "unknown";
+  }
+
+  public final class ExecutorCompat {
+    method public static java.util.concurrent.Executor create(android.os.Handler);
+  }
+
+  public final class HandlerCompat {
+    method public static android.os.Handler createAsync(android.os.Looper);
+    method public static android.os.Handler createAsync(android.os.Looper, android.os.Handler.Callback);
+    method public static boolean postDelayed(android.os.Handler, Runnable, Object?, long);
+  }
+
+  public final class LocaleListCompat {
+    method public static androidx.core.os.LocaleListCompat create(java.util.Locale!...);
+    method public static androidx.core.os.LocaleListCompat forLanguageTags(String?);
+    method public java.util.Locale! get(int);
+    method @Size(min=1) public static androidx.core.os.LocaleListCompat getAdjustedDefault();
+    method @Size(min=1) public static androidx.core.os.LocaleListCompat getDefault();
+    method public static androidx.core.os.LocaleListCompat getEmptyLocaleList();
+    method public java.util.Locale? getFirstMatch(String![]);
+    method @IntRange(from=0xffffffff) public int indexOf(java.util.Locale!);
+    method public boolean isEmpty();
+    method @IntRange(from=0) public int size();
+    method public String toLanguageTags();
+    method public Object? unwrap();
+    method @Deprecated @RequiresApi(24) public static androidx.core.os.LocaleListCompat! wrap(Object!);
+    method @RequiresApi(24) public static androidx.core.os.LocaleListCompat wrap(android.os.LocaleList);
+  }
+
+  public final class MessageCompat {
+    method public static boolean isAsynchronous(android.os.Message);
+    method public static void setAsynchronous(android.os.Message, boolean);
+  }
+
+  public class OperationCanceledException extends java.lang.RuntimeException {
+    ctor public OperationCanceledException();
+    ctor public OperationCanceledException(String?);
+  }
+
+  public final class ParcelCompat {
+    method public static boolean readBoolean(android.os.Parcel);
+    method public static void writeBoolean(android.os.Parcel, boolean);
+  }
+
+  @Deprecated public final class ParcelableCompat {
+    method @Deprecated public static <T> android.os.Parcelable.Creator<T!>! newCreator(androidx.core.os.ParcelableCompatCreatorCallbacks<T!>!);
+  }
+
+  @Deprecated public interface ParcelableCompatCreatorCallbacks<T> {
+    method @Deprecated public T! createFromParcel(android.os.Parcel!, ClassLoader!);
+    method @Deprecated public T![]! newArray(int);
+  }
+
+  public final class ProcessCompat {
+    method public static boolean isApplicationUid(int);
+  }
+
+  @Deprecated public final class TraceCompat {
+    method @Deprecated public static void beginAsyncSection(String, int);
+    method @Deprecated public static void beginSection(String);
+    method @Deprecated public static void endAsyncSection(String, int);
+    method @Deprecated public static void endSection();
+    method @Deprecated public static boolean isEnabled();
+    method @Deprecated public static void setCounter(String, int);
+  }
+
+  public class UserManagerCompat {
+    method public static boolean isUserUnlocked(android.content.Context);
+  }
+
+}
+
+package androidx.core.provider {
+
+  public final class FontRequest {
+    ctor public FontRequest(String, String, String, java.util.List<java.util.List<byte[]!>!>);
+    ctor public FontRequest(String, String, String, @ArrayRes int);
+    method public java.util.List<java.util.List<byte[]!>!>? getCertificates();
+    method @ArrayRes public int getCertificatesArrayResId();
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public String! getIdentifier();
+    method public String getProviderAuthority();
+    method public String getProviderPackage();
+    method public String getQuery();
+  }
+
+  public class FontsContractCompat {
+    method public static android.graphics.Typeface? buildTypeface(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontsContractCompat.FontInfo![]);
+    method public static androidx.core.provider.FontsContractCompat.FontFamilyResult fetchFonts(android.content.Context, android.os.CancellationSignal?, androidx.core.provider.FontRequest) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.graphics.Typeface! getFontSync(android.content.Context!, androidx.core.provider.FontRequest!, androidx.core.content.res.ResourcesCompat.FontCallback?, android.os.Handler?, boolean, int, int);
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @VisibleForTesting public static android.content.pm.ProviderInfo? getProvider(android.content.pm.PackageManager, androidx.core.provider.FontRequest, android.content.res.Resources?) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated @RequiresApi(19) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static java.util.Map<android.net.Uri!,java.nio.ByteBuffer!>! prepareFontData(android.content.Context!, androidx.core.provider.FontsContractCompat.FontInfo![]!, android.os.CancellationSignal!);
+    method public static void requestFont(android.content.Context, androidx.core.provider.FontRequest, androidx.core.provider.FontsContractCompat.FontRequestCallback, android.os.Handler);
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static void resetCache();
+    field @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final String PARCEL_FONT_RESULTS = "font_results";
+  }
+
+  public static final class FontsContractCompat.Columns implements android.provider.BaseColumns {
+    ctor public FontsContractCompat.Columns();
+    field public static final String FILE_ID = "file_id";
+    field public static final String ITALIC = "font_italic";
+    field public static final String RESULT_CODE = "result_code";
+    field public static final int RESULT_CODE_FONT_NOT_FOUND = 1; // 0x1
+    field public static final int RESULT_CODE_FONT_UNAVAILABLE = 2; // 0x2
+    field public static final int RESULT_CODE_MALFORMED_QUERY = 3; // 0x3
+    field public static final int RESULT_CODE_OK = 0; // 0x0
+    field public static final String TTC_INDEX = "font_ttc_index";
+    field public static final String VARIATION_SETTINGS = "font_variation_settings";
+    field public static final String WEIGHT = "font_weight";
+  }
+
+  public static class FontsContractCompat.FontFamilyResult {
+    ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public FontsContractCompat.FontFamilyResult(int, androidx.core.provider.FontsContractCompat.FontInfo![]?);
+    method public androidx.core.provider.FontsContractCompat.FontInfo![]! getFonts();
+    method public int getStatusCode();
+    field public static final int STATUS_OK = 0; // 0x0
+    field public static final int STATUS_UNEXPECTED_DATA_PROVIDED = 2; // 0x2
+    field public static final int STATUS_WRONG_CERTIFICATES = 1; // 0x1
+  }
+
+  public static class FontsContractCompat.FontInfo {
+    ctor @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public FontsContractCompat.FontInfo(android.net.Uri, @IntRange(from=0) int, @IntRange(from=1, to=1000) int, boolean, int);
+    method public int getResultCode();
+    method @IntRange(from=0) public int getTtcIndex();
+    method public android.net.Uri getUri();
+    method @IntRange(from=1, to=1000) public int getWeight();
+    method public boolean isItalic();
+  }
+
+  public static class FontsContractCompat.FontRequestCallback {
+    ctor public FontsContractCompat.FontRequestCallback();
+    method public void onTypefaceRequestFailed(@androidx.core.provider.FontsContractCompat.FontRequestCallback.FontRequestFailReason int);
+    method public void onTypefaceRetrieved(android.graphics.Typeface!);
+    field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
+    field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
+    field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
+    field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
+    field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
+    field public static final int FAIL_REASON_SECURITY_VIOLATION = -4; // 0xfffffffc
+    field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
+    field @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final int RESULT_OK = 0; // 0x0
+  }
+
+  @IntDef({androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_PROVIDER_NOT_FOUND, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_FONT_UNAVAILABLE, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_MALFORMED_QUERY, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_WRONG_CERTIFICATES, androidx.core.provider.FontsContractCompat.FontRequestCallback.FAIL_REASON_SECURITY_VIOLATION, androidx.core.provider.FontsContractCompat.FontRequestCallback.RESULT_OK}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface FontsContractCompat.FontRequestCallback.FontRequestFailReason {
+  }
+
+  @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class SelfDestructiveThread {
+    ctor @Deprecated public SelfDestructiveThread(String!, int, int);
+    method @Deprecated @VisibleForTesting public int getGeneration();
+    method @Deprecated @VisibleForTesting public boolean isRunning();
+    method @Deprecated public <T> void postAndReply(java.util.concurrent.Callable<T!>!, androidx.core.provider.SelfDestructiveThread.ReplyCallback<T!>!);
+    method @Deprecated public <T> T! postAndWait(java.util.concurrent.Callable<T!>!, int) throws java.lang.InterruptedException;
+  }
+
+  @Deprecated public static interface SelfDestructiveThread.ReplyCallback<T> {
+    method @Deprecated public void onReply(T!);
+  }
+
+}
+
+package androidx.core.telephony.mbms {
+
+  public final class MbmsHelper {
+    method public static CharSequence? getBestNameForService(android.content.Context, android.telephony.mbms.ServiceInfo);
+  }
+
+}
+
+package androidx.core.text {
+
+  public final class BidiFormatter {
+    method public static androidx.core.text.BidiFormatter! getInstance();
+    method public static androidx.core.text.BidiFormatter! getInstance(boolean);
+    method public static androidx.core.text.BidiFormatter! getInstance(java.util.Locale!);
+    method public boolean getStereoReset();
+    method public boolean isRtl(String!);
+    method public boolean isRtl(CharSequence!);
+    method public boolean isRtlContext();
+    method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+    method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!, boolean);
+    method public String! unicodeWrap(String!, androidx.core.text.TextDirectionHeuristicCompat!);
+    method public CharSequence! unicodeWrap(CharSequence!, androidx.core.text.TextDirectionHeuristicCompat!);
+    method public String! unicodeWrap(String!, boolean);
+    method public CharSequence! unicodeWrap(CharSequence!, boolean);
+    method public String! unicodeWrap(String!);
+    method public CharSequence! unicodeWrap(CharSequence!);
+  }
+
+  public static final class BidiFormatter.Builder {
+    ctor public BidiFormatter.Builder();
+    ctor public BidiFormatter.Builder(boolean);
+    ctor public BidiFormatter.Builder(java.util.Locale!);
+    method public androidx.core.text.BidiFormatter! build();
+    method public androidx.core.text.BidiFormatter.Builder! setTextDirectionHeuristic(androidx.core.text.TextDirectionHeuristicCompat!);
+    method public androidx.core.text.BidiFormatter.Builder! stereoReset(boolean);
+  }
+
+  public final class HtmlCompat {
+    method public static android.text.Spanned fromHtml(String, int);
+    method public static android.text.Spanned fromHtml(String, int, android.text.Html.ImageGetter?, android.text.Html.TagHandler?);
+    method public static String toHtml(android.text.Spanned, int);
+    field public static final int FROM_HTML_MODE_COMPACT = 63; // 0x3f
+    field public static final int FROM_HTML_MODE_LEGACY = 0; // 0x0
+    field public static final int FROM_HTML_OPTION_USE_CSS_COLORS = 256; // 0x100
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_BLOCKQUOTE = 32; // 0x20
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_DIV = 16; // 0x10
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_HEADING = 2; // 0x2
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST = 8; // 0x8
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_LIST_ITEM = 4; // 0x4
+    field public static final int FROM_HTML_SEPARATOR_LINE_BREAK_PARAGRAPH = 1; // 0x1
+    field public static final int TO_HTML_PARAGRAPH_LINES_CONSECUTIVE = 0; // 0x0
+    field public static final int TO_HTML_PARAGRAPH_LINES_INDIVIDUAL = 1; // 0x1
+  }
+
+  public final class ICUCompat {
+    method public static String? maximizeAndGetScript(java.util.Locale!);
+  }
+
+  public class PrecomputedTextCompat implements android.text.Spannable {
+    method public char charAt(int);
+    method public static androidx.core.text.PrecomputedTextCompat! create(CharSequence, androidx.core.text.PrecomputedTextCompat.Params);
+    method @IntRange(from=0) public int getParagraphCount();
+    method @IntRange(from=0) public int getParagraphEnd(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getParagraphStart(@IntRange(from=0) int);
+    method public androidx.core.text.PrecomputedTextCompat.Params getParams();
+    method @RequiresApi(28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public android.text.PrecomputedText? getPrecomputedText();
+    method public int getSpanEnd(Object!);
+    method public int getSpanFlags(Object!);
+    method public int getSpanStart(Object!);
+    method public <T> T![]! getSpans(int, int, Class<T!>!);
+    method @UiThread public static java.util.concurrent.Future<androidx.core.text.PrecomputedTextCompat!>! getTextFuture(CharSequence, androidx.core.text.PrecomputedTextCompat.Params, java.util.concurrent.Executor?);
+    method public int length();
+    method public int nextSpanTransition(int, int, Class!);
+    method public void removeSpan(Object!);
+    method public void setSpan(Object!, int, int, int);
+    method public CharSequence! subSequence(int, int);
+  }
+
+  public static final class PrecomputedTextCompat.Params {
+    ctor @RequiresApi(28) public PrecomputedTextCompat.Params(android.text.PrecomputedText.Params);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean equalsWithoutTextDirection(androidx.core.text.PrecomputedTextCompat.Params);
+    method @RequiresApi(23) public int getBreakStrategy();
+    method @RequiresApi(23) public int getHyphenationFrequency();
+    method @RequiresApi(18) public android.text.TextDirectionHeuristic? getTextDirection();
+    method public android.text.TextPaint getTextPaint();
+  }
+
+  public static class PrecomputedTextCompat.Params.Builder {
+    ctor public PrecomputedTextCompat.Params.Builder(android.text.TextPaint);
+    method public androidx.core.text.PrecomputedTextCompat.Params build();
+    method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setBreakStrategy(int);
+    method @RequiresApi(23) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setHyphenationFrequency(int);
+    method @RequiresApi(18) public androidx.core.text.PrecomputedTextCompat.Params.Builder! setTextDirection(android.text.TextDirectionHeuristic);
+  }
+
+  public interface TextDirectionHeuristicCompat {
+    method public boolean isRtl(char[]!, int, int);
+    method public boolean isRtl(CharSequence!, int, int);
+  }
+
+  public final class TextDirectionHeuristicsCompat {
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! ANYRTL_LTR;
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_LTR;
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! FIRSTSTRONG_RTL;
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! LOCALE;
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! LTR;
+    field public static final androidx.core.text.TextDirectionHeuristicCompat! RTL;
+  }
+
+  public final class TextUtilsCompat {
+    method public static int getLayoutDirectionFromLocale(java.util.Locale?);
+    method public static String htmlEncode(String);
+  }
+
+}
+
+package androidx.core.text.util {
+
+  public final class LinkifyCompat {
+    method public static boolean addLinks(android.text.Spannable, @androidx.core.text.util.LinkifyCompat.LinkifyMask int);
+    method public static boolean addLinks(android.widget.TextView, @androidx.core.text.util.LinkifyCompat.LinkifyMask int);
+    method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?);
+    method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+    method public static void addLinks(android.widget.TextView, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+    method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?);
+    method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+    method public static boolean addLinks(android.text.Spannable, java.util.regex.Pattern, String?, String![]?, android.text.util.Linkify.MatchFilter?, android.text.util.Linkify.TransformFilter?);
+  }
+
+  @IntDef(flag=true, value={android.text.util.Linkify.WEB_URLS, android.text.util.Linkify.EMAIL_ADDRESSES, android.text.util.Linkify.PHONE_NUMBERS, android.text.util.Linkify.MAP_ADDRESSES, android.text.util.Linkify.ALL}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface LinkifyCompat.LinkifyMask {
+  }
+
+}
+
+package androidx.core.util {
+
+  public class AtomicFile {
+    ctor public AtomicFile(java.io.File);
+    method public void delete();
+    method public void failWrite(java.io.FileOutputStream?);
+    method public void finishWrite(java.io.FileOutputStream?);
+    method public java.io.File getBaseFile();
+    method public java.io.FileInputStream openRead() throws java.io.FileNotFoundException;
+    method public byte[] readFully() throws java.io.IOException;
+    method public java.io.FileOutputStream startWrite() throws java.io.IOException;
+  }
+
+  public interface Consumer<T> {
+    method public void accept(T!);
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class DebugUtils {
+    method public static void buildShortClassTag(Object!, StringBuilder!);
+  }
+
+  @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class LogWriter extends java.io.Writer {
+    ctor @Deprecated public LogWriter(String!);
+    method @Deprecated public void close();
+    method @Deprecated public void flush();
+    method @Deprecated public void write(char[]!, int, int);
+  }
+
+  public class ObjectsCompat {
+    method public static boolean equals(Object?, Object?);
+    method public static int hash(java.lang.Object!...);
+    method public static int hashCode(Object?);
+    method public static String? toString(Object?, String?);
+  }
+
+  public class Pair<F, S> {
+    ctor public Pair(F!, S!);
+    method public static <A, B> androidx.core.util.Pair<A!,B!> create(A!, B!);
+    field public final F! first;
+    field public final S! second;
+  }
+
+  public final class PatternsCompat {
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final java.util.regex.Pattern AUTOLINK_EMAIL_ADDRESS;
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final java.util.regex.Pattern AUTOLINK_WEB_URL;
+    field public static final java.util.regex.Pattern DOMAIN_NAME;
+    field public static final java.util.regex.Pattern EMAIL_ADDRESS;
+    field public static final java.util.regex.Pattern IP_ADDRESS;
+    field public static final java.util.regex.Pattern WEB_URL;
+  }
+
+  public final class Pools {
+  }
+
+  public static interface Pools.Pool<T> {
+    method public T? acquire();
+    method public boolean release(T);
+  }
+
+  public static class Pools.SimplePool<T> implements androidx.core.util.Pools.Pool<T> {
+    ctor public Pools.SimplePool(int);
+    method public T! acquire();
+    method public boolean release(T);
+  }
+
+  public static class Pools.SynchronizedPool<T> extends androidx.core.util.Pools.SimplePool<T> {
+    ctor public Pools.SynchronizedPool(int);
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class Preconditions {
+    method public static void checkArgument(boolean);
+    method public static void checkArgument(boolean, Object);
+    method public static int checkArgumentInRange(int, int, int, String);
+    method @IntRange(from=0) public static int checkArgumentNonnegative(int, String?);
+    method @IntRange(from=0) public static int checkArgumentNonnegative(int);
+    method public static int checkFlagsArgument(int, int);
+    method public static <T> T checkNotNull(T?);
+    method public static <T> T checkNotNull(T?, Object);
+    method public static void checkState(boolean, String?);
+    method public static void checkState(boolean);
+    method public static <T extends java.lang.CharSequence> T checkStringNotEmpty(T?);
+    method public static <T extends java.lang.CharSequence> T checkStringNotEmpty(T?, Object);
+    method public static <T extends java.lang.CharSequence> T checkStringNotEmpty(T?, String, java.lang.Object!...);
+  }
+
+  public interface Predicate<T> {
+    method public boolean test(T!);
+  }
+
+  public interface Supplier<T> {
+    method public T! get();
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class TimeUtils {
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static void formatDuration(long, StringBuilder!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static void formatDuration(long, java.io.PrintWriter!, int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static void formatDuration(long, java.io.PrintWriter!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static void formatDuration(long, long, java.io.PrintWriter!);
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final int HUNDRED_DAY_FIELD_LEN = 19; // 0x13
+  }
+
+}
+
+package androidx.core.view {
+
+  public class AccessibilityDelegateCompat {
+    ctor public AccessibilityDelegateCompat();
+    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public AccessibilityDelegateCompat(android.view.View.AccessibilityDelegate!);
+    method public boolean dispatchPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public androidx.core.view.accessibility.AccessibilityNodeProviderCompat! getAccessibilityNodeProvider(android.view.View!);
+    method public void onInitializeAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public void onInitializeAccessibilityNodeInfo(android.view.View!, androidx.core.view.accessibility.AccessibilityNodeInfoCompat!);
+    method public void onPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public boolean onRequestSendAccessibilityEvent(android.view.ViewGroup!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public boolean performAccessibilityAction(android.view.View!, int, android.os.Bundle!);
+    method public void sendAccessibilityEvent(android.view.View!, int);
+    method public void sendAccessibilityEventUnchecked(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+  }
+
+  public abstract class ActionProvider {
+    ctor public ActionProvider(android.content.Context!);
+    method public android.content.Context! getContext();
+    method public boolean hasSubMenu();
+    method public boolean isVisible();
+    method public abstract android.view.View! onCreateActionView();
+    method public android.view.View! onCreateActionView(android.view.MenuItem!);
+    method public boolean onPerformDefaultAction();
+    method public void onPrepareSubMenu(android.view.SubMenu!);
+    method public boolean overridesItemVisibility();
+    method public void refreshVisibility();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void reset();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setSubUiVisibilityListener(androidx.core.view.ActionProvider.SubUiVisibilityListener!);
+    method public void setVisibilityListener(androidx.core.view.ActionProvider.VisibilityListener!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void subUiVisibilityChanged(boolean);
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static interface ActionProvider.SubUiVisibilityListener {
+    method public void onSubUiVisibilityChanged(boolean);
+  }
+
+  public static interface ActionProvider.VisibilityListener {
+    method public void onActionProviderVisibilityChanged(boolean);
+  }
+
+  public final class ContentInfoCompat {
+    method public android.content.ClipData getClip();
+    method public android.os.Bundle? getExtras();
+    method @androidx.core.view.ContentInfoCompat.Flags public int getFlags();
+    method public android.net.Uri? getLinkUri();
+    method @androidx.core.view.ContentInfoCompat.Source public int getSource();
+    method public android.util.Pair<androidx.core.view.ContentInfoCompat!,androidx.core.view.ContentInfoCompat!> partition(androidx.core.util.Predicate<android.content.ClipData.Item!>);
+    field public static final int FLAG_CONVERT_TO_PLAIN_TEXT = 1; // 0x1
+    field public static final int SOURCE_APP = 0; // 0x0
+    field public static final int SOURCE_CLIPBOARD = 1; // 0x1
+    field public static final int SOURCE_DRAG_AND_DROP = 3; // 0x3
+    field public static final int SOURCE_INPUT_METHOD = 2; // 0x2
+  }
+
+  public static final class ContentInfoCompat.Builder {
+    ctor public ContentInfoCompat.Builder(androidx.core.view.ContentInfoCompat);
+    ctor public ContentInfoCompat.Builder(android.content.ClipData, @androidx.core.view.ContentInfoCompat.Source int);
+    method public androidx.core.view.ContentInfoCompat build();
+    method public androidx.core.view.ContentInfoCompat.Builder setClip(android.content.ClipData);
+    method public androidx.core.view.ContentInfoCompat.Builder setExtras(android.os.Bundle?);
+    method public androidx.core.view.ContentInfoCompat.Builder setFlags(@androidx.core.view.ContentInfoCompat.Flags int);
+    method public androidx.core.view.ContentInfoCompat.Builder setLinkUri(android.net.Uri?);
+    method public androidx.core.view.ContentInfoCompat.Builder setSource(@androidx.core.view.ContentInfoCompat.Source int);
+  }
+
+  @IntDef(flag=true, value={androidx.core.view.ContentInfoCompat.FLAG_CONVERT_TO_PLAIN_TEXT}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ContentInfoCompat.Flags {
+  }
+
+  @IntDef({androidx.core.view.ContentInfoCompat.SOURCE_APP, androidx.core.view.ContentInfoCompat.SOURCE_CLIPBOARD, androidx.core.view.ContentInfoCompat.SOURCE_INPUT_METHOD, androidx.core.view.ContentInfoCompat.SOURCE_DRAG_AND_DROP}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ContentInfoCompat.Source {
+  }
+
+  public final class DisplayCompat {
+    method public static androidx.core.view.DisplayCompat.ModeCompat![] getSupportedModes(android.content.Context, android.view.Display);
+  }
+
+  public static final class DisplayCompat.ModeCompat {
+    method public int getPhysicalHeight();
+    method public int getPhysicalWidth();
+    method public boolean isNative();
+    method @RequiresApi(android.os.Build.VERSION_CODES.M) public android.view.Display.Mode? toMode();
+  }
+
+  public final class DisplayCutoutCompat {
+    ctor public DisplayCutoutCompat(android.graphics.Rect!, java.util.List<android.graphics.Rect!>!);
+    ctor public DisplayCutoutCompat(androidx.core.graphics.Insets, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, android.graphics.Rect?, androidx.core.graphics.Insets);
+    method public java.util.List<android.graphics.Rect!> getBoundingRects();
+    method public int getSafeInsetBottom();
+    method public int getSafeInsetLeft();
+    method public int getSafeInsetRight();
+    method public int getSafeInsetTop();
+    method public androidx.core.graphics.Insets getWaterfallInsets();
+  }
+
+  public final class DragAndDropPermissionsCompat {
+    method public void release();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static androidx.core.view.DragAndDropPermissionsCompat? request(android.app.Activity!, android.view.DragEvent!);
+  }
+
+  public class DragStartHelper {
+    ctor public DragStartHelper(android.view.View!, androidx.core.view.DragStartHelper.OnDragStartListener!);
+    method public void attach();
+    method public void detach();
+    method public void getTouchPosition(android.graphics.Point!);
+    method public boolean onLongClick(android.view.View!);
+    method public boolean onTouch(android.view.View!, android.view.MotionEvent!);
+  }
+
+  public static interface DragStartHelper.OnDragStartListener {
+    method public boolean onDragStart(android.view.View!, androidx.core.view.DragStartHelper!);
+  }
+
+  public final class GestureDetectorCompat {
+    ctor public GestureDetectorCompat(android.content.Context!, android.view.GestureDetector.OnGestureListener!);
+    ctor public GestureDetectorCompat(android.content.Context!, android.view.GestureDetector.OnGestureListener!, android.os.Handler!);
+    method public boolean isLongpressEnabled();
+    method public boolean onTouchEvent(android.view.MotionEvent!);
+    method public void setIsLongpressEnabled(boolean);
+    method public void setOnDoubleTapListener(android.view.GestureDetector.OnDoubleTapListener!);
+  }
+
+  public final class GravityCompat {
+    method public static void apply(int, int, int, android.graphics.Rect!, android.graphics.Rect!, int);
+    method public static void apply(int, int, int, android.graphics.Rect!, int, int, android.graphics.Rect!, int);
+    method public static void applyDisplay(int, android.graphics.Rect!, android.graphics.Rect!, int);
+    method public static int getAbsoluteGravity(int, int);
+    field public static final int END = 8388613; // 0x800005
+    field public static final int RELATIVE_HORIZONTAL_GRAVITY_MASK = 8388615; // 0x800007
+    field public static final int RELATIVE_LAYOUT_DIRECTION = 8388608; // 0x800000
+    field public static final int START = 8388611; // 0x800003
+  }
+
+  public final class InputDeviceCompat {
+    field public static final int SOURCE_ANY = -256; // 0xffffff00
+    field public static final int SOURCE_CLASS_BUTTON = 1; // 0x1
+    field public static final int SOURCE_CLASS_JOYSTICK = 16; // 0x10
+    field public static final int SOURCE_CLASS_MASK = 255; // 0xff
+    field public static final int SOURCE_CLASS_NONE = 0; // 0x0
+    field public static final int SOURCE_CLASS_POINTER = 2; // 0x2
+    field public static final int SOURCE_CLASS_POSITION = 8; // 0x8
+    field public static final int SOURCE_CLASS_TRACKBALL = 4; // 0x4
+    field public static final int SOURCE_DPAD = 513; // 0x201
+    field public static final int SOURCE_GAMEPAD = 1025; // 0x401
+    field public static final int SOURCE_HDMI = 33554433; // 0x2000001
+    field public static final int SOURCE_JOYSTICK = 16777232; // 0x1000010
+    field public static final int SOURCE_KEYBOARD = 257; // 0x101
+    field public static final int SOURCE_MOUSE = 8194; // 0x2002
+    field public static final int SOURCE_ROTARY_ENCODER = 4194304; // 0x400000
+    field public static final int SOURCE_STYLUS = 16386; // 0x4002
+    field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008
+    field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002
+    field public static final int SOURCE_TOUCH_NAVIGATION = 2097152; // 0x200000
+    field public static final int SOURCE_TRACKBALL = 65540; // 0x10004
+    field public static final int SOURCE_UNKNOWN = 0; // 0x0
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class KeyEventDispatcher {
+    method public static boolean dispatchBeforeHierarchy(android.view.View, android.view.KeyEvent);
+    method public static boolean dispatchKeyEvent(androidx.core.view.KeyEventDispatcher.Component, android.view.View?, android.view.Window.Callback?, android.view.KeyEvent);
+  }
+
+  public static interface KeyEventDispatcher.Component {
+    method public boolean superDispatchKeyEvent(android.view.KeyEvent!);
+  }
+
+  public final class LayoutInflaterCompat {
+    method @Deprecated public static androidx.core.view.LayoutInflaterFactory! getFactory(android.view.LayoutInflater!);
+    method @Deprecated public static void setFactory(android.view.LayoutInflater, androidx.core.view.LayoutInflaterFactory);
+    method public static void setFactory2(android.view.LayoutInflater, android.view.LayoutInflater.Factory2);
+  }
+
+  @Deprecated public interface LayoutInflaterFactory {
+    method @Deprecated public android.view.View! onCreateView(android.view.View!, String!, android.content.Context!, android.util.AttributeSet!);
+  }
+
+  public final class MarginLayoutParamsCompat {
+    method public static int getLayoutDirection(android.view.ViewGroup.MarginLayoutParams!);
+    method public static int getMarginEnd(android.view.ViewGroup.MarginLayoutParams!);
+    method public static int getMarginStart(android.view.ViewGroup.MarginLayoutParams!);
+    method public static boolean isMarginRelative(android.view.ViewGroup.MarginLayoutParams!);
+    method public static void resolveLayoutDirection(android.view.ViewGroup.MarginLayoutParams!, int);
+    method public static void setLayoutDirection(android.view.ViewGroup.MarginLayoutParams!, int);
+    method public static void setMarginEnd(android.view.ViewGroup.MarginLayoutParams!, int);
+    method public static void setMarginStart(android.view.ViewGroup.MarginLayoutParams!, int);
+  }
+
+  public final class MenuCompat {
+    method public static void setGroupDividerEnabled(android.view.Menu!, boolean);
+    method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+  }
+
+  public final class MenuItemCompat {
+    method @Deprecated public static boolean collapseActionView(android.view.MenuItem!);
+    method @Deprecated public static boolean expandActionView(android.view.MenuItem!);
+    method public static androidx.core.view.ActionProvider! getActionProvider(android.view.MenuItem!);
+    method @Deprecated public static android.view.View! getActionView(android.view.MenuItem!);
+    method public static int getAlphabeticModifiers(android.view.MenuItem!);
+    method public static CharSequence! getContentDescription(android.view.MenuItem!);
+    method public static android.content.res.ColorStateList! getIconTintList(android.view.MenuItem!);
+    method public static android.graphics.PorterDuff.Mode! getIconTintMode(android.view.MenuItem!);
+    method public static int getNumericModifiers(android.view.MenuItem!);
+    method public static CharSequence! getTooltipText(android.view.MenuItem!);
+    method @Deprecated public static boolean isActionViewExpanded(android.view.MenuItem!);
+    method public static android.view.MenuItem! setActionProvider(android.view.MenuItem!, androidx.core.view.ActionProvider!);
+    method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, android.view.View!);
+    method @Deprecated public static android.view.MenuItem! setActionView(android.view.MenuItem!, int);
+    method public static void setAlphabeticShortcut(android.view.MenuItem!, char, int);
+    method public static void setContentDescription(android.view.MenuItem!, CharSequence!);
+    method public static void setIconTintList(android.view.MenuItem!, android.content.res.ColorStateList!);
+    method public static void setIconTintMode(android.view.MenuItem!, android.graphics.PorterDuff.Mode!);
+    method public static void setNumericShortcut(android.view.MenuItem!, char, int);
+    method @Deprecated public static android.view.MenuItem! setOnActionExpandListener(android.view.MenuItem!, androidx.core.view.MenuItemCompat.OnActionExpandListener!);
+    method public static void setShortcut(android.view.MenuItem!, char, char, int, int);
+    method @Deprecated public static void setShowAsAction(android.view.MenuItem!, int);
+    method public static void setTooltipText(android.view.MenuItem!, CharSequence!);
+    field @Deprecated public static final int SHOW_AS_ACTION_ALWAYS = 2; // 0x2
+    field @Deprecated public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = 8; // 0x8
+    field @Deprecated public static final int SHOW_AS_ACTION_IF_ROOM = 1; // 0x1
+    field @Deprecated public static final int SHOW_AS_ACTION_NEVER = 0; // 0x0
+    field @Deprecated public static final int SHOW_AS_ACTION_WITH_TEXT = 4; // 0x4
+  }
+
+  @Deprecated public static interface MenuItemCompat.OnActionExpandListener {
+    method @Deprecated public boolean onMenuItemActionCollapse(android.view.MenuItem!);
+    method @Deprecated public boolean onMenuItemActionExpand(android.view.MenuItem!);
+  }
+
+  public final class MotionEventCompat {
+    method @Deprecated public static int findPointerIndex(android.view.MotionEvent!, int);
+    method @Deprecated public static int getActionIndex(android.view.MotionEvent!);
+    method @Deprecated public static int getActionMasked(android.view.MotionEvent!);
+    method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int);
+    method @Deprecated public static float getAxisValue(android.view.MotionEvent!, int, int);
+    method @Deprecated public static int getButtonState(android.view.MotionEvent!);
+    method @Deprecated public static int getPointerCount(android.view.MotionEvent!);
+    method @Deprecated public static int getPointerId(android.view.MotionEvent!, int);
+    method @Deprecated public static int getSource(android.view.MotionEvent!);
+    method @Deprecated public static float getX(android.view.MotionEvent!, int);
+    method @Deprecated public static float getY(android.view.MotionEvent!, int);
+    method public static boolean isFromSource(android.view.MotionEvent!, int);
+    field @Deprecated public static final int ACTION_HOVER_ENTER = 9; // 0x9
+    field @Deprecated public static final int ACTION_HOVER_EXIT = 10; // 0xa
+    field @Deprecated public static final int ACTION_HOVER_MOVE = 7; // 0x7
+    field @Deprecated public static final int ACTION_MASK = 255; // 0xff
+    field @Deprecated public static final int ACTION_POINTER_DOWN = 5; // 0x5
+    field @Deprecated public static final int ACTION_POINTER_INDEX_MASK = 65280; // 0xff00
+    field @Deprecated public static final int ACTION_POINTER_INDEX_SHIFT = 8; // 0x8
+    field @Deprecated public static final int ACTION_POINTER_UP = 6; // 0x6
+    field @Deprecated public static final int ACTION_SCROLL = 8; // 0x8
+    field @Deprecated public static final int AXIS_BRAKE = 23; // 0x17
+    field @Deprecated public static final int AXIS_DISTANCE = 24; // 0x18
+    field @Deprecated public static final int AXIS_GAS = 22; // 0x16
+    field @Deprecated public static final int AXIS_GENERIC_1 = 32; // 0x20
+    field @Deprecated public static final int AXIS_GENERIC_10 = 41; // 0x29
+    field @Deprecated public static final int AXIS_GENERIC_11 = 42; // 0x2a
+    field @Deprecated public static final int AXIS_GENERIC_12 = 43; // 0x2b
+    field @Deprecated public static final int AXIS_GENERIC_13 = 44; // 0x2c
+    field @Deprecated public static final int AXIS_GENERIC_14 = 45; // 0x2d
+    field @Deprecated public static final int AXIS_GENERIC_15 = 46; // 0x2e
+    field @Deprecated public static final int AXIS_GENERIC_16 = 47; // 0x2f
+    field @Deprecated public static final int AXIS_GENERIC_2 = 33; // 0x21
+    field @Deprecated public static final int AXIS_GENERIC_3 = 34; // 0x22
+    field @Deprecated public static final int AXIS_GENERIC_4 = 35; // 0x23
+    field @Deprecated public static final int AXIS_GENERIC_5 = 36; // 0x24
+    field @Deprecated public static final int AXIS_GENERIC_6 = 37; // 0x25
+    field @Deprecated public static final int AXIS_GENERIC_7 = 38; // 0x26
+    field @Deprecated public static final int AXIS_GENERIC_8 = 39; // 0x27
+    field @Deprecated public static final int AXIS_GENERIC_9 = 40; // 0x28
+    field @Deprecated public static final int AXIS_HAT_X = 15; // 0xf
+    field @Deprecated public static final int AXIS_HAT_Y = 16; // 0x10
+    field @Deprecated public static final int AXIS_HSCROLL = 10; // 0xa
+    field @Deprecated public static final int AXIS_LTRIGGER = 17; // 0x11
+    field @Deprecated public static final int AXIS_ORIENTATION = 8; // 0x8
+    field @Deprecated public static final int AXIS_PRESSURE = 2; // 0x2
+    field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+    field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
+    field @Deprecated public static final int AXIS_RTRIGGER = 18; // 0x12
+    field @Deprecated public static final int AXIS_RUDDER = 20; // 0x14
+    field @Deprecated public static final int AXIS_RX = 12; // 0xc
+    field @Deprecated public static final int AXIS_RY = 13; // 0xd
+    field @Deprecated public static final int AXIS_RZ = 14; // 0xe
+    field public static final int AXIS_SCROLL = 26; // 0x1a
+    field @Deprecated public static final int AXIS_SIZE = 3; // 0x3
+    field @Deprecated public static final int AXIS_THROTTLE = 19; // 0x13
+    field @Deprecated public static final int AXIS_TILT = 25; // 0x19
+    field @Deprecated public static final int AXIS_TOOL_MAJOR = 6; // 0x6
+    field @Deprecated public static final int AXIS_TOOL_MINOR = 7; // 0x7
+    field @Deprecated public static final int AXIS_TOUCH_MAJOR = 4; // 0x4
+    field @Deprecated public static final int AXIS_TOUCH_MINOR = 5; // 0x5
+    field @Deprecated public static final int AXIS_VSCROLL = 9; // 0x9
+    field @Deprecated public static final int AXIS_WHEEL = 21; // 0x15
+    field @Deprecated public static final int AXIS_X = 0; // 0x0
+    field @Deprecated public static final int AXIS_Y = 1; // 0x1
+    field @Deprecated public static final int AXIS_Z = 11; // 0xb
+    field @Deprecated public static final int BUTTON_PRIMARY = 1; // 0x1
+  }
+
+  public interface NestedScrollingChild {
+    method public boolean dispatchNestedFling(float, float, boolean);
+    method public boolean dispatchNestedPreFling(float, float);
+    method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+    method public boolean hasNestedScrollingParent();
+    method public boolean isNestedScrollingEnabled();
+    method public void setNestedScrollingEnabled(boolean);
+    method public boolean startNestedScroll(@androidx.core.view.ViewCompat.ScrollAxis int);
+    method public void stopNestedScroll();
+  }
+
+  public interface NestedScrollingChild2 extends androidx.core.view.NestedScrollingChild {
+    method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public boolean hasNestedScrollingParent(@androidx.core.view.ViewCompat.NestedScrollType int);
+    method public boolean startNestedScroll(@androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public void stopNestedScroll(@androidx.core.view.ViewCompat.NestedScrollType int);
+  }
+
+  public interface NestedScrollingChild3 extends androidx.core.view.NestedScrollingChild2 {
+    method public void dispatchNestedScroll(int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int, int[]);
+  }
+
+  public class NestedScrollingChildHelper {
+    ctor public NestedScrollingChildHelper(android.view.View);
+    method public boolean dispatchNestedFling(float, float, boolean);
+    method public boolean dispatchNestedPreFling(float, float);
+    method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?);
+    method public boolean dispatchNestedPreScroll(int, int, int[]?, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]?);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public void dispatchNestedScroll(int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int, int[]?);
+    method public boolean hasNestedScrollingParent();
+    method public boolean hasNestedScrollingParent(@androidx.core.view.ViewCompat.NestedScrollType int);
+    method public boolean isNestedScrollingEnabled();
+    method public void onDetachedFromWindow();
+    method public void onStopNestedScroll(android.view.View);
+    method public void setNestedScrollingEnabled(boolean);
+    method public boolean startNestedScroll(@androidx.core.view.ViewCompat.ScrollAxis int);
+    method public boolean startNestedScroll(@androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public void stopNestedScroll();
+    method public void stopNestedScroll(@androidx.core.view.ViewCompat.NestedScrollType int);
+  }
+
+  public interface NestedScrollingParent {
+    method @androidx.core.view.ViewCompat.ScrollAxis public int getNestedScrollAxes();
+    method public boolean onNestedFling(android.view.View, float, float, boolean);
+    method public boolean onNestedPreFling(android.view.View, float, float);
+    method public void onNestedPreScroll(android.view.View, int, int, int[]);
+    method public void onNestedScroll(android.view.View, int, int, int, int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int);
+    method public boolean onStartNestedScroll(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int);
+    method public void onStopNestedScroll(android.view.View);
+  }
+
+  public interface NestedScrollingParent2 extends androidx.core.view.NestedScrollingParent {
+    method public void onNestedPreScroll(android.view.View, int, int, int[], @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public void onNestedScroll(android.view.View, int, int, int, int, @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public boolean onStartNestedScroll(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public void onStopNestedScroll(android.view.View, @androidx.core.view.ViewCompat.NestedScrollType int);
+  }
+
+  public interface NestedScrollingParent3 extends androidx.core.view.NestedScrollingParent2 {
+    method public void onNestedScroll(android.view.View, int, int, int, int, @androidx.core.view.ViewCompat.NestedScrollType int, int[]);
+  }
+
+  public class NestedScrollingParentHelper {
+    ctor public NestedScrollingParentHelper(android.view.ViewGroup);
+    method @androidx.core.view.ViewCompat.ScrollAxis public int getNestedScrollAxes();
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public void onStopNestedScroll(android.view.View);
+    method public void onStopNestedScroll(android.view.View, @androidx.core.view.ViewCompat.NestedScrollType int);
+  }
+
+  public interface OnApplyWindowInsetsListener {
+    method public androidx.core.view.WindowInsetsCompat! onApplyWindowInsets(android.view.View!, androidx.core.view.WindowInsetsCompat!);
+  }
+
+  public interface OnReceiveContentListener {
+    method public androidx.core.view.ContentInfoCompat? onReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+  }
+
+  public interface OnReceiveContentViewBehavior {
+    method public androidx.core.view.ContentInfoCompat? onReceiveContent(androidx.core.view.ContentInfoCompat);
+  }
+
+  public final class OneShotPreDrawListener implements android.view.View.OnAttachStateChangeListener android.view.ViewTreeObserver.OnPreDrawListener {
+    method public static androidx.core.view.OneShotPreDrawListener add(android.view.View, Runnable);
+    method public boolean onPreDraw();
+    method public void onViewAttachedToWindow(android.view.View!);
+    method public void onViewDetachedFromWindow(android.view.View!);
+    method public void removeListener();
+  }
+
+  public final class PointerIconCompat {
+    method public static androidx.core.view.PointerIconCompat! create(android.graphics.Bitmap!, float, float);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public Object! getPointerIcon();
+    method public static androidx.core.view.PointerIconCompat! getSystemIcon(android.content.Context!, int);
+    method public static androidx.core.view.PointerIconCompat! load(android.content.res.Resources!, int);
+    field public static final int TYPE_ALIAS = 1010; // 0x3f2
+    field public static final int TYPE_ALL_SCROLL = 1013; // 0x3f5
+    field public static final int TYPE_ARROW = 1000; // 0x3e8
+    field public static final int TYPE_CELL = 1006; // 0x3ee
+    field public static final int TYPE_CONTEXT_MENU = 1001; // 0x3e9
+    field public static final int TYPE_COPY = 1011; // 0x3f3
+    field public static final int TYPE_CROSSHAIR = 1007; // 0x3ef
+    field public static final int TYPE_DEFAULT = 1000; // 0x3e8
+    field public static final int TYPE_GRAB = 1020; // 0x3fc
+    field public static final int TYPE_GRABBING = 1021; // 0x3fd
+    field public static final int TYPE_HAND = 1002; // 0x3ea
+    field public static final int TYPE_HELP = 1003; // 0x3eb
+    field public static final int TYPE_HORIZONTAL_DOUBLE_ARROW = 1014; // 0x3f6
+    field public static final int TYPE_NO_DROP = 1012; // 0x3f4
+    field public static final int TYPE_NULL = 0; // 0x0
+    field public static final int TYPE_TEXT = 1008; // 0x3f0
+    field public static final int TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW = 1017; // 0x3f9
+    field public static final int TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW = 1016; // 0x3f8
+    field public static final int TYPE_VERTICAL_DOUBLE_ARROW = 1015; // 0x3f7
+    field public static final int TYPE_VERTICAL_TEXT = 1009; // 0x3f1
+    field public static final int TYPE_WAIT = 1004; // 0x3ec
+    field public static final int TYPE_ZOOM_IN = 1018; // 0x3fa
+    field public static final int TYPE_ZOOM_OUT = 1019; // 0x3fb
+  }
+
+  public final class ScaleGestureDetectorCompat {
+    method @Deprecated public static boolean isQuickScaleEnabled(Object!);
+    method public static boolean isQuickScaleEnabled(android.view.ScaleGestureDetector!);
+    method @Deprecated public static void setQuickScaleEnabled(Object!, boolean);
+    method public static void setQuickScaleEnabled(android.view.ScaleGestureDetector!, boolean);
+  }
+
+  public interface ScrollingView {
+    method public int computeHorizontalScrollExtent();
+    method public int computeHorizontalScrollOffset();
+    method public int computeHorizontalScrollRange();
+    method public int computeVerticalScrollExtent();
+    method public int computeVerticalScrollOffset();
+    method public int computeVerticalScrollRange();
+  }
+
+  public interface TintableBackgroundView {
+    method public android.content.res.ColorStateList? getSupportBackgroundTintList();
+    method public android.graphics.PorterDuff.Mode? getSupportBackgroundTintMode();
+    method public void setSupportBackgroundTintList(android.content.res.ColorStateList?);
+    method public void setSupportBackgroundTintMode(android.graphics.PorterDuff.Mode?);
+  }
+
+  @Deprecated public final class VelocityTrackerCompat {
+    method @Deprecated public static float getXVelocity(android.view.VelocityTracker!, int);
+    method @Deprecated public static float getYVelocity(android.view.VelocityTracker!, int);
+  }
+
+  public class ViewCompat {
+    ctor @Deprecated protected ViewCompat();
+    method public static int addAccessibilityAction(android.view.View, CharSequence, androidx.core.view.accessibility.AccessibilityViewCommand);
+    method public static void addKeyboardNavigationClusters(android.view.View, java.util.Collection<android.view.View!>, int);
+    method public static void addOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+    method public static androidx.core.view.ViewPropertyAnimatorCompat animate(android.view.View);
+    method @Deprecated public static boolean canScrollHorizontally(android.view.View!, int);
+    method @Deprecated public static boolean canScrollVertically(android.view.View!, int);
+    method public static void cancelDragAndDrop(android.view.View);
+    method @Deprecated public static int combineMeasuredStates(int, int);
+    method public static androidx.core.view.WindowInsetsCompat computeSystemWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat, android.graphics.Rect);
+    method public static androidx.core.view.WindowInsetsCompat dispatchApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+    method public static void dispatchFinishTemporaryDetach(android.view.View);
+    method public static boolean dispatchNestedFling(android.view.View, float, float, boolean);
+    method public static boolean dispatchNestedPreFling(android.view.View, float, float);
+    method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?);
+    method public static boolean dispatchNestedPreScroll(android.view.View, int, int, int[]?, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?);
+    method public static void dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int, int[]);
+    method public static boolean dispatchNestedScroll(android.view.View, int, int, int, int, int[]?, @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public static void dispatchStartTemporaryDetach(android.view.View);
+    method public static void enableAccessibleClickableSpanSupport(android.view.View!);
+    method public static int generateViewId();
+    method public static androidx.core.view.AccessibilityDelegateCompat? getAccessibilityDelegate(android.view.View);
+    method public static int getAccessibilityLiveRegion(android.view.View);
+    method public static androidx.core.view.accessibility.AccessibilityNodeProviderCompat! getAccessibilityNodeProvider(android.view.View);
+    method @UiThread public static CharSequence! getAccessibilityPaneTitle(android.view.View!);
+    method @Deprecated public static float getAlpha(android.view.View!);
+    method public static android.content.res.ColorStateList! getBackgroundTintList(android.view.View);
+    method public static android.graphics.PorterDuff.Mode! getBackgroundTintMode(android.view.View);
+    method public static android.graphics.Rect? getClipBounds(android.view.View);
+    method public static android.view.Display? getDisplay(android.view.View);
+    method public static float getElevation(android.view.View);
+    method public static boolean getFitsSystemWindows(android.view.View);
+    method public static int getImportantForAccessibility(android.view.View);
+    method public static int getImportantForAutofill(android.view.View);
+    method public static int getLabelFor(android.view.View);
+    method @Deprecated public static int getLayerType(android.view.View!);
+    method public static int getLayoutDirection(android.view.View);
+    method @Deprecated public static android.graphics.Matrix? getMatrix(android.view.View!);
+    method @Deprecated public static int getMeasuredHeightAndState(android.view.View!);
+    method @Deprecated public static int getMeasuredState(android.view.View!);
+    method @Deprecated public static int getMeasuredWidthAndState(android.view.View!);
+    method public static int getMinimumHeight(android.view.View);
+    method public static int getMinimumWidth(android.view.View);
+    method public static int getNextClusterForwardId(android.view.View);
+    method public static String![]? getOnReceiveContentMimeTypes(android.view.View);
+    method @Deprecated public static int getOverScrollMode(android.view.View!);
+    method @Px public static int getPaddingEnd(android.view.View);
+    method @Px public static int getPaddingStart(android.view.View);
+    method public static android.view.ViewParent! getParentForAccessibility(android.view.View);
+    method @Deprecated public static float getPivotX(android.view.View!);
+    method @Deprecated public static float getPivotY(android.view.View!);
+    method public static androidx.core.view.WindowInsetsCompat? getRootWindowInsets(android.view.View);
+    method @Deprecated public static float getRotation(android.view.View!);
+    method @Deprecated public static float getRotationX(android.view.View!);
+    method @Deprecated public static float getRotationY(android.view.View!);
+    method @Deprecated public static float getScaleX(android.view.View!);
+    method @Deprecated public static float getScaleY(android.view.View!);
+    method public static int getScrollIndicators(android.view.View);
+    method @UiThread public static final CharSequence? getStateDescription(android.view.View);
+    method public static java.util.List<android.graphics.Rect!> getSystemGestureExclusionRects(android.view.View);
+    method public static String? getTransitionName(android.view.View);
+    method @Deprecated public static float getTranslationX(android.view.View!);
+    method @Deprecated public static float getTranslationY(android.view.View!);
+    method public static float getTranslationZ(android.view.View);
+    method public static androidx.core.view.WindowInsetsControllerCompat? getWindowInsetsController(android.view.View);
+    method public static int getWindowSystemUiVisibility(android.view.View);
+    method @Deprecated public static float getX(android.view.View!);
+    method @Deprecated public static float getY(android.view.View!);
+    method public static float getZ(android.view.View);
+    method public static boolean hasAccessibilityDelegate(android.view.View);
+    method public static boolean hasExplicitFocusable(android.view.View);
+    method public static boolean hasNestedScrollingParent(android.view.View);
+    method public static boolean hasNestedScrollingParent(android.view.View, @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public static boolean hasOnClickListeners(android.view.View);
+    method public static boolean hasOverlappingRendering(android.view.View);
+    method public static boolean hasTransientState(android.view.View);
+    method @UiThread public static boolean isAccessibilityHeading(android.view.View!);
+    method public static boolean isAttachedToWindow(android.view.View);
+    method public static boolean isFocusedByDefault(android.view.View);
+    method public static boolean isImportantForAccessibility(android.view.View);
+    method public static boolean isImportantForAutofill(android.view.View);
+    method public static boolean isInLayout(android.view.View);
+    method public static boolean isKeyboardNavigationCluster(android.view.View);
+    method public static boolean isLaidOut(android.view.View);
+    method public static boolean isLayoutDirectionResolved(android.view.View);
+    method public static boolean isNestedScrollingEnabled(android.view.View);
+    method @Deprecated public static boolean isOpaque(android.view.View!);
+    method public static boolean isPaddingRelative(android.view.View);
+    method @UiThread public static boolean isScreenReaderFocusable(android.view.View!);
+    method @Deprecated public static void jumpDrawablesToCurrentState(android.view.View!);
+    method public static android.view.View! keyboardNavigationClusterSearch(android.view.View, android.view.View!, @androidx.core.view.ViewCompat.FocusDirection int);
+    method public static void offsetLeftAndRight(android.view.View, int);
+    method public static void offsetTopAndBottom(android.view.View, int);
+    method public static androidx.core.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, androidx.core.view.WindowInsetsCompat);
+    method @Deprecated public static void onInitializeAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public static void onInitializeAccessibilityNodeInfo(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat!);
+    method @Deprecated public static void onPopulateAccessibilityEvent(android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public static boolean performAccessibilityAction(android.view.View, int, android.os.Bundle!);
+    method public static androidx.core.view.ContentInfoCompat? performReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+    method public static void postInvalidateOnAnimation(android.view.View);
+    method public static void postInvalidateOnAnimation(android.view.View, int, int, int, int);
+    method public static void postOnAnimation(android.view.View, Runnable!);
+    method public static void postOnAnimationDelayed(android.view.View, Runnable!, long);
+    method public static void removeAccessibilityAction(android.view.View, int);
+    method public static void removeOnUnhandledKeyEventListener(android.view.View, androidx.core.view.ViewCompat.OnUnhandledKeyEventListenerCompat);
+    method public static void replaceAccessibilityAction(android.view.View, androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat, CharSequence?, androidx.core.view.accessibility.AccessibilityViewCommand?);
+    method public static void requestApplyInsets(android.view.View);
+    method public static <T extends android.view.View> T requireViewById(android.view.View, @IdRes int);
+    method @Deprecated public static int resolveSizeAndState(int, int, int);
+    method public static boolean restoreDefaultFocus(android.view.View);
+    method public static void saveAttributeDataForStyleable(android.view.View, android.content.Context, int[], android.util.AttributeSet?, android.content.res.TypedArray, int, int);
+    method public static void setAccessibilityDelegate(android.view.View, androidx.core.view.AccessibilityDelegateCompat!);
+    method @UiThread public static void setAccessibilityHeading(android.view.View!, boolean);
+    method public static void setAccessibilityLiveRegion(android.view.View, int);
+    method @UiThread public static void setAccessibilityPaneTitle(android.view.View!, CharSequence!);
+    method @Deprecated public static void setActivated(android.view.View!, boolean);
+    method @Deprecated public static void setAlpha(android.view.View!, @FloatRange(from=0.0, to=1.0) float);
+    method public static void setAutofillHints(android.view.View, java.lang.String!...);
+    method public static void setBackground(android.view.View, android.graphics.drawable.Drawable?);
+    method public static void setBackgroundTintList(android.view.View, android.content.res.ColorStateList!);
+    method public static void setBackgroundTintMode(android.view.View, android.graphics.PorterDuff.Mode!);
+    method @Deprecated public static void setChildrenDrawingOrderEnabled(android.view.ViewGroup!, boolean);
+    method public static void setClipBounds(android.view.View, android.graphics.Rect!);
+    method public static void setElevation(android.view.View, float);
+    method @Deprecated public static void setFitsSystemWindows(android.view.View!, boolean);
+    method public static void setFocusedByDefault(android.view.View, boolean);
+    method public static void setHasTransientState(android.view.View, boolean);
+    method public static void setImportantForAccessibility(android.view.View, int);
+    method public static void setImportantForAutofill(android.view.View, int);
+    method public static void setKeyboardNavigationCluster(android.view.View, boolean);
+    method public static void setLabelFor(android.view.View, @IdRes int);
+    method public static void setLayerPaint(android.view.View, android.graphics.Paint!);
+    method @Deprecated public static void setLayerType(android.view.View!, int, android.graphics.Paint!);
+    method public static void setLayoutDirection(android.view.View, int);
+    method public static void setNestedScrollingEnabled(android.view.View, boolean);
+    method public static void setNextClusterForwardId(android.view.View, int);
+    method public static void setOnApplyWindowInsetsListener(android.view.View, androidx.core.view.OnApplyWindowInsetsListener?);
+    method public static void setOnReceiveContentListener(android.view.View, String![]?, androidx.core.view.OnReceiveContentListener?);
+    method @Deprecated public static void setOverScrollMode(android.view.View!, int);
+    method public static void setPaddingRelative(android.view.View, @Px int, @Px int, @Px int, @Px int);
+    method @Deprecated public static void setPivotX(android.view.View!, float);
+    method @Deprecated public static void setPivotY(android.view.View!, float);
+    method public static void setPointerIcon(android.view.View, androidx.core.view.PointerIconCompat!);
+    method @Deprecated public static void setRotation(android.view.View!, float);
+    method @Deprecated public static void setRotationX(android.view.View!, float);
+    method @Deprecated public static void setRotationY(android.view.View!, float);
+    method @Deprecated public static void setSaveFromParentEnabled(android.view.View!, boolean);
+    method @Deprecated public static void setScaleX(android.view.View!, float);
+    method @Deprecated public static void setScaleY(android.view.View!, float);
+    method @UiThread public static void setScreenReaderFocusable(android.view.View!, boolean);
+    method public static void setScrollIndicators(android.view.View, @androidx.core.view.ViewCompat.ScrollIndicators int);
+    method public static void setScrollIndicators(android.view.View, @androidx.core.view.ViewCompat.ScrollIndicators int, @androidx.core.view.ViewCompat.ScrollIndicators int);
+    method @UiThread public static void setStateDescription(android.view.View, CharSequence?);
+    method public static void setSystemGestureExclusionRects(android.view.View, java.util.List<android.graphics.Rect!>);
+    method public static void setTooltipText(android.view.View, CharSequence?);
+    method public static void setTransitionName(android.view.View, String!);
+    method @Deprecated public static void setTranslationX(android.view.View!, float);
+    method @Deprecated public static void setTranslationY(android.view.View!, float);
+    method public static void setTranslationZ(android.view.View, float);
+    method public static void setWindowInsetsAnimationCallback(android.view.View, androidx.core.view.WindowInsetsAnimationCompat.Callback?);
+    method @Deprecated public static void setX(android.view.View!, float);
+    method @Deprecated public static void setY(android.view.View!, float);
+    method public static void setZ(android.view.View, float);
+    method public static boolean startDragAndDrop(android.view.View, android.content.ClipData!, android.view.View.DragShadowBuilder!, Object!, int);
+    method public static boolean startNestedScroll(android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int);
+    method public static boolean startNestedScroll(android.view.View, @androidx.core.view.ViewCompat.ScrollAxis int, @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public static void stopNestedScroll(android.view.View);
+    method public static void stopNestedScroll(android.view.View, @androidx.core.view.ViewCompat.NestedScrollType int);
+    method public static void updateDragShadow(android.view.View, android.view.View.DragShadowBuilder!);
+    field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2
+    field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0
+    field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0; // 0x0
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 2; // 0x2
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 4; // 0x4
+    field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
+    field @Deprecated public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
+    field @Deprecated public static final int LAYER_TYPE_NONE = 0; // 0x0
+    field @Deprecated public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
+    field public static final int LAYOUT_DIRECTION_INHERIT = 2; // 0x2
+    field public static final int LAYOUT_DIRECTION_LOCALE = 3; // 0x3
+    field public static final int LAYOUT_DIRECTION_LTR = 0; // 0x0
+    field public static final int LAYOUT_DIRECTION_RTL = 1; // 0x1
+    field @Deprecated public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; // 0x10
+    field @Deprecated public static final int MEASURED_SIZE_MASK = 16777215; // 0xffffff
+    field @Deprecated public static final int MEASURED_STATE_MASK = -16777216; // 0xff000000
+    field @Deprecated public static final int MEASURED_STATE_TOO_SMALL = 16777216; // 0x1000000
+    field @Deprecated public static final int OVER_SCROLL_ALWAYS = 0; // 0x0
+    field @Deprecated public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; // 0x1
+    field @Deprecated public static final int OVER_SCROLL_NEVER = 2; // 0x2
+    field public static final int SCROLL_AXIS_HORIZONTAL = 1; // 0x1
+    field public static final int SCROLL_AXIS_NONE = 0; // 0x0
+    field public static final int SCROLL_AXIS_VERTICAL = 2; // 0x2
+    field public static final int SCROLL_INDICATOR_BOTTOM = 2; // 0x2
+    field public static final int SCROLL_INDICATOR_END = 32; // 0x20
+    field public static final int SCROLL_INDICATOR_LEFT = 4; // 0x4
+    field public static final int SCROLL_INDICATOR_RIGHT = 8; // 0x8
+    field public static final int SCROLL_INDICATOR_START = 16; // 0x10
+    field public static final int SCROLL_INDICATOR_TOP = 1; // 0x1
+    field public static final int TYPE_NON_TOUCH = 1; // 0x1
+    field public static final int TYPE_TOUCH = 0; // 0x0
+  }
+
+  @IntDef({android.view.View.FOCUS_LEFT, android.view.View.FOCUS_UP, android.view.View.FOCUS_RIGHT, android.view.View.FOCUS_DOWN, android.view.View.FOCUS_FORWARD, android.view.View.FOCUS_BACKWARD}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.FocusDirection {
+  }
+
+  @IntDef({android.view.View.FOCUS_LEFT, android.view.View.FOCUS_UP, android.view.View.FOCUS_RIGHT, android.view.View.FOCUS_DOWN}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.FocusRealDirection {
+  }
+
+  @IntDef({android.view.View.FOCUS_FORWARD, android.view.View.FOCUS_BACKWARD}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.FocusRelativeDirection {
+  }
+
+  @IntDef({androidx.core.view.ViewCompat.TYPE_TOUCH, androidx.core.view.ViewCompat.TYPE_NON_TOUCH}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.NestedScrollType {
+  }
+
+  public static interface ViewCompat.OnUnhandledKeyEventListenerCompat {
+    method public boolean onUnhandledKeyEvent(android.view.View!, android.view.KeyEvent!);
+  }
+
+  @IntDef(value={androidx.core.view.ViewCompat.SCROLL_AXIS_NONE, androidx.core.view.ViewCompat.SCROLL_AXIS_HORIZONTAL, androidx.core.view.ViewCompat.SCROLL_AXIS_VERTICAL}, flag=true) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.ScrollAxis {
+  }
+
+  @IntDef(flag=true, value={androidx.core.view.ViewCompat.SCROLL_INDICATOR_TOP, androidx.core.view.ViewCompat.SCROLL_INDICATOR_BOTTOM, androidx.core.view.ViewCompat.SCROLL_INDICATOR_LEFT, androidx.core.view.ViewCompat.SCROLL_INDICATOR_RIGHT, androidx.core.view.ViewCompat.SCROLL_INDICATOR_START, androidx.core.view.ViewCompat.SCROLL_INDICATOR_END}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface ViewCompat.ScrollIndicators {
+  }
+
+  public final class ViewConfigurationCompat {
+    method public static float getScaledHorizontalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+    method public static int getScaledHoverSlop(android.view.ViewConfiguration!);
+    method @Deprecated public static int getScaledPagingTouchSlop(android.view.ViewConfiguration!);
+    method public static float getScaledVerticalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+    method @Deprecated public static boolean hasPermanentMenuKey(android.view.ViewConfiguration!);
+    method public static boolean shouldShowMenuShortcutsWhenKeyboardPresent(android.view.ViewConfiguration!, android.content.Context);
+  }
+
+  public final class ViewGroupCompat {
+    method public static int getLayoutMode(android.view.ViewGroup);
+    method @androidx.core.view.ViewCompat.ScrollAxis public static int getNestedScrollAxes(android.view.ViewGroup);
+    method public static boolean isTransitionGroup(android.view.ViewGroup);
+    method @Deprecated public static boolean onRequestSendAccessibilityEvent(android.view.ViewGroup!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+    method public static void setLayoutMode(android.view.ViewGroup, int);
+    method @Deprecated public static void setMotionEventSplittingEnabled(android.view.ViewGroup!, boolean);
+    method public static void setTransitionGroup(android.view.ViewGroup, boolean);
+    field public static final int LAYOUT_MODE_CLIP_BOUNDS = 0; // 0x0
+    field public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1; // 0x1
+  }
+
+  public final class ViewParentCompat {
+    method public static void notifySubtreeAccessibilityStateChanged(android.view.ViewParent!, android.view.View!, android.view.View!, int);
+    method public static boolean onNestedFling(android.view.ViewParent!, android.view.View!, float, float, boolean);
+    method public static boolean onNestedPreFling(android.view.ViewParent!, android.view.View!, float, float);
+    method public static void onNestedPreScroll(android.view.ViewParent!, android.view.View!, int, int, int[]!);
+    method public static void onNestedPreScroll(android.view.ViewParent!, android.view.View!, int, int, int[]!, int);
+    method public static void onNestedScroll(android.view.ViewParent!, android.view.View!, int, int, int, int);
+    method public static void onNestedScroll(android.view.ViewParent!, android.view.View!, int, int, int, int, int);
+    method public static void onNestedScroll(android.view.ViewParent!, android.view.View!, int, int, int, int, int, int[]);
+    method public static void onNestedScrollAccepted(android.view.ViewParent!, android.view.View!, android.view.View!, int);
+    method public static void onNestedScrollAccepted(android.view.ViewParent!, android.view.View!, android.view.View!, int, int);
+    method public static boolean onStartNestedScroll(android.view.ViewParent!, android.view.View!, android.view.View!, int);
+    method public static boolean onStartNestedScroll(android.view.ViewParent!, android.view.View!, android.view.View!, int, int);
+    method public static void onStopNestedScroll(android.view.ViewParent!, android.view.View!);
+    method public static void onStopNestedScroll(android.view.ViewParent!, android.view.View!, int);
+    method @Deprecated public static boolean requestSendAccessibilityEvent(android.view.ViewParent!, android.view.View!, android.view.accessibility.AccessibilityEvent!);
+  }
+
+  public final class ViewPropertyAnimatorCompat {
+    method public androidx.core.view.ViewPropertyAnimatorCompat! alpha(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! alphaBy(float);
+    method public void cancel();
+    method public long getDuration();
+    method public android.view.animation.Interpolator! getInterpolator();
+    method public long getStartDelay();
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotation(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotationBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotationX(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotationXBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotationY(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! rotationYBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! scaleX(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! scaleXBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! scaleY(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! scaleYBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! setDuration(long);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! setInterpolator(android.view.animation.Interpolator!);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! setListener(androidx.core.view.ViewPropertyAnimatorListener!);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! setStartDelay(long);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! setUpdateListener(androidx.core.view.ViewPropertyAnimatorUpdateListener!);
+    method public void start();
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationX(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationXBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationY(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationYBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationZ(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! translationZBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! withEndAction(Runnable!);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! withLayer();
+    method public androidx.core.view.ViewPropertyAnimatorCompat! withStartAction(Runnable!);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! x(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! xBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! y(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! yBy(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! z(float);
+    method public androidx.core.view.ViewPropertyAnimatorCompat! zBy(float);
+  }
+
+  public interface ViewPropertyAnimatorListener {
+    method public void onAnimationCancel(android.view.View!);
+    method public void onAnimationEnd(android.view.View!);
+    method public void onAnimationStart(android.view.View!);
+  }
+
+  public class ViewPropertyAnimatorListenerAdapter implements androidx.core.view.ViewPropertyAnimatorListener {
+    ctor public ViewPropertyAnimatorListenerAdapter();
+    method public void onAnimationCancel(android.view.View!);
+    method public void onAnimationEnd(android.view.View!);
+    method public void onAnimationStart(android.view.View!);
+  }
+
+  public interface ViewPropertyAnimatorUpdateListener {
+    method public void onAnimationUpdate(android.view.View!);
+  }
+
+  public final class WindowCompat {
+    method public static androidx.core.view.WindowInsetsControllerCompat? getInsetsController(android.view.Window, android.view.View);
+    method public static <T extends android.view.View> T requireViewById(android.view.Window, @IdRes int);
+    method public static void setDecorFitsSystemWindows(android.view.Window, boolean);
+    field public static final int FEATURE_ACTION_BAR = 8; // 0x8
+    field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
+    field public static final int FEATURE_ACTION_MODE_OVERLAY = 10; // 0xa
+  }
+
+  public final class WindowInsetsAnimationCompat {
+    ctor public WindowInsetsAnimationCompat(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, android.view.animation.Interpolator?, long);
+    method @FloatRange(from=0.0f, to=1.0f) public float getAlpha();
+    method public long getDurationMillis();
+    method @FloatRange(from=0.0f, to=1.0f) public float getFraction();
+    method public float getInterpolatedFraction();
+    method public android.view.animation.Interpolator? getInterpolator();
+    method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public int getTypeMask();
+    method public void setAlpha(@FloatRange(from=0.0f, to=1.0f) float);
+    method public void setFraction(@FloatRange(from=0.0f, to=1.0f) float);
+  }
+
+  public static final class WindowInsetsAnimationCompat.BoundsCompat {
+    ctor public WindowInsetsAnimationCompat.BoundsCompat(androidx.core.graphics.Insets, androidx.core.graphics.Insets);
+    method public androidx.core.graphics.Insets getLowerBound();
+    method public androidx.core.graphics.Insets getUpperBound();
+    method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat inset(androidx.core.graphics.Insets);
+    method @RequiresApi(30) public android.view.WindowInsetsAnimation.Bounds toBounds();
+    method @RequiresApi(30) public static androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat toBoundsCompat(android.view.WindowInsetsAnimation.Bounds);
+  }
+
+  public abstract static class WindowInsetsAnimationCompat.Callback {
+    ctor public WindowInsetsAnimationCompat.Callback(@androidx.core.view.WindowInsetsAnimationCompat.Callback.DispatchMode int);
+    method @androidx.core.view.WindowInsetsAnimationCompat.Callback.DispatchMode public final int getDispatchMode();
+    method public void onEnd(androidx.core.view.WindowInsetsAnimationCompat);
+    method public void onPrepare(androidx.core.view.WindowInsetsAnimationCompat);
+    method public abstract androidx.core.view.WindowInsetsCompat onProgress(androidx.core.view.WindowInsetsCompat, java.util.List<androidx.core.view.WindowInsetsAnimationCompat!>);
+    method public androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat onStart(androidx.core.view.WindowInsetsAnimationCompat, androidx.core.view.WindowInsetsAnimationCompat.BoundsCompat);
+    field public static final int DISPATCH_MODE_CONTINUE_ON_SUBTREE = 1; // 0x1
+    field public static final int DISPATCH_MODE_STOP = 0; // 0x0
+  }
+
+  @IntDef({androidx.core.view.WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_STOP, androidx.core.view.WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface WindowInsetsAnimationCompat.Callback.DispatchMode {
+  }
+
+  public interface WindowInsetsAnimationControlListenerCompat {
+    method public void onCancelled(androidx.core.view.WindowInsetsAnimationControllerCompat?);
+    method public void onFinished(androidx.core.view.WindowInsetsAnimationControllerCompat);
+    method public void onReady(androidx.core.view.WindowInsetsAnimationControllerCompat, @androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+  }
+
+  public final class WindowInsetsAnimationControllerCompat {
+    method public void finish(boolean);
+    method public float getCurrentAlpha();
+    method @FloatRange(from=0.0f, to=1.0f) public float getCurrentFraction();
+    method public androidx.core.graphics.Insets getCurrentInsets();
+    method public androidx.core.graphics.Insets getHiddenStateInsets();
+    method public androidx.core.graphics.Insets getShownStateInsets();
+    method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public int getTypes();
+    method public boolean isCancelled();
+    method public boolean isFinished();
+    method public boolean isReady();
+    method public void setInsetsAndAlpha(androidx.core.graphics.Insets?, @FloatRange(from=0.0f, to=1.0f) float, @FloatRange(from=0.0f, to=1.0f) float);
+  }
+
+  public class WindowInsetsCompat {
+    ctor public WindowInsetsCompat(androidx.core.view.WindowInsetsCompat?);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat consumeDisplayCutout();
+    method @Deprecated public androidx.core.view.WindowInsetsCompat consumeStableInsets();
+    method @Deprecated public androidx.core.view.WindowInsetsCompat consumeSystemWindowInsets();
+    method public androidx.core.view.DisplayCutoutCompat? getDisplayCutout();
+    method public androidx.core.graphics.Insets getInsets(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+    method public androidx.core.graphics.Insets getInsetsIgnoringVisibility(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+    method @Deprecated public androidx.core.graphics.Insets getMandatorySystemGestureInsets();
+    method @Deprecated public int getStableInsetBottom();
+    method @Deprecated public int getStableInsetLeft();
+    method @Deprecated public int getStableInsetRight();
+    method @Deprecated public int getStableInsetTop();
+    method @Deprecated public androidx.core.graphics.Insets getStableInsets();
+    method @Deprecated public androidx.core.graphics.Insets getSystemGestureInsets();
+    method @Deprecated public int getSystemWindowInsetBottom();
+    method @Deprecated public int getSystemWindowInsetLeft();
+    method @Deprecated public int getSystemWindowInsetRight();
+    method @Deprecated public int getSystemWindowInsetTop();
+    method @Deprecated public androidx.core.graphics.Insets getSystemWindowInsets();
+    method @Deprecated public androidx.core.graphics.Insets getTappableElementInsets();
+    method public boolean hasInsets();
+    method @Deprecated public boolean hasStableInsets();
+    method @Deprecated public boolean hasSystemWindowInsets();
+    method public androidx.core.view.WindowInsetsCompat inset(androidx.core.graphics.Insets);
+    method public androidx.core.view.WindowInsetsCompat inset(@IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int, @IntRange(from=0) int);
+    method public boolean isConsumed();
+    method public boolean isRound();
+    method public boolean isVisible(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(int, int, int, int);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat replaceSystemWindowInsets(android.graphics.Rect);
+    method @RequiresApi(20) public android.view.WindowInsets? toWindowInsets();
+    method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets);
+    method @RequiresApi(20) public static androidx.core.view.WindowInsetsCompat toWindowInsetsCompat(android.view.WindowInsets, android.view.View?);
+    field public static final androidx.core.view.WindowInsetsCompat CONSUMED;
+  }
+
+  public static final class WindowInsetsCompat.Builder {
+    ctor public WindowInsetsCompat.Builder();
+    ctor public WindowInsetsCompat.Builder(androidx.core.view.WindowInsetsCompat);
+    method public androidx.core.view.WindowInsetsCompat build();
+    method public androidx.core.view.WindowInsetsCompat.Builder setDisplayCutout(androidx.core.view.DisplayCutoutCompat?);
+    method public androidx.core.view.WindowInsetsCompat.Builder setInsets(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, androidx.core.graphics.Insets);
+    method public androidx.core.view.WindowInsetsCompat.Builder setInsetsIgnoringVisibility(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, androidx.core.graphics.Insets);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setMandatorySystemGestureInsets(androidx.core.graphics.Insets);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setStableInsets(androidx.core.graphics.Insets);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemGestureInsets(androidx.core.graphics.Insets);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setSystemWindowInsets(androidx.core.graphics.Insets);
+    method @Deprecated public androidx.core.view.WindowInsetsCompat.Builder setTappableElementInsets(androidx.core.graphics.Insets);
+    method public androidx.core.view.WindowInsetsCompat.Builder setVisible(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, boolean);
+  }
+
+  public static final class WindowInsetsCompat.Type {
+    method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int captionBar();
+    method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int displayCutout();
+    method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int ime();
+    method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int mandatorySystemGestures();
+    method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int navigationBars();
+    method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int statusBars();
+    method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int systemBars();
+    method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int systemGestures();
+    method @androidx.core.view.WindowInsetsCompat.Type.InsetsType public static int tappableElement();
+  }
+
+  @IntDef(flag=true, value={androidx.core.view.WindowInsetsCompat.Type.STATUS_BARS, androidx.core.view.WindowInsetsCompat.Type.NAVIGATION_BARS, androidx.core.view.WindowInsetsCompat.Type.CAPTION_BAR, androidx.core.view.WindowInsetsCompat.Type.IME, androidx.core.view.WindowInsetsCompat.Type.WINDOW_DECOR, androidx.core.view.WindowInsetsCompat.Type.SYSTEM_GESTURES, androidx.core.view.WindowInsetsCompat.Type.MANDATORY_SYSTEM_GESTURES, androidx.core.view.WindowInsetsCompat.Type.TAPPABLE_ELEMENT, androidx.core.view.WindowInsetsCompat.Type.DISPLAY_CUTOUT}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface WindowInsetsCompat.Type.InsetsType {
+  }
+
+  public final class WindowInsetsControllerCompat {
+    ctor public WindowInsetsControllerCompat(android.view.Window, android.view.View);
+    method public void addOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+    method public void controlWindowInsetsAnimation(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int, long, android.view.animation.Interpolator?, android.os.CancellationSignal?, androidx.core.view.WindowInsetsAnimationControlListenerCompat);
+    method public int getSystemBarsBehavior();
+    method public void hide(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+    method public boolean isAppearanceLightNavigationBars();
+    method public boolean isAppearanceLightStatusBars();
+    method public void removeOnControllableInsetsChangedListener(androidx.core.view.WindowInsetsControllerCompat.OnControllableInsetsChangedListener);
+    method public void setAppearanceLightNavigationBars(boolean);
+    method public void setAppearanceLightStatusBars(boolean);
+    method public void setSystemBarsBehavior(int);
+    method public void show(@androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+    method @RequiresApi(30) public static androidx.core.view.WindowInsetsControllerCompat toWindowInsetsControllerCompat(android.view.WindowInsetsController);
+    field public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
+    field public static final int BEHAVIOR_SHOW_BARS_BY_TOUCH = 0; // 0x0
+    field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2
+  }
+
+  public static interface WindowInsetsControllerCompat.OnControllableInsetsChangedListener {
+    method public void onControllableInsetsChanged(androidx.core.view.WindowInsetsControllerCompat, @androidx.core.view.WindowInsetsCompat.Type.InsetsType int);
+  }
+
+}
+
+package androidx.core.view.accessibility {
+
+  public final class AccessibilityClickableSpanCompat extends android.text.style.ClickableSpan {
+    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public AccessibilityClickableSpanCompat(int, androidx.core.view.accessibility.AccessibilityNodeInfoCompat!, int);
+    method public void onClick(android.view.View);
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final String SPAN_ID = "ACCESSIBILITY_CLICKABLE_SPAN_ID";
+  }
+
+  public final class AccessibilityEventCompat {
+    method @Deprecated public static void appendRecord(android.view.accessibility.AccessibilityEvent!, androidx.core.view.accessibility.AccessibilityRecordCompat!);
+    method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! asRecord(android.view.accessibility.AccessibilityEvent!);
+    method public static int getAction(android.view.accessibility.AccessibilityEvent!);
+    method @androidx.core.view.accessibility.AccessibilityEventCompat.ContentChangeType public static int getContentChangeTypes(android.view.accessibility.AccessibilityEvent!);
+    method public static int getMovementGranularity(android.view.accessibility.AccessibilityEvent!);
+    method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! getRecord(android.view.accessibility.AccessibilityEvent!, int);
+    method @Deprecated public static int getRecordCount(android.view.accessibility.AccessibilityEvent!);
+    method public static void setAction(android.view.accessibility.AccessibilityEvent!, int);
+    method public static void setContentChangeTypes(android.view.accessibility.AccessibilityEvent!, @androidx.core.view.accessibility.AccessibilityEventCompat.ContentChangeType int);
+    method public static void setMovementGranularity(android.view.accessibility.AccessibilityEvent!, int);
+    field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+    field public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 16; // 0x10
+    field public static final int CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 32; // 0x20
+    field public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 8; // 0x8
+    field public static final int CONTENT_CHANGE_TYPE_STATE_DESCRIPTION = 64; // 0x40
+    field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1
+    field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2
+    field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0
+    field public static final int TYPES_ALL_MASK = -1; // 0xffffffff
+    field public static final int TYPE_ANNOUNCEMENT = 16384; // 0x4000
+    field public static final int TYPE_ASSIST_READING_CONTEXT = 16777216; // 0x1000000
+    field public static final int TYPE_GESTURE_DETECTION_END = 524288; // 0x80000
+    field public static final int TYPE_GESTURE_DETECTION_START = 262144; // 0x40000
+    field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_END = 1024; // 0x400
+    field @Deprecated public static final int TYPE_TOUCH_EXPLORATION_GESTURE_START = 512; // 0x200
+    field public static final int TYPE_TOUCH_INTERACTION_END = 2097152; // 0x200000
+    field public static final int TYPE_TOUCH_INTERACTION_START = 1048576; // 0x100000
+    field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUSED = 32768; // 0x8000
+    field public static final int TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED = 65536; // 0x10000
+    field public static final int TYPE_VIEW_CONTEXT_CLICKED = 8388608; // 0x800000
+    field @Deprecated public static final int TYPE_VIEW_HOVER_ENTER = 128; // 0x80
+    field @Deprecated public static final int TYPE_VIEW_HOVER_EXIT = 256; // 0x100
+    field @Deprecated public static final int TYPE_VIEW_SCROLLED = 4096; // 0x1000
+    field @Deprecated public static final int TYPE_VIEW_TEXT_SELECTION_CHANGED = 8192; // 0x2000
+    field public static final int TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY = 131072; // 0x20000
+    field public static final int TYPE_WINDOWS_CHANGED = 4194304; // 0x400000
+    field @Deprecated public static final int TYPE_WINDOW_CONTENT_CHANGED = 2048; // 0x800
+  }
+
+  @IntDef(flag=true, value={androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_SUBTREE, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_TEXT, androidx.core.view.accessibility.AccessibilityEventCompat.CONTENT_CHANGE_TYPE_UNDEFINED}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface AccessibilityEventCompat.ContentChangeType {
+  }
+
+  public final class AccessibilityManagerCompat {
+    method @Deprecated public static boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+    method public static boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener!);
+    method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getEnabledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!, int);
+    method @Deprecated public static java.util.List<android.accessibilityservice.AccessibilityServiceInfo!>! getInstalledAccessibilityServiceList(android.view.accessibility.AccessibilityManager!);
+    method @Deprecated public static boolean isTouchExplorationEnabled(android.view.accessibility.AccessibilityManager!);
+    method @Deprecated public static boolean removeAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener!);
+    method public static boolean removeTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager!, androidx.core.view.accessibility.AccessibilityManagerCompat.TouchExplorationStateChangeListener!);
+  }
+
+  @Deprecated public static interface AccessibilityManagerCompat.AccessibilityStateChangeListener {
+    method @Deprecated public void onAccessibilityStateChanged(boolean);
+  }
+
+  @Deprecated public abstract static class AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat implements androidx.core.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListener {
+    ctor @Deprecated public AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat();
+  }
+
+  public static interface AccessibilityManagerCompat.TouchExplorationStateChangeListener {
+    method public void onTouchExplorationStateChanged(boolean);
+  }
+
+  public class AccessibilityNodeInfoCompat {
+    ctor @Deprecated public AccessibilityNodeInfoCompat(Object!);
+    method public void addAction(int);
+    method public void addAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+    method public void addChild(android.view.View!);
+    method public void addChild(android.view.View!, int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void addSpansToExtras(CharSequence!, android.view.View!);
+    method public boolean canOpenPopup();
+    method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByText(String!);
+    method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>! findAccessibilityNodeInfosByViewId(String!);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! findFocus(int);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! focusSearch(int);
+    method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!>! getActionList();
+    method public int getActions();
+    method @Deprecated public void getBoundsInParent(android.graphics.Rect!);
+    method public void getBoundsInScreen(android.graphics.Rect!);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getChild(int);
+    method public int getChildCount();
+    method public CharSequence! getClassName();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.text.style.ClickableSpan![]! getClickableSpans(CharSequence!);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! getCollectionInfo();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! getCollectionItemInfo();
+    method public CharSequence! getContentDescription();
+    method public int getDrawingOrder();
+    method public CharSequence! getError();
+    method public android.os.Bundle! getExtras();
+    method public CharSequence? getHintText();
+    method @Deprecated public Object! getInfo();
+    method public int getInputType();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabelFor();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getLabeledBy();
+    method public int getLiveRegion();
+    method public int getMaxTextLength();
+    method public int getMovementGranularities();
+    method public CharSequence! getPackageName();
+    method public CharSequence? getPaneTitle();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getParent();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! getRangeInfo();
+    method public CharSequence? getRoleDescription();
+    method public CharSequence? getStateDescription();
+    method public CharSequence! getText();
+    method public int getTextSelectionEnd();
+    method public int getTextSelectionStart();
+    method public CharSequence? getTooltipText();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat? getTouchDelegateInfo();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalAfter();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getTraversalBefore();
+    method public String! getViewIdResourceName();
+    method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat! getWindow();
+    method public int getWindowId();
+    method public boolean isAccessibilityFocused();
+    method public boolean isCheckable();
+    method public boolean isChecked();
+    method public boolean isClickable();
+    method public boolean isContentInvalid();
+    method public boolean isContextClickable();
+    method public boolean isDismissable();
+    method public boolean isEditable();
+    method public boolean isEnabled();
+    method public boolean isFocusable();
+    method public boolean isFocused();
+    method public boolean isHeading();
+    method public boolean isImportantForAccessibility();
+    method public boolean isLongClickable();
+    method public boolean isMultiLine();
+    method public boolean isPassword();
+    method public boolean isScreenReaderFocusable();
+    method public boolean isScrollable();
+    method public boolean isSelected();
+    method public boolean isShowingHintText();
+    method public boolean isTextEntryKey();
+    method public boolean isVisibleToUser();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!);
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(android.view.View!, int);
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! obtain(androidx.core.view.accessibility.AccessibilityNodeInfoCompat!);
+    method public boolean performAction(int);
+    method public boolean performAction(int, android.os.Bundle!);
+    method public void recycle();
+    method public boolean refresh();
+    method public boolean removeAction(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat!);
+    method public boolean removeChild(android.view.View!);
+    method public boolean removeChild(android.view.View!, int);
+    method public void setAccessibilityFocused(boolean);
+    method @Deprecated public void setBoundsInParent(android.graphics.Rect!);
+    method public void setBoundsInScreen(android.graphics.Rect!);
+    method public void setCanOpenPopup(boolean);
+    method public void setCheckable(boolean);
+    method public void setChecked(boolean);
+    method public void setClassName(CharSequence!);
+    method public void setClickable(boolean);
+    method public void setCollectionInfo(Object!);
+    method public void setCollectionItemInfo(Object!);
+    method public void setContentDescription(CharSequence!);
+    method public void setContentInvalid(boolean);
+    method public void setContextClickable(boolean);
+    method public void setDismissable(boolean);
+    method public void setDrawingOrder(int);
+    method public void setEditable(boolean);
+    method public void setEnabled(boolean);
+    method public void setError(CharSequence!);
+    method public void setFocusable(boolean);
+    method public void setFocused(boolean);
+    method public void setHeading(boolean);
+    method public void setHintText(CharSequence?);
+    method public void setImportantForAccessibility(boolean);
+    method public void setInputType(int);
+    method public void setLabelFor(android.view.View!);
+    method public void setLabelFor(android.view.View!, int);
+    method public void setLabeledBy(android.view.View!);
+    method public void setLabeledBy(android.view.View!, int);
+    method public void setLiveRegion(int);
+    method public void setLongClickable(boolean);
+    method public void setMaxTextLength(int);
+    method public void setMovementGranularities(int);
+    method public void setMultiLine(boolean);
+    method public void setPackageName(CharSequence!);
+    method public void setPaneTitle(CharSequence?);
+    method public void setParent(android.view.View!);
+    method public void setParent(android.view.View!, int);
+    method public void setPassword(boolean);
+    method public void setRangeInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat!);
+    method public void setRoleDescription(CharSequence?);
+    method public void setScreenReaderFocusable(boolean);
+    method public void setScrollable(boolean);
+    method public void setSelected(boolean);
+    method public void setShowingHintText(boolean);
+    method public void setSource(android.view.View!);
+    method public void setSource(android.view.View!, int);
+    method public void setStateDescription(CharSequence?);
+    method public void setText(CharSequence!);
+    method public void setTextEntryKey(boolean);
+    method public void setTextSelection(int, int);
+    method public void setTooltipText(CharSequence?);
+    method public void setTouchDelegateInfo(androidx.core.view.accessibility.AccessibilityNodeInfoCompat.TouchDelegateInfoCompat);
+    method public void setTraversalAfter(android.view.View!);
+    method public void setTraversalAfter(android.view.View!, int);
+    method public void setTraversalBefore(android.view.View!);
+    method public void setTraversalBefore(android.view.View!, int);
+    method public void setViewIdResourceName(String!);
+    method public void setVisibleToUser(boolean);
+    method public android.view.accessibility.AccessibilityNodeInfo! unwrap();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat! wrap(android.view.accessibility.AccessibilityNodeInfo);
+    field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
+    field public static final String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
+    field public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
+    field public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
+    field public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
+    field public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = "ACTION_ARGUMENT_MOVE_WINDOW_X";
+    field public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = "ACTION_ARGUMENT_MOVE_WINDOW_Y";
+    field public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT = "android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT";
+    field public static final String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
+    field public static final String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
+    field public static final String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
+    field public static final String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
+    field public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
+    field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
+    field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
+    field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
+    field public static final int ACTION_CLICK = 16; // 0x10
+    field public static final int ACTION_COLLAPSE = 524288; // 0x80000
+    field public static final int ACTION_COPY = 16384; // 0x4000
+    field public static final int ACTION_CUT = 65536; // 0x10000
+    field public static final int ACTION_DISMISS = 1048576; // 0x100000
+    field public static final int ACTION_EXPAND = 262144; // 0x40000
+    field public static final int ACTION_FOCUS = 1; // 0x1
+    field public static final int ACTION_LONG_CLICK = 32; // 0x20
+    field public static final int ACTION_NEXT_AT_MOVEMENT_GRANULARITY = 256; // 0x100
+    field public static final int ACTION_NEXT_HTML_ELEMENT = 1024; // 0x400
+    field public static final int ACTION_PASTE = 32768; // 0x8000
+    field public static final int ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY = 512; // 0x200
+    field public static final int ACTION_PREVIOUS_HTML_ELEMENT = 2048; // 0x800
+    field public static final int ACTION_SCROLL_BACKWARD = 8192; // 0x2000
+    field public static final int ACTION_SCROLL_FORWARD = 4096; // 0x1000
+    field public static final int ACTION_SELECT = 4; // 0x4
+    field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
+    field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
+    field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
+    field public static final int FOCUS_INPUT = 1; // 0x1
+    field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1
+    field public static final int MOVEMENT_GRANULARITY_LINE = 4; // 0x4
+    field public static final int MOVEMENT_GRANULARITY_PAGE = 16; // 0x10
+    field public static final int MOVEMENT_GRANULARITY_PARAGRAPH = 8; // 0x8
+    field public static final int MOVEMENT_GRANULARITY_WORD = 2; // 0x2
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int mParentVirtualDescendantId;
+  }
+
+  public static class AccessibilityNodeInfoCompat.AccessibilityActionCompat {
+    ctor public AccessibilityNodeInfoCompat.AccessibilityActionCompat(int, CharSequence!);
+    ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public AccessibilityNodeInfoCompat.AccessibilityActionCompat(int, CharSequence!, androidx.core.view.accessibility.AccessibilityViewCommand!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! createReplacementAction(CharSequence!, androidx.core.view.accessibility.AccessibilityViewCommand!);
+    method public int getId();
+    method public CharSequence! getLabel();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean perform(android.view.View!, android.os.Bundle!);
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_ACCESSIBILITY_FOCUS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_ACCESSIBILITY_FOCUS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_FOCUS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLEAR_SELECTION;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CLICK;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COLLAPSE;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CONTEXT_CLICK;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_COPY;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_CUT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_DISMISS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_EXPAND;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_FOCUS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_HIDE_TOOLTIP;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_IME_ENTER;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_LONG_CLICK;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_MOVE_WINDOW;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_AT_MOVEMENT_GRANULARITY;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_NEXT_HTML_ELEMENT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_DOWN;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_LEFT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_RIGHT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PAGE_UP;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PASTE;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat ACTION_PRESS_AND_HOLD;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_PREVIOUS_HTML_ELEMENT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_BACKWARD;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_DOWN;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_FORWARD;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_LEFT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_RIGHT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_TO_POSITION;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SCROLL_UP;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SELECT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_PROGRESS;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_SELECTION;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SET_TEXT;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_ON_SCREEN;
+    field public static final androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat! ACTION_SHOW_TOOLTIP;
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) protected final androidx.core.view.accessibility.AccessibilityViewCommand! mCommand;
+  }
+
+  public static class AccessibilityNodeInfoCompat.CollectionInfoCompat {
+    method public int getColumnCount();
+    method public int getRowCount();
+    method public int getSelectionMode();
+    method public boolean isHierarchical();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean, int);
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat! obtain(int, int, boolean);
+    field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
+    field public static final int SELECTION_MODE_NONE = 0; // 0x0
+    field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
+  }
+
+  public static class AccessibilityNodeInfoCompat.CollectionItemInfoCompat {
+    method public int getColumnIndex();
+    method public int getColumnSpan();
+    method public int getRowIndex();
+    method public int getRowSpan();
+    method @Deprecated public boolean isHeading();
+    method public boolean isSelected();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean, boolean);
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat! obtain(int, int, int, int, boolean);
+  }
+
+  public static class AccessibilityNodeInfoCompat.RangeInfoCompat {
+    method public float getCurrent();
+    method public float getMax();
+    method public float getMin();
+    method public int getType();
+    method public static androidx.core.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat! obtain(int, float, float, float);
+    field public static final int RANGE_TYPE_FLOAT = 1; // 0x1
+    field public static final int RANGE_TYPE_INT = 0; // 0x0
+    field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
+  }
+
+  public static final class AccessibilityNodeInfoCompat.TouchDelegateInfoCompat {
+    ctor public AccessibilityNodeInfoCompat.TouchDelegateInfoCompat(java.util.Map<android.graphics.Region!,android.view.View!>);
+    method public android.graphics.Region? getRegionAt(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getRegionCount();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? getTargetForRegion(android.graphics.Region);
+  }
+
+  public class AccessibilityNodeProviderCompat {
+    ctor public AccessibilityNodeProviderCompat();
+    ctor public AccessibilityNodeProviderCompat(Object!);
+    method public void addExtraDataToAccessibilityNodeInfo(int, androidx.core.view.accessibility.AccessibilityNodeInfoCompat, String, android.os.Bundle?);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? createAccessibilityNodeInfo(int);
+    method public java.util.List<androidx.core.view.accessibility.AccessibilityNodeInfoCompat!>? findAccessibilityNodeInfosByText(String!, int);
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat? findFocus(int);
+    method public Object! getProvider();
+    method public boolean performAction(int, int, android.os.Bundle!);
+    field public static final int HOST_VIEW_ID = -1; // 0xffffffff
+  }
+
+  public class AccessibilityRecordCompat {
+    ctor @Deprecated public AccessibilityRecordCompat(Object!);
+    method @Deprecated public boolean equals(Object?);
+    method @Deprecated public int getAddedCount();
+    method @Deprecated public CharSequence! getBeforeText();
+    method @Deprecated public CharSequence! getClassName();
+    method @Deprecated public CharSequence! getContentDescription();
+    method @Deprecated public int getCurrentItemIndex();
+    method @Deprecated public int getFromIndex();
+    method @Deprecated public Object! getImpl();
+    method @Deprecated public int getItemCount();
+    method @Deprecated public int getMaxScrollX();
+    method public static int getMaxScrollX(android.view.accessibility.AccessibilityRecord!);
+    method @Deprecated public int getMaxScrollY();
+    method public static int getMaxScrollY(android.view.accessibility.AccessibilityRecord!);
+    method @Deprecated public android.os.Parcelable! getParcelableData();
+    method @Deprecated public int getRemovedCount();
+    method @Deprecated public int getScrollX();
+    method @Deprecated public int getScrollY();
+    method @Deprecated public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getSource();
+    method @Deprecated public java.util.List<java.lang.CharSequence!>! getText();
+    method @Deprecated public int getToIndex();
+    method @Deprecated public int getWindowId();
+    method @Deprecated public int hashCode();
+    method @Deprecated public boolean isChecked();
+    method @Deprecated public boolean isEnabled();
+    method @Deprecated public boolean isFullScreen();
+    method @Deprecated public boolean isPassword();
+    method @Deprecated public boolean isScrollable();
+    method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain(androidx.core.view.accessibility.AccessibilityRecordCompat!);
+    method @Deprecated public static androidx.core.view.accessibility.AccessibilityRecordCompat! obtain();
+    method @Deprecated public void recycle();
+    method @Deprecated public void setAddedCount(int);
+    method @Deprecated public void setBeforeText(CharSequence!);
+    method @Deprecated public void setChecked(boolean);
+    method @Deprecated public void setClassName(CharSequence!);
+    method @Deprecated public void setContentDescription(CharSequence!);
+    method @Deprecated public void setCurrentItemIndex(int);
+    method @Deprecated public void setEnabled(boolean);
+    method @Deprecated public void setFromIndex(int);
+    method @Deprecated public void setFullScreen(boolean);
+    method @Deprecated public void setItemCount(int);
+    method @Deprecated public void setMaxScrollX(int);
+    method public static void setMaxScrollX(android.view.accessibility.AccessibilityRecord!, int);
+    method @Deprecated public void setMaxScrollY(int);
+    method public static void setMaxScrollY(android.view.accessibility.AccessibilityRecord!, int);
+    method @Deprecated public void setParcelableData(android.os.Parcelable!);
+    method @Deprecated public void setPassword(boolean);
+    method @Deprecated public void setRemovedCount(int);
+    method @Deprecated public void setScrollX(int);
+    method @Deprecated public void setScrollY(int);
+    method @Deprecated public void setScrollable(boolean);
+    method @Deprecated public void setSource(android.view.View!);
+    method @Deprecated public void setSource(android.view.View!, int);
+    method public static void setSource(android.view.accessibility.AccessibilityRecord, android.view.View!, int);
+    method @Deprecated public void setToIndex(int);
+  }
+
+  public interface AccessibilityViewCommand {
+    method public boolean perform(android.view.View, androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments?);
+  }
+
+  public abstract static class AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.CommandArguments();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void setBundle(android.os.Bundle!);
+  }
+
+  public static final class AccessibilityViewCommand.MoveAtGranularityArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.MoveAtGranularityArguments();
+    method public boolean getExtendSelection();
+    method public int getGranularity();
+  }
+
+  public static final class AccessibilityViewCommand.MoveHtmlArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.MoveHtmlArguments();
+    method public String! getHTMLElement();
+  }
+
+  public static final class AccessibilityViewCommand.MoveWindowArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.MoveWindowArguments();
+    method public int getX();
+    method public int getY();
+  }
+
+  public static final class AccessibilityViewCommand.ScrollToPositionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.ScrollToPositionArguments();
+    method public int getColumn();
+    method public int getRow();
+  }
+
+  public static final class AccessibilityViewCommand.SetProgressArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.SetProgressArguments();
+    method public float getProgress();
+  }
+
+  public static final class AccessibilityViewCommand.SetSelectionArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.SetSelectionArguments();
+    method public int getEnd();
+    method public int getStart();
+  }
+
+  public static final class AccessibilityViewCommand.SetTextArguments extends androidx.core.view.accessibility.AccessibilityViewCommand.CommandArguments {
+    ctor public AccessibilityViewCommand.SetTextArguments();
+    method public CharSequence! getText();
+  }
+
+  public class AccessibilityWindowInfoCompat {
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getAnchor();
+    method public void getBoundsInScreen(android.graphics.Rect!);
+    method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat! getChild(int);
+    method public int getChildCount();
+    method public int getId();
+    method public int getLayer();
+    method public androidx.core.view.accessibility.AccessibilityWindowInfoCompat! getParent();
+    method public androidx.core.view.accessibility.AccessibilityNodeInfoCompat! getRoot();
+    method public CharSequence! getTitle();
+    method public int getType();
+    method public boolean isAccessibilityFocused();
+    method public boolean isActive();
+    method public boolean isFocused();
+    method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat! obtain();
+    method public static androidx.core.view.accessibility.AccessibilityWindowInfoCompat! obtain(androidx.core.view.accessibility.AccessibilityWindowInfoCompat!);
+    method public void recycle();
+    field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
+    field public static final int TYPE_APPLICATION = 1; // 0x1
+    field public static final int TYPE_INPUT_METHOD = 2; // 0x2
+    field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5
+    field public static final int TYPE_SYSTEM = 3; // 0x3
+  }
+
+}
+
+package androidx.core.view.animation {
+
+  public final class PathInterpolatorCompat {
+    method public static android.view.animation.Interpolator! create(android.graphics.Path!);
+    method public static android.view.animation.Interpolator! create(float, float);
+    method public static android.view.animation.Interpolator! create(float, float, float, float);
+  }
+
+}
+
+package androidx.core.view.inputmethod {
+
+  public final class EditorInfoCompat {
+    ctor @Deprecated public EditorInfoCompat();
+    method public static String![] getContentMimeTypes(android.view.inputmethod.EditorInfo!);
+    method public static CharSequence? getInitialSelectedText(android.view.inputmethod.EditorInfo, int);
+    method public static CharSequence? getInitialTextAfterCursor(android.view.inputmethod.EditorInfo, int, int);
+    method public static CharSequence? getInitialTextBeforeCursor(android.view.inputmethod.EditorInfo, int, int);
+    method public static void setContentMimeTypes(android.view.inputmethod.EditorInfo, String![]?);
+    method public static void setInitialSurroundingSubText(android.view.inputmethod.EditorInfo, CharSequence, int);
+    method public static void setInitialSurroundingText(android.view.inputmethod.EditorInfo, CharSequence);
+    field public static final int IME_FLAG_FORCE_ASCII = -2147483648; // 0x80000000
+    field public static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 16777216; // 0x1000000
+  }
+
+  public final class InputConnectionCompat {
+    ctor @Deprecated public InputConnectionCompat();
+    method public static boolean commitContent(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle?);
+    method public static android.view.inputmethod.InputConnection createWrapper(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, androidx.core.view.inputmethod.InputConnectionCompat.OnCommitContentListener);
+    field public static final int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 1; // 0x1
+  }
+
+  public static interface InputConnectionCompat.OnCommitContentListener {
+    method public boolean onCommitContent(androidx.core.view.inputmethod.InputContentInfoCompat!, int, android.os.Bundle!);
+  }
+
+  public final class InputContentInfoCompat {
+    ctor public InputContentInfoCompat(android.net.Uri, android.content.ClipDescription, android.net.Uri?);
+    method public android.net.Uri getContentUri();
+    method public android.content.ClipDescription getDescription();
+    method public android.net.Uri? getLinkUri();
+    method public void releasePermission();
+    method public void requestPermission();
+    method public Object? unwrap();
+    method public static androidx.core.view.inputmethod.InputContentInfoCompat? wrap(Object?);
+  }
+
+}
+
+package androidx.core.widget {
+
+  public abstract class AutoScrollHelper implements android.view.View.OnTouchListener {
+    ctor public AutoScrollHelper(android.view.View);
+    method public abstract boolean canTargetScrollHorizontally(int);
+    method public abstract boolean canTargetScrollVertically(int);
+    method public boolean isEnabled();
+    method public boolean isExclusive();
+    method public boolean onTouch(android.view.View!, android.view.MotionEvent!);
+    method public abstract void scrollTargetBy(int, int);
+    method public androidx.core.widget.AutoScrollHelper setActivationDelay(int);
+    method public androidx.core.widget.AutoScrollHelper setEdgeType(int);
+    method public androidx.core.widget.AutoScrollHelper! setEnabled(boolean);
+    method public androidx.core.widget.AutoScrollHelper! setExclusive(boolean);
+    method public androidx.core.widget.AutoScrollHelper setMaximumEdges(float, float);
+    method public androidx.core.widget.AutoScrollHelper setMaximumVelocity(float, float);
+    method public androidx.core.widget.AutoScrollHelper setMinimumVelocity(float, float);
+    method public androidx.core.widget.AutoScrollHelper setRampDownDuration(int);
+    method public androidx.core.widget.AutoScrollHelper setRampUpDuration(int);
+    method public androidx.core.widget.AutoScrollHelper setRelativeEdges(float, float);
+    method public androidx.core.widget.AutoScrollHelper setRelativeVelocity(float, float);
+    field public static final int EDGE_TYPE_INSIDE = 0; // 0x0
+    field public static final int EDGE_TYPE_INSIDE_EXTEND = 1; // 0x1
+    field public static final int EDGE_TYPE_OUTSIDE = 2; // 0x2
+    field public static final float NO_MAX = 3.4028235E38f;
+    field public static final float NO_MIN = 0.0f;
+    field public static final float RELATIVE_UNSPECIFIED = 0.0f;
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface AutoSizeableTextView {
+    method public int getAutoSizeMaxTextSize();
+    method public int getAutoSizeMinTextSize();
+    method public int getAutoSizeStepGranularity();
+    method public int[]! getAutoSizeTextAvailableSizes();
+    method @androidx.core.widget.TextViewCompat.AutoSizeTextType public int getAutoSizeTextType();
+    method public void setAutoSizeTextTypeUniformWithConfiguration(int, int, int, int) throws java.lang.IllegalArgumentException;
+    method public void setAutoSizeTextTypeUniformWithPresetSizes(int[], int) throws java.lang.IllegalArgumentException;
+    method public void setAutoSizeTextTypeWithDefaults(@androidx.core.widget.TextViewCompat.AutoSizeTextType int);
+    field @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static final boolean PLATFORM_SUPPORTS_AUTOSIZE;
+  }
+
+  public final class CompoundButtonCompat {
+    method public static android.graphics.drawable.Drawable? getButtonDrawable(android.widget.CompoundButton);
+    method public static android.content.res.ColorStateList? getButtonTintList(android.widget.CompoundButton);
+    method public static android.graphics.PorterDuff.Mode? getButtonTintMode(android.widget.CompoundButton);
+    method public static void setButtonTintList(android.widget.CompoundButton, android.content.res.ColorStateList?);
+    method public static void setButtonTintMode(android.widget.CompoundButton, android.graphics.PorterDuff.Mode?);
+  }
+
+  public class ContentLoadingProgressBar extends android.widget.ProgressBar {
+    ctor public ContentLoadingProgressBar(android.content.Context);
+    ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet?);
+    method public void hide();
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public void show();
+  }
+
+  public final class EdgeEffectCompat {
+    ctor @Deprecated public EdgeEffectCompat(android.content.Context!);
+    method @Deprecated public boolean draw(android.graphics.Canvas!);
+    method @Deprecated public void finish();
+    method @Deprecated public boolean isFinished();
+    method @Deprecated public boolean onAbsorb(int);
+    method @Deprecated public boolean onPull(float);
+    method @Deprecated public boolean onPull(float, float);
+    method public static void onPull(android.widget.EdgeEffect, float, float);
+    method @Deprecated public boolean onRelease();
+    method @Deprecated public void setSize(int, int);
+  }
+
+  public class ImageViewCompat {
+    method public static android.content.res.ColorStateList? getImageTintList(android.widget.ImageView);
+    method public static android.graphics.PorterDuff.Mode? getImageTintMode(android.widget.ImageView);
+    method public static void setImageTintList(android.widget.ImageView, android.content.res.ColorStateList?);
+    method public static void setImageTintMode(android.widget.ImageView, android.graphics.PorterDuff.Mode?);
+  }
+
+  public final class ListPopupWindowCompat {
+    method @Deprecated public static android.view.View.OnTouchListener! createDragToOpenListener(Object!, android.view.View!);
+    method public static android.view.View.OnTouchListener? createDragToOpenListener(android.widget.ListPopupWindow, android.view.View);
+  }
+
+  public class ListViewAutoScrollHelper extends androidx.core.widget.AutoScrollHelper {
+    ctor public ListViewAutoScrollHelper(android.widget.ListView);
+    method public boolean canTargetScrollHorizontally(int);
+    method public boolean canTargetScrollVertically(int);
+    method public void scrollTargetBy(int, int);
+  }
+
+  public final class ListViewCompat {
+    method public static boolean canScrollList(android.widget.ListView, int);
+    method public static void scrollListBy(android.widget.ListView, int);
+  }
+
+  public class NestedScrollView extends android.widget.FrameLayout implements androidx.core.view.NestedScrollingChild3 androidx.core.view.NestedScrollingParent3 androidx.core.view.ScrollingView {
+    ctor public NestedScrollView(android.content.Context);
+    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?);
+    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet?, int);
+    method public boolean arrowScroll(int);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollExtent();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollOffset();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeHorizontalScrollRange();
+    method protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect!);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollExtent();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollOffset();
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public int computeVerticalScrollRange();
+    method public boolean dispatchNestedPreScroll(int, int, int[]!, int[]!, int);
+    method public void dispatchNestedScroll(int, int, int, int, int[]?, int, int[]);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]!, int);
+    method public boolean executeKeyEvent(android.view.KeyEvent);
+    method public void fling(int);
+    method public boolean fullScroll(int);
+    method public int getMaxScrollAmount();
+    method public boolean hasNestedScrollingParent(int);
+    method public boolean isFillViewport();
+    method public boolean isSmoothScrollingEnabled();
+    method public void onAttachedToWindow();
+    method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+    method public void onNestedScroll(android.view.View, int, int, int, int, int, int[]);
+    method public void onNestedScroll(android.view.View, int, int, int, int, int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+    method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+    method public void onStopNestedScroll(android.view.View, int);
+    method public boolean pageScroll(int);
+    method public void setFillViewport(boolean);
+    method public void setOnScrollChangeListener(androidx.core.widget.NestedScrollView.OnScrollChangeListener?);
+    method public void setSmoothScrollingEnabled(boolean);
+    method public final void smoothScrollBy(int, int);
+    method public final void smoothScrollBy(int, int, int);
+    method public final void smoothScrollTo(int, int);
+    method public final void smoothScrollTo(int, int, int);
+    method public boolean startNestedScroll(int, int);
+    method public void stopNestedScroll(int);
+  }
+
+  public static interface NestedScrollView.OnScrollChangeListener {
+    method public void onScrollChange(androidx.core.widget.NestedScrollView!, int, int, int, int);
+  }
+
+  public final class PopupMenuCompat {
+    method public static android.view.View.OnTouchListener? getDragToOpenListener(Object);
+  }
+
+  public final class PopupWindowCompat {
+    method public static boolean getOverlapAnchor(android.widget.PopupWindow);
+    method public static int getWindowLayoutType(android.widget.PopupWindow);
+    method public static void setOverlapAnchor(android.widget.PopupWindow, boolean);
+    method public static void setWindowLayoutType(android.widget.PopupWindow, int);
+    method public static void showAsDropDown(android.widget.PopupWindow, android.view.View, int, int, int);
+  }
+
+  @Deprecated public final class ScrollerCompat {
+    method @Deprecated public void abortAnimation();
+    method @Deprecated public boolean computeScrollOffset();
+    method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!);
+    method @Deprecated public static androidx.core.widget.ScrollerCompat! create(android.content.Context!, android.view.animation.Interpolator!);
+    method @Deprecated public void fling(int, int, int, int, int, int, int, int);
+    method @Deprecated public void fling(int, int, int, int, int, int, int, int, int, int);
+    method @Deprecated public float getCurrVelocity();
+    method @Deprecated public int getCurrX();
+    method @Deprecated public int getCurrY();
+    method @Deprecated public int getFinalX();
+    method @Deprecated public int getFinalY();
+    method @Deprecated public boolean isFinished();
+    method @Deprecated public boolean isOverScrolled();
+    method @Deprecated public void notifyHorizontalEdgeReached(int, int, int);
+    method @Deprecated public void notifyVerticalEdgeReached(int, int, int);
+    method @Deprecated public boolean springBack(int, int, int, int, int, int);
+    method @Deprecated public void startScroll(int, int, int, int);
+    method @Deprecated public void startScroll(int, int, int, int, int);
+  }
+
+  public final class TextViewCompat {
+    method public static int getAutoSizeMaxTextSize(android.widget.TextView);
+    method public static int getAutoSizeMinTextSize(android.widget.TextView);
+    method public static int getAutoSizeStepGranularity(android.widget.TextView);
+    method public static int[] getAutoSizeTextAvailableSizes(android.widget.TextView);
+    method public static int getAutoSizeTextType(android.widget.TextView);
+    method public static android.content.res.ColorStateList? getCompoundDrawableTintList(android.widget.TextView);
+    method public static android.graphics.PorterDuff.Mode? getCompoundDrawableTintMode(android.widget.TextView);
+    method public static android.graphics.drawable.Drawable![] getCompoundDrawablesRelative(android.widget.TextView);
+    method public static int getFirstBaselineToTopHeight(android.widget.TextView);
+    method public static int getLastBaselineToBottomHeight(android.widget.TextView);
+    method public static int getMaxLines(android.widget.TextView);
+    method public static int getMinLines(android.widget.TextView);
+    method public static androidx.core.text.PrecomputedTextCompat.Params getTextMetricsParams(android.widget.TextView);
+    method public static void setAutoSizeTextTypeUniformWithConfiguration(android.widget.TextView, int, int, int, int) throws java.lang.IllegalArgumentException;
+    method public static void setAutoSizeTextTypeUniformWithPresetSizes(android.widget.TextView, int[], int) throws java.lang.IllegalArgumentException;
+    method public static void setAutoSizeTextTypeWithDefaults(android.widget.TextView, int);
+    method public static void setCompoundDrawableTintList(android.widget.TextView, android.content.res.ColorStateList?);
+    method public static void setCompoundDrawableTintMode(android.widget.TextView, android.graphics.PorterDuff.Mode?);
+    method public static void setCompoundDrawablesRelative(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?, android.graphics.drawable.Drawable?);
+    method public static void setCompoundDrawablesRelativeWithIntrinsicBounds(android.widget.TextView, @DrawableRes int, @DrawableRes int, @DrawableRes int, @DrawableRes int);
+    method public static void setCustomSelectionActionModeCallback(android.widget.TextView, android.view.ActionMode.Callback);
+    method public static void setFirstBaselineToTopHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+    method public static void setLastBaselineToBottomHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+    method public static void setLineHeight(android.widget.TextView, @IntRange(from=0) @Px int);
+    method public static void setPrecomputedText(android.widget.TextView, androidx.core.text.PrecomputedTextCompat);
+    method public static void setTextAppearance(android.widget.TextView, @StyleRes int);
+    method public static void setTextMetricsParams(android.widget.TextView, androidx.core.text.PrecomputedTextCompat.Params);
+    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static android.view.ActionMode.Callback wrapCustomSelectionActionModeCallback(android.widget.TextView, android.view.ActionMode.Callback);
+    field public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0; // 0x0
+    field public static final int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1; // 0x1
+  }
+
+  @IntDef({androidx.core.widget.TextViewCompat.AUTO_SIZE_TEXT_TYPE_NONE, androidx.core.widget.TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM}) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface TextViewCompat.AutoSizeTextType {
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class TextViewOnReceiveContentListener implements androidx.core.view.OnReceiveContentListener {
+    ctor public TextViewOnReceiveContentListener();
+    method public androidx.core.view.ContentInfoCompat? onReceiveContent(android.view.View, androidx.core.view.ContentInfoCompat);
+  }
+
+  public interface TintableCompoundButton {
+    method public android.content.res.ColorStateList? getSupportButtonTintList();
+    method public android.graphics.PorterDuff.Mode? getSupportButtonTintMode();
+    method public void setSupportButtonTintList(android.content.res.ColorStateList?);
+    method public void setSupportButtonTintMode(android.graphics.PorterDuff.Mode?);
+  }
+
+  public interface TintableCompoundDrawablesView {
+    method public android.content.res.ColorStateList? getSupportCompoundDrawablesTintList();
+    method public android.graphics.PorterDuff.Mode? getSupportCompoundDrawablesTintMode();
+    method public void setSupportCompoundDrawablesTintList(android.content.res.ColorStateList?);
+    method public void setSupportCompoundDrawablesTintMode(android.graphics.PorterDuff.Mode?);
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public interface TintableImageSourceView {
+    method public android.content.res.ColorStateList? getSupportImageTintList();
+    method public android.graphics.PorterDuff.Mode? getSupportImageTintMode();
+    method public void setSupportImageTintList(android.content.res.ColorStateList?);
+    method public void setSupportImageTintMode(android.graphics.PorterDuff.Mode?);
+  }
+
+}
+
diff --git a/core/core/api/restricted_current.ignore b/core/core/api/restricted_current.ignore
new file mode 100644
index 0000000..15be615
--- /dev/null
+++ b/core/core/api/restricted_current.ignore
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+RemovedClass: androidx.core.os.HandlerExecutor:
+    Removed class androidx.core.os.HandlerExecutor
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index 4fb5f40..edda7df 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -1862,17 +1862,16 @@
     field public static final String MEDIA_UNKNOWN = "unknown";
   }
 
+  public final class ExecutorCompat {
+    method public static java.util.concurrent.Executor create(android.os.Handler);
+  }
+
   public final class HandlerCompat {
     method public static android.os.Handler createAsync(android.os.Looper);
     method public static android.os.Handler createAsync(android.os.Looper, android.os.Handler.Callback);
     method public static boolean postDelayed(android.os.Handler, Runnable, Object?, long);
   }
 
-  public class HandlerExecutor implements java.util.concurrent.Executor {
-    ctor public HandlerExecutor(android.os.Handler);
-    method public void execute(Runnable);
-  }
-
   public final class LocaleListCompat {
     method public static androidx.core.os.LocaleListCompat create(java.util.Locale!...);
     method public static androidx.core.os.LocaleListCompat forLanguageTags(String?);
diff --git a/core/core/build.gradle b/core/core/build.gradle
index 3f0fdc5..f776c9cf 100644
--- a/core/core/build.gradle
+++ b/core/core/build.gradle
@@ -10,7 +10,7 @@
 }
 
 dependencies {
-    api(project(":annotation:annotation"))
+    api("androidx.annotation:annotation:1.2.0-rc01")
     api("androidx.lifecycle:lifecycle-runtime:2.0.0")
     api("androidx.versionedparcelable:versionedparcelable:1.1.1")
     implementation("androidx.collection:collection:1.0.0")
diff --git a/core/core/src/androidTest/java/androidx/core/os/HandlerExecutorTest.java b/core/core/src/androidTest/java/androidx/core/os/ExecutorCompatTest.java
similarity index 84%
rename from core/core/src/androidTest/java/androidx/core/os/HandlerExecutorTest.java
rename to core/core/src/androidTest/java/androidx/core/os/ExecutorCompatTest.java
index c49a597..41a5399 100644
--- a/core/core/src/androidTest/java/androidx/core/os/HandlerExecutorTest.java
+++ b/core/core/src/androidTest/java/androidx/core/os/ExecutorCompatTest.java
@@ -29,21 +29,22 @@
 import org.junit.runner.RunWith;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
 /**
- * Tests for {@link HandlerExecutor}.
+ * Tests for {@link ExecutorCompat}.
  */
 @RunWith(AndroidJUnit4.class)
 @SmallTest
-public class HandlerExecutorTest {
+public class ExecutorCompatTest {
 
     private static final long TIMEOUT_MS = 5000;
 
     @Test
     public void testExecutor() throws Exception {
         final CountDownLatch latch = new CountDownLatch(1);
-        HandlerExecutor executor = new HandlerExecutor(new Handler(Looper.getMainLooper()));
+        Executor executor = ExecutorCompat.create(new Handler(Looper.getMainLooper()));
         executor.execute(new Runnable() {
             @Override
             public void run() {
@@ -56,7 +57,7 @@
     @Test
     public void testConstructor_Null() {
         try {
-            new HandlerExecutor(null);
+            ExecutorCompat.create(null);
             fail();
         } catch (NullPointerException e) {
             // pass
@@ -65,7 +66,7 @@
 
     @Test
     public void testExecute_Null() {
-        HandlerExecutor executor = new HandlerExecutor(new Handler(Looper.getMainLooper()));
+        Executor executor = ExecutorCompat.create(new Handler(Looper.getMainLooper()));
         try {
             executor.execute(null);
             fail();
diff --git a/core/core/src/main/java/androidx/core/location/LocationManagerCompat.java b/core/core/src/main/java/androidx/core/location/LocationManagerCompat.java
index 7c87f3e..5d5c7dc 100644
--- a/core/core/src/main/java/androidx/core/location/LocationManagerCompat.java
+++ b/core/core/src/main/java/androidx/core/location/LocationManagerCompat.java
@@ -41,7 +41,7 @@
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RequiresPermission;
 import androidx.collection.SimpleArrayMap;
-import androidx.core.os.HandlerExecutor;
+import androidx.core.os.ExecutorCompat;
 import androidx.core.util.Preconditions;
 
 import java.lang.reflect.Field;
@@ -123,7 +123,7 @@
     public static boolean registerGnssStatusCallback(@NonNull LocationManager locationManager,
             @NonNull GnssStatusCompat.Callback callback, @NonNull Handler handler) {
         if (VERSION.SDK_INT >= VERSION_CODES.R) {
-            return registerGnssStatusCallback(locationManager, new HandlerExecutor(handler),
+            return registerGnssStatusCallback(locationManager, ExecutorCompat.create(handler),
                 callback);
         } else {
             return registerGnssStatusCallback(locationManager, new InlineHandlerExecutor(handler),
diff --git a/core/core/src/main/java/androidx/core/os/ExecutorCompat.java b/core/core/src/main/java/androidx/core/os/ExecutorCompat.java
new file mode 100644
index 0000000..bbe6047
--- /dev/null
+++ b/core/core/src/main/java/androidx/core/os/ExecutorCompat.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.os;
+
+import android.os.Handler;
+
+import androidx.annotation.NonNull;
+import androidx.core.util.Preconditions;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * Helper for accessing features in {@link Executor}.
+ */
+public final class ExecutorCompat {
+
+    /** Creates an adapter {@link Executor} that posts all executed tasks onto the given
+     *  {@link Handler}.
+     */
+    public static @NonNull Executor create(@NonNull Handler handler) {
+        return new HandlerExecutor(handler);
+    }
+
+    private ExecutorCompat() {
+    }
+
+    private static class HandlerExecutor implements Executor {
+        private final Handler mHandler;
+
+        HandlerExecutor(@NonNull Handler handler) {
+            mHandler = Preconditions.checkNotNull(handler);
+        }
+
+        @Override
+        public void execute(@NonNull Runnable command) {
+            if (!mHandler.post(Preconditions.checkNotNull(command))) {
+                throw new RejectedExecutionException(mHandler + " is shutting down");
+            }
+        }
+    }
+}
diff --git a/core/core/src/main/java/androidx/core/os/HandlerExecutor.java b/core/core/src/main/java/androidx/core/os/HandlerExecutor.java
deleted file mode 100644
index 962a076..0000000
--- a/core/core/src/main/java/androidx/core/os/HandlerExecutor.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2019 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 androidx.annotation.NonNull;
-import androidx.core.util.Preconditions;
-
-import java.util.concurrent.Executor;
-import java.util.concurrent.RejectedExecutionException;
-
-/** An adapter {@link Executor} that posts all executed tasks onto the given {@link Handler}. */
-public class HandlerExecutor implements Executor {
-    private final Handler mHandler;
-
-    public HandlerExecutor(@NonNull Handler handler) {
-        mHandler = Preconditions.checkNotNull(handler);
-    }
-
-    @Override
-    public void execute(@NonNull Runnable command) {
-        if (!mHandler.post(Preconditions.checkNotNull(command))) {
-            throw new RejectedExecutionException(mHandler + " is shutting down");
-        }
-    }
-}
diff --git a/datastore/datastore-core/src/test/java/androidx/datastore/core/SimpleActorTest.kt b/datastore/datastore-core/src/test/java/androidx/datastore/core/SimpleActorTest.kt
index dce2835..a57f197 100644
--- a/datastore/datastore-core/src/test/java/androidx/datastore/core/SimpleActorTest.kt
+++ b/datastore/datastore-core/src/test/java/androidx/datastore/core/SimpleActorTest.kt
@@ -209,7 +209,11 @@
             onComplete = {},
             onUndeliveredElement = { msg, _ -> msg.complete(Unit) }
         ) {
-            awaitCancellation()
+            try {
+                awaitCancellation()
+            } finally {
+                it.complete(Unit)
+            }
         }
 
         val senderScope =
diff --git a/datastore/datastore-rxjava2/src/test/java/androidx/datastore/rxjava2/RxDataStoreTest.java b/datastore/datastore-rxjava2/src/test/java/androidx/datastore/rxjava2/RxDataStoreTest.java
index 40d4c42..5a5c816 100644
--- a/datastore/datastore-rxjava2/src/test/java/androidx/datastore/rxjava2/RxDataStoreTest.java
+++ b/datastore/datastore-rxjava2/src/test/java/androidx/datastore/rxjava2/RxDataStoreTest.java
@@ -72,8 +72,9 @@
         TestSubscriber<Byte> testSubscriber = byteStore.data().test();
 
         byteStore.updateDataAsync(RxDataStoreTest::incrementByte);
+        // Wait for our subscriber to see the second write, otherwise we may skip from 0 - 2
+        testSubscriber.awaitCount(2);
         byteStore.updateDataAsync(RxDataStoreTest::incrementByte);
-
         testSubscriber.awaitCount(3).assertValues((byte) 0, (byte) 1, (byte) 2);
     }
 
diff --git a/datastore/datastore-rxjava3/src/test/java/androidx/datastore/rxjava3/RxDataStoreTest.java b/datastore/datastore-rxjava3/src/test/java/androidx/datastore/rxjava3/RxDataStoreTest.java
index fbe7d28..9da1bfd 100644
--- a/datastore/datastore-rxjava3/src/test/java/androidx/datastore/rxjava3/RxDataStoreTest.java
+++ b/datastore/datastore-rxjava3/src/test/java/androidx/datastore/rxjava3/RxDataStoreTest.java
@@ -71,8 +71,9 @@
         TestSubscriber<Byte> testSubscriber = byteStore.data().test();
 
         byteStore.updateDataAsync(RxDataStoreTest::incrementByte);
+        // Wait for our subscriber to see the second write, otherwise we may skip from 0 - 2
+        testSubscriber.awaitCount(2);
         byteStore.updateDataAsync(RxDataStoreTest::incrementByte);
-
         testSubscriber.awaitCount(3).assertValues((byte) 0, (byte) 1, (byte) 2);
     }
 
diff --git a/development/build_log_simplifier/message-flakes.ignore b/development/build_log_simplifier/message-flakes.ignore
index 5bf2587..2226d60 100644
--- a/development/build_log_simplifier/message-flakes.ignore
+++ b/development/build_log_simplifier/message-flakes.ignore
@@ -33,6 +33,48 @@
 \[ant\:jacocoReport\] Note\: Recompile with \-Xlint\:deprecation for details\.
 \[ant\:jacocoReport\] Note\: Some input files use unchecked or unsafe operations\.
 \[ant\:jacocoReport\] Note\: Recompile with \-Xlint\:unchecked for details\.
+# b/179833331 , https://youtrack.jetbrains.com/issue/KT-35156
+# b/181258249 , https://youtrack.jetbrains.com/issue/KT-43881
 # > Task :jetifier-core:compileKotlin
 Could not perform incremental compilation\: Could not connect to Kotlin compile daemon
 Could not connect to kotlin daemon\. Using fallback strategy\.
+at org\.gradle\.workers\.internal\.AbstractWorker\.executeWrappedInBuildOperation\(AbstractWorker\.java\:[0-9]+\)
+at org\.gradle\.workers\.internal\.NoIsolationWorkerFactory\$[0-9]+\.execute\(NoIsolationWorkerFactory\.java\:[0-9]+\)
+at org\.gradle\.workers\.internal\.DefaultWorkerExecutor\.lambda\$submitWork\$[0-9]+\(DefaultWorkerExecutor\.java\:[0-9]+\)
+\.\.\. [0-9]+ more
+at java\.rmi\/sun\.rmi\.transport\.StreamRemoteCall\.exceptionReceivedFromServer\(StreamRemoteCall\.java\:[0-9]+\)
+at java\.rmi\/sun\.rmi\.transport\.StreamRemoteCall\.executeCall\(StreamRemoteCall\.java\:[0-9]+\)
+at java\.rmi\/sun\.rmi\.server\.UnicastRef\.invoke\(UnicastRef\.java\:[0-9]+\)
+at java\.rmi\/java\.rmi\.server\.RemoteObjectInvocationHandler\.invokeRemoteMethod\(RemoteObjectInvocationHandler\.java\:[0-9]+\)
+at java\.rmi\/java\.rmi\.server\.RemoteObjectInvocationHandler\.invoke\(RemoteObjectInvocationHandler\.java\:[0-9]+\)
+at com\.sun\.proxy\.\$Proxy[0-9]+\.compile\(Unknown Source\)
+at org\.jetbrains\.kotlin\.compilerRunner\.GradleKotlinCompilerWork\.incrementalCompilationWithDaemon\(GradleKotlinCompilerWork\.kt\:[0-9]+\)
+at org\.jetbrains\.kotlin\.compilerRunner\.GradleKotlinCompilerWork\.compileWithDaemon\(GradleKotlinCompilerWork\.kt\:[0-9]+\)
+at org\.jetbrains\.kotlin\.compilerRunner\.GradleKotlinCompilerWork\.compileWithDaemonOrFallbackImpl\(GradleKotlinCompilerWork\.kt\:[0-9]+\)
+at org\.jetbrains\.kotlin\.compilerRunner\.GradleKotlinCompilerWork\.run\(GradleKotlinCompilerWork\.kt\:[0-9]+\)
+at org\.gradle\.workers\.internal\.AdapterWorkAction\.execute\(AdapterWorkAction\.java\:[0-9]+\)
+at org\.gradle\.workers\.internal\.DefaultWorkerServer\.execute\(DefaultWorkerServer\.java\:[0-9]+\)
+at org\.gradle\.workers\.internal\.NoIsolationWorkerFactory\$[0-9]+\$[0-9]+\.create\(NoIsolationWorkerFactory\.java\:[0-9]+\)
+at org\.gradle\.internal\.classloader\.ClassLoaderUtils\.executeInClassloader\(ClassLoaderUtils\.java\:[0-9]+\)
+at org\.gradle\.workers\.internal\.NoIsolationWorkerFactory\$[0-9]+\.lambda\$execute\$[0-9]+\(NoIsolationWorkerFactory\.java\:[0-9]+\)
+at org\.gradle\.workers\.internal\.AbstractWorker\$[0-9]+\.call\(AbstractWorker\.java\:[0-9]+\)
+Caused by\: java\.lang\.AssertionError\: Incremental compilation is not enabled
+at org\.jetbrains\.kotlin\.incremental\.IncrementalCompilerRunner\.compileImpl\(IncrementalCompilerRunner\.kt\:[0-9]+\)
+at org\.jetbrains\.kotlin\.incremental\.IncrementalCompilerRunner\.compile\(IncrementalCompilerRunner\.kt\:[0-9]+\)
+at org\.jetbrains\.kotlin\.daemon\.CompileServiceImplBase\.execIncrementalCompiler\(CompileServiceImpl\.kt\:[0-9]+\)
+at org\.jetbrains\.kotlin\.daemon\.CompileServiceImplBase\.access\$execIncrementalCompiler\(CompileServiceImpl\.kt\:[0-9]+\)
+at org\.jetbrains\.kotlin\.daemon\.CompileServiceImpl\.compile\(CompileServiceImpl\.kt\:[0-9]+\)
+at java\.rmi\/sun\.rmi\.transport\.Transport\.serviceCall\(Transport\.java\:[0-9]+\)
+at java\.rmi\/sun\.rmi\.transport\.tcp\.TCPTransport\.handleMessages\(TCPTransport\.java\:[0-9]+\)
+at java\.rmi\/sun\.rmi\.transport\.tcp\.TCPTransport\$ConnectionHandler\.run[0-9]+\(TCPTransport\.java\:[0-9]+\)
+at java\.rmi\/sun\.rmi\.transport\.tcp\.TCPTransport\$ConnectionHandler\.lambda\$run\$[0-9]+\(TCPTransport\.java\:[0-9]+\)
+at java\.rmi\/sun\.rmi\.transport\.tcp\.TCPTransport\$ConnectionHandler\.run\(TCPTransport\.java\:[0-9]+\)
+at org\.gradle\.internal\.work\.DefaultConditionalExecutionQueue\$ExecutionRunner\.runExecution\(DefaultConditionalExecutionQueue\.java\:[0-9]+\)
+at org\.gradle\.internal\.work\.DefaultConditionalExecutionQueue\$ExecutionRunner\.runBatch\(DefaultConditionalExecutionQueue\.java\:[0-9]+\)
+at org\.gradle\.internal\.work\.DefaultConditionalExecutionQueue\$ExecutionRunner\.run\(DefaultConditionalExecutionQueue\.java\:[0-9]+\)
+Compilation with Kotlin compile daemon was not successful
+java\.rmi\.ServerError\: Error occurred in server thread\; nested exception is\:
+java\.lang\.AssertionError\: Incremental compilation is not enabled
+at java\.rmi\/sun\.rmi\.server\.UnicastServerRef\.dispatch\(UnicastServerRef\.java\:[0-9]+\)
+at java\.rmi\/sun\.rmi\.transport\.Transport\$[0-9]+\.run\(Transport\.java\:[0-9]+\)
+at org.gradle.*
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index a0fa20e..0c470ae 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -595,3 +595,11 @@
 \$OUT_DIR\/androidx\/compose\/foundation\/foundation\-layout\/foundation\-layout\-benchmark\/build\/intermediates\/tmp\/manifest\/androidTest\/release\/manifestMerger[0-9]+\.xml\:[0-9]+\:[0-9]+\-[0-9]+\:[0-9]+ Warning\:
 # > Task :compose:ui:ui-text:ui-text-benchmark:processReleaseAndroidTestManifest
 \$OUT_DIR\/androidx\/compose\/ui\/ui\-text\/ui\-text\-benchmark\/build\/intermediates\/tmp\/manifest\/androidTest\/release\/manifestMerger[0-9]+\.xml\:[0-9]+\:[0-9]+\-[0-9]+\:[0-9]+ Warning\:
+# > Task :compose:benchmark-utils:benchmark-utils-benchmark:processReleaseAndroidTestManifest
+\$OUT_DIR\/androidx\/compose\/benchmark\-utils\/benchmark\-utils\-benchmark\/build\/intermediates\/tmp\/manifest\/androidTest\/release\/manifestMerger[0-9]+\.xml\:[0-9]+\:[0-9]+\-[0-9]+\:[0-9]+ Warning\:
+# > Task :compose:ui:ui-benchmark:processReleaseAndroidTestManifest
+\$OUT_DIR\/androidx\/compose\/ui\/ui\-benchmark\/build\/intermediates\/tmp\/manifest\/androidTest\/release\/manifestMerger[0-9]+\.xml\:[0-9]+\:[0-9]+\-[0-9]+\:[0-9]+ Warning\:
+# > Task :compose:animation:animation-core:animation-core-benchmark:processReleaseAndroidTestManifest
+\$OUT_DIR\/androidx\/compose\/animation\/animation\-core\/animation\-core\-benchmark\/build\/intermediates\/tmp\/manifest\/androidTest\/release\/manifestMerger[0-9]+\.xml\:[0-9]+\:[0-9]+\-[0-9]+\:[0-9]+ Warning\:
+# > Task :compose:ui:ui-graphics:ui-graphics-benchmark:processReleaseAndroidTestManifest
+\$OUT_DIR\/androidx\/compose\/ui\/ui\-graphics\/ui\-graphics\-benchmark\/build\/intermediates\/tmp\/manifest\/androidTest\/release\/manifestMerger[0-9]+\.xml\:[0-9]+\:[0-9]+\-[0-9]+\:[0-9]+ Warning\:
diff --git a/development/project-creator/README.md b/development/project-creator/README.md
new file mode 100644
index 0000000..26b20f5
--- /dev/null
+++ b/development/project-creator/README.md
@@ -0,0 +1,39 @@
+# Project/Module Creator
+
+This script will create a new project/module using a groupId and artifactId.
+
+It will use the groupId and artifactId to best guess which configuration
+is most appropriate for the project/module you are creating.
+
+### Using the script
+
+```bash
+./create_project.py androidx.foo foo-bar
+```
+
+### Todos **after** project creation
+
+1. [OWNERS] Check that the OWNERS file is in the correct place
+2. [OWNERS] Add your name (and others) to the OWNERS file
+3. [build.grade] Check that the correct library version is assigned
+4. [build.grade] Fill out the project/module name
+5. [build.grade] Fill out the project/module description
+6. [package-info.java] Fill out the project/module package-info.java file
+
+### Project/Module Types
+
+The script leverages buildSrc/src/main/kotlin/androidx/build/LibraryType.kt
+to create the recommended defaults for your project.  However, you can override
+the options to best fit your requirements.
+
+### Testing the script
+
+Generic project integration test
+```bash
+./create_project.py androidx.foo.bar bar-qux
+```
+
+Script test suite
+```bash
+./test_project_creator.py
+```
\ No newline at end of file
diff --git a/development/project-creator/create_project.py b/development/project-creator/create_project.py
index c47aca1..8504416 100755
--- a/development/project-creator/create_project.py
+++ b/development/project-creator/create_project.py
@@ -552,6 +552,40 @@
     # The group id does not exist yet, so just default to false.
     return False
 
+def print_todo_list(group_id, artifact_id):
+    """Prints to the todo list once the script has finished.
+
+    There are some pieces that can not be automated or require human eyes.
+    List out the appropriate todos so that the users knows what needs
+    to be done prior to uploading.
+
+    Args:
+        group_id: group_id of the new library
+        artifact_id: group_id of the new library
+    """
+    build_gradle_path = get_full_artifact_path(group_id, artifact_id) + \
+                        "/build.gradle"
+    owners_file_path = get_group_id_path(group_id) + "/OWNERS"
+    package_info_path = get_package_info_file_dir(group_id, artifact_id) + \
+                        "/package-info.java"
+    print("---\n")
+    print("Created the project.  The following TODOs need to be completed by "
+          "you:\n")
+    print("\t1. Check that the OWNERS file is in the correct place. It is "
+          "currently at:"
+          "\n\t\t" + owners_file_path)
+    print("\t2. Add your name (and others) to the OWNERS file:" + \
+          "\n\t\t" + owners_file_path)
+    print("\t3. Check that the correct library version is assigned in the "
+          "build.gradle:"
+          "\n\t\t" + build_gradle_path)
+    print("\t4. Fill out the project/module name in the build.gradle:"
+          "\n\t\t" + build_gradle_path)
+    print("\t5. Fill out the project/module description in the build.gradle:"
+          "\n\t\t" + build_gradle_path)
+    print("\t6. Update the project/module package-info.java file:"
+          "\n\t\t" + package_info_path)
+
 def main(args):
     # Parse arguments and check for existence of build ID or file
     args = parser.parse_args()
@@ -572,6 +606,7 @@
         print("done.")
     else:
         print("failed.  Please investigate manually.")
+    print_todo_list(args.group_id, args.artifact_id)
 
 if __name__ == '__main__':
     main(sys.argv)
diff --git a/docs-public/build.gradle b/docs-public/build.gradle
index 04dd370..ea9d32c 100644
--- a/docs-public/build.gradle
+++ b/docs-public/build.gradle
@@ -4,14 +4,14 @@
 }
 
 dependencies {
-    docs("androidx.activity:activity:1.3.0-alpha03")
-    docs("androidx.activity:activity-compose:1.3.0-alpha03")
-    samples("androidx.activity:activity-compose-samples:1.3.0-alpha03")
-    docs("androidx.activity:activity-ktx:1.3.0-alpha03")
+    docs("androidx.activity:activity:1.3.0-alpha04")
+    docs("androidx.activity:activity-compose:1.3.0-alpha04")
+    samples("androidx.activity:activity-compose-samples:1.3.0-alpha04")
+    docs("androidx.activity:activity-ktx:1.3.0-alpha04")
     docs("androidx.ads:ads-identifier:1.0.0-alpha04")
     docs("androidx.ads:ads-identifier-provider:1.0.0-alpha04")
     docs("androidx.annotation:annotation:1.2.0-rc01")
-    docs("androidx.annotation:annotation-experimental:1.1.0-alpha01")
+    docs("androidx.annotation:annotation-experimental:1.1.0-rc01")
     docs("androidx.appcompat:appcompat:1.3.0-beta01")
     docs("androidx.appcompat:appcompat-resources:1.3.0-beta01")
     docs("androidx.arch.core:core-common:2.1.0")
@@ -35,47 +35,47 @@
     docs("androidx.cardview:cardview:1.0.0")
     docs("androidx.collection:collection:1.2.0-alpha01")
     docs("androidx.collection:collection-ktx:1.2.0-alpha01")
-    docs("androidx.compose.animation:animation:1.0.0-beta01")
-    docs("androidx.compose.animation:animation-core:1.0.0-beta01")
-    samples("androidx.compose.animation:animation-samples:1.0.0-beta01")
-    samples("androidx.compose.animation:animation-core-samples:1.0.0-beta01")
-    docs("androidx.compose.foundation:foundation:1.0.0-beta01")
-    docs("androidx.compose.foundation:foundation-layout:1.0.0-beta01")
-    samples("androidx.compose.foundation:foundation-layout-samples:1.0.0-beta01")
-    samples("androidx.compose.foundation:foundation-samples:1.0.0-beta01")
-    docs("androidx.compose.material:material:1.0.0-beta01")
-    docs("androidx.compose.material:material-icons-core:1.0.0-beta01")
-    samples("androidx.compose.material:material-icons-core-samples:1.0.0-beta01")
-    docs("androidx.compose.material:material-icons-extended:1.0.0-beta01")
-    docs("androidx.compose.material:material-ripple:1.0.0-beta01")
-    samples("androidx.compose.material:material-samples:1.0.0-beta01")
-    docs("androidx.compose.runtime:runtime:1.0.0-beta01")
-    docs("androidx.compose.runtime:runtime-livedata:1.0.0-beta01")
-    samples("androidx.compose.runtime:runtime-livedata-samples:1.0.0-beta01")
-    docs("androidx.compose.runtime:runtime-rxjava2:1.0.0-beta01")
-    samples("androidx.compose.runtime:runtime-rxjava2-samples:1.0.0-beta01")
-    docs("androidx.compose.runtime:runtime-rxjava3:1.0.0-beta01")
-    samples("androidx.compose.runtime:runtime-rxjava3-samples:1.0.0-beta01")
-    docs("androidx.compose.runtime:runtime-saveable:1.0.0-beta01")
-    samples("androidx.compose.runtime:runtime-saveable-samples:1.0.0-beta01")
-    samples("androidx.compose.runtime:runtime-samples:1.0.0-beta01")
-    docs("androidx.compose.ui:ui:1.0.0-beta01")
-    docs("androidx.compose.ui:ui-geometry:1.0.0-beta01")
-    docs("androidx.compose.ui:ui-graphics:1.0.0-beta01")
-    samples("androidx.compose.ui:ui-graphics-samples:1.0.0-beta01")
-    docs("androidx.compose.ui:ui-test:1.0.0-beta01")
-    docs("androidx.compose.ui:ui-test-junit4:1.0.0-beta01")
-    docs("androidx.compose.ui:ui-text:1.0.0-beta01")
+    docs("androidx.compose.animation:animation:1.0.0-beta02")
+    docs("androidx.compose.animation:animation-core:1.0.0-beta02")
+    samples("androidx.compose.animation:animation-samples:1.0.0-beta02")
+    samples("androidx.compose.animation:animation-core-samples:1.0.0-beta02")
+    docs("androidx.compose.foundation:foundation:1.0.0-beta02")
+    docs("androidx.compose.foundation:foundation-layout:1.0.0-beta02")
+    samples("androidx.compose.foundation:foundation-layout-samples:1.0.0-beta02")
+    samples("androidx.compose.foundation:foundation-samples:1.0.0-beta02")
+    docs("androidx.compose.material:material:1.0.0-beta02")
+    docs("androidx.compose.material:material-icons-core:1.0.0-beta02")
+    samples("androidx.compose.material:material-icons-core-samples:1.0.0-beta02")
+    docs("androidx.compose.material:material-icons-extended:1.0.0-beta02")
+    docs("androidx.compose.material:material-ripple:1.0.0-beta02")
+    samples("androidx.compose.material:material-samples:1.0.0-beta02")
+    docs("androidx.compose.runtime:runtime:1.0.0-beta02")
+    docs("androidx.compose.runtime:runtime-livedata:1.0.0-beta02")
+    samples("androidx.compose.runtime:runtime-livedata-samples:1.0.0-beta02")
+    docs("androidx.compose.runtime:runtime-rxjava2:1.0.0-beta02")
+    samples("androidx.compose.runtime:runtime-rxjava2-samples:1.0.0-beta02")
+    docs("androidx.compose.runtime:runtime-rxjava3:1.0.0-beta02")
+    samples("androidx.compose.runtime:runtime-rxjava3-samples:1.0.0-beta02")
+    docs("androidx.compose.runtime:runtime-saveable:1.0.0-beta02")
+    samples("androidx.compose.runtime:runtime-saveable-samples:1.0.0-beta02")
+    samples("androidx.compose.runtime:runtime-samples:1.0.0-beta02")
+    docs("androidx.compose.ui:ui:1.0.0-beta02")
+    docs("androidx.compose.ui:ui-geometry:1.0.0-beta02")
+    docs("androidx.compose.ui:ui-graphics:1.0.0-beta02")
+    samples("androidx.compose.ui:ui-graphics-samples:1.0.0-beta02")
+    docs("androidx.compose.ui:ui-test:1.0.0-beta02")
+    docs("androidx.compose.ui:ui-test-junit4:1.0.0-beta02")
+    docs("androidx.compose.ui:ui-text:1.0.0-beta02")
     docs("androidx.compose.ui:ui-text-android:1.0.0-alpha06")
-    samples("androidx.compose.ui:ui-text-samples:1.0.0-beta01")
-    docs("androidx.compose.ui:ui-tooling:1.0.0-beta01")
-    docs("androidx.compose.ui:ui-tooling-data:1.0.0-beta01")
-    docs("androidx.compose.ui:ui-unit:1.0.0-beta01")
-    samples("androidx.compose.ui:ui-unit-samples:1.0.0-beta01")
-    docs("androidx.compose.ui:ui-util:1.0.0-beta01")
-    docs("androidx.compose.ui:ui-viewbinding:1.0.0-beta01")
-    samples("androidx.compose.ui:ui-viewbinding-samples:1.0.0-beta01")
-    samples("androidx.compose.ui:ui-samples:1.0.0-beta01")
+    samples("androidx.compose.ui:ui-text-samples:1.0.0-beta02")
+    docs("androidx.compose.ui:ui-tooling:1.0.0-beta02")
+    docs("androidx.compose.ui:ui-tooling-data:1.0.0-beta02")
+    docs("androidx.compose.ui:ui-unit:1.0.0-beta02")
+    samples("androidx.compose.ui:ui-unit-samples:1.0.0-beta02")
+    docs("androidx.compose.ui:ui-util:1.0.0-beta02")
+    docs("androidx.compose.ui:ui-viewbinding:1.0.0-beta02")
+    samples("androidx.compose.ui:ui-viewbinding-samples:1.0.0-beta02")
+    samples("androidx.compose.ui:ui-samples:1.0.0-beta02")
     docs("androidx.concurrent:concurrent-futures:1.1.0")
     docs("androidx.concurrent:concurrent-futures-ktx:1.1.0")
     docs("androidx.contentpager:contentpager:1.0.0")
@@ -87,14 +87,14 @@
     docs("androidx.core:core-ktx:1.5.0-beta02")
     docs("androidx.cursoradapter:cursoradapter:1.0.0")
     docs("androidx.customview:customview:1.1.0")
-    docs("androidx.datastore:datastore:1.0.0-alpha07")
-    docs("androidx.datastore:datastore-core:1.0.0-alpha07")
-    docs("androidx.datastore:datastore-preferences:1.0.0-alpha07")
-    docs("androidx.datastore:datastore-preferences-core:1.0.0-alpha07")
-    docs("androidx.datastore:datastore-preferences-rxjava2:1.0.0-alpha07")
-    docs("androidx.datastore:datastore-preferences-rxjava3:1.0.0-alpha07")
-    docs("androidx.datastore:datastore-rxjava2:1.0.0-alpha07")
-    docs("androidx.datastore:datastore-rxjava3:1.0.0-alpha07")
+    docs("androidx.datastore:datastore:1.0.0-alpha08")
+    docs("androidx.datastore:datastore-core:1.0.0-alpha08")
+    docs("androidx.datastore:datastore-preferences:1.0.0-alpha08")
+    docs("androidx.datastore:datastore-preferences-core:1.0.0-alpha08")
+    docs("androidx.datastore:datastore-preferences-rxjava2:1.0.0-alpha08")
+    docs("androidx.datastore:datastore-preferences-rxjava3:1.0.0-alpha08")
+    docs("androidx.datastore:datastore-rxjava2:1.0.0-alpha08")
+    docs("androidx.datastore:datastore-rxjava3:1.0.0-alpha08")
     docs("androidx.documentfile:documentfile:1.0.0")
     docs("androidx.drawerlayout:drawerlayout:1.1.1")
     docs("androidx.dynamicanimation:dynamicanimation:1.1.0-alpha02")
@@ -110,11 +110,12 @@
     docs("androidx.fragment:fragment-testing:1.3.1")
     docs("androidx.gridlayout:gridlayout:1.0.0")
     docs("androidx.heifwriter:heifwriter:1.1.0-alpha01")
-    docs("androidx.hilt:hilt-common:1.0.0-alpha03")
+    docs("androidx.hilt:hilt-common:1.0.0-beta01")
     docs("androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03")
-    docs("androidx.hilt:hilt-navigation:1.0.0-alpha03")
-    docs("androidx.hilt:hilt-navigation-fragment:1.0.0-alpha03")
-    docs("androidx.hilt:hilt-work:1.0.0-alpha03")
+    docs("androidx.hilt:hilt-navigation:1.0.0-beta01")
+    docs("androidx.hilt:hilt-navigation-compose:1.0.0-alpha01")
+    docs("androidx.hilt:hilt-navigation-fragment:1.0.0-beta01")
+    docs("androidx.hilt:hilt-work:1.0.0-beta01")
     docs("androidx.interpolator:interpolator:1.0.0")
     docs("androidx.leanback:leanback:1.1.0-beta01")
     docs("androidx.leanback:leanback-paging:1.1.0-alpha07")
@@ -135,7 +136,7 @@
     docs("androidx.lifecycle:lifecycle-runtime-testing:2.3.0")
     docs("androidx.lifecycle:lifecycle-service:2.3.0")
     docs("androidx.lifecycle:lifecycle-viewmodel:2.3.0")
-    docs("androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha02")
+    docs("androidx.lifecycle:lifecycle-viewmodel-compose:1.0.0-alpha03")
     docs("androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0")
     docs("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.3.0")
     docs("androidx.loader:loader:1.1.0")
@@ -144,11 +145,11 @@
     docs("androidx.media2:media2-player:1.1.2")
     docs("androidx.media2:media2-session:1.1.2")
     docs("androidx.media2:media2-widget:1.1.2")
-    docs("androidx.media:media:1.3.0-beta01")
+    docs("androidx.media:media:1.3.0-rc01")
     docs("androidx.mediarouter:mediarouter:1.2.2")
     docs("androidx.navigation:navigation-common:2.3.4")
     docs("androidx.navigation:navigation-common-ktx:2.3.4")
-    docs("androidx.navigation:navigation-compose:1.0.0-alpha08")
+    docs("androidx.navigation:navigation-compose:1.0.0-alpha09")
     samples("androidx.navigation:navigation-compose-samples:1.0.0-alpha01")
     docs("androidx.navigation:navigation-dynamic-features-fragment:2.3.4")
     docs("androidx.navigation:navigation-dynamic-features-runtime:2.3.4")
@@ -159,16 +160,16 @@
     docs("androidx.navigation:navigation-testing:2.3.4")
     docs("androidx.navigation:navigation-ui:2.3.4")
     docs("androidx.navigation:navigation-ui-ktx:2.3.4")
-    docs("androidx.paging:paging-common:3.0.0-beta01")
-    docs("androidx.paging:paging-common-ktx:3.0.0-beta01")
+    docs("androidx.paging:paging-common:3.0.0-beta02")
+    docs("androidx.paging:paging-common-ktx:3.0.0-beta02")
     docs("androidx.paging:paging-compose:1.0.0-alpha08")
     samples("androidx.paging:paging-compose-samples:3.0.0-alpha08")
-    docs("androidx.paging:paging-guava:3.0.0-beta01")
-    docs("androidx.paging:paging-runtime:3.0.0-beta01")
-    docs("androidx.paging:paging-runtime-ktx:3.0.0-beta01")
-    docs("androidx.paging:paging-rxjava2:3.0.0-beta01")
-    docs("androidx.paging:paging-rxjava2-ktx:3.0.0-beta01")
-    docs("androidx.paging:paging-rxjava3:3.0.0-beta01")
+    docs("androidx.paging:paging-guava:3.0.0-beta02")
+    docs("androidx.paging:paging-runtime:3.0.0-beta02")
+    docs("androidx.paging:paging-runtime-ktx:3.0.0-beta02")
+    docs("androidx.paging:paging-rxjava2:3.0.0-beta02")
+    docs("androidx.paging:paging-rxjava2-ktx:3.0.0-beta02")
+    docs("androidx.paging:paging-rxjava3:3.0.0-beta02")
     samples("androidx.paging:paging-samples:3.0.0-beta01")
     docs("androidx.palette:palette:1.0.0")
     docs("androidx.palette:palette-ktx:1.0.0")
@@ -180,14 +181,14 @@
     docs("androidx.recyclerview:recyclerview:1.2.0-beta02")
     docs("androidx.recyclerview:recyclerview-selection:2.0.0-alpha01")
     docs("androidx.remotecallback:remotecallback:1.0.0-alpha02")
-    docs("androidx.room:room-common:2.3.0-beta02")
-    docs("androidx.room:room-guava:2.3.0-beta02")
-    docs("androidx.room:room-ktx:2.3.0-beta02")
-    docs("androidx.room:room-migration:2.3.0-beta02")
-    docs("androidx.room:room-runtime:2.3.0-beta02")
-    docs("androidx.room:room-rxjava2:2.3.0-beta02")
-    docs("androidx.room:room-rxjava3:2.3.0-beta02")
-    docs("androidx.room:room-testing:2.3.0-beta02")
+    docs("androidx.room:room-common:2.3.0-beta03")
+    docs("androidx.room:room-guava:2.3.0-beta03")
+    docs("androidx.room:room-ktx:2.3.0-beta03")
+    docs("androidx.room:room-migration:2.3.0-beta03")
+    docs("androidx.room:room-runtime:2.3.0-beta03")
+    docs("androidx.room:room-rxjava2:2.3.0-beta03")
+    docs("androidx.room:room-rxjava3:2.3.0-beta03")
+    docs("androidx.room:room-testing:2.3.0-beta03")
     docs("androidx.savedstate:savedstate:1.1.0")
     docs("androidx.savedstate:savedstate-ktx:1.1.0")
     docs("androidx.security:security-crypto:1.1.0-alpha03")
@@ -219,25 +220,27 @@
     docs("androidx.viewpager:viewpager:1.0.0")
     docs("androidx.wear:wear:1.2.0-alpha06")
     stubs(fileTree(dir: "../wear/wear_stubs/", include: ["com.google.android.wearable-stubs.jar"]))
-    docs("androidx.wear:wear-complications-data:1.0.0-alpha08")
-    docs("androidx.wear:wear-complications-provider:1.0.0-alpha08")
-    docs("androidx.wear:wear-ongoing:1.0.0-alpha02")
-    docs("androidx.wear:wear-phone-interactions:1.0.0-alpha02")
-    docs("androidx.wear:wear-remote-interactions:1.0.0-alpha01")
-    docs("androidx.wear:wear-watchface:1.0.0-alpha08")
-    docs("androidx.wear:wear-watchface-client:1.0.0-alpha08")
-    docs("androidx.wear:wear-watchface-client-guava:1.0.0-alpha08")
-    docs("androidx.wear:wear-watchface-complications-rendering:1.0.0-alpha08")
-    docs("androidx.wear:wear-watchface-data:1.0.0-alpha08")
-    docs("androidx.wear:wear-watchface-editor:1.0.0-alpha08")
-    docs("androidx.wear:wear-watchface-editor-guava:1.0.0-alpha08")
-    docs("androidx.wear:wear-watchface-guava:1.0.0-alpha08")
+    docs("androidx.wear:wear-complications-data:1.0.0-alpha09")
+    docs("androidx.wear:wear-complications-provider:1.0.0-alpha09")
+    docs("androidx.wear:wear-ongoing:1.0.0-alpha03")
+    docs("androidx.wear:wear-phone-interactions:1.0.0-alpha03")
+    docs("androidx.wear:wear-remote-interactions:1.0.0-alpha02")
+    docs("androidx.wear:wear-tiles:1.0.0-alpha01")
+    docs("androidx.wear:wear-tiles-renderer:1.0.0-alpha01")
+    docs("androidx.wear:wear-watchface:1.0.0-alpha09")
+    docs("androidx.wear:wear-watchface-client:1.0.0-alpha09")
+    docs("androidx.wear:wear-watchface-client-guava:1.0.0-alpha09")
+    docs("androidx.wear:wear-watchface-complications-rendering:1.0.0-alpha09")
+    docs("androidx.wear:wear-watchface-data:1.0.0-alpha09")
+    docs("androidx.wear:wear-watchface-editor:1.0.0-alpha09")
+    docs("androidx.wear:wear-watchface-editor-guava:1.0.0-alpha09")
+    docs("androidx.wear:wear-watchface-guava:1.0.0-alpha09")
     samples("androidx.wear:wear-watchface-samples:1.0.0-alpha02")
-    docs("androidx.wear:wear-watchface-style:1.0.0-alpha08")
+    docs("androidx.wear:wear-watchface-style:1.0.0-alpha09")
     docs("androidx.wear:wear-input:1.1.0-alpha01")
     docs("androidx.wear:wear-input-testing:1.1.0-alpha01")
     docs("androidx.webkit:webkit:1.4.0")
-    docs("androidx.window:window:1.0.0-alpha03")
+    docs("androidx.window:window:1.0.0-alpha04")
     stubs(fileTree(dir: "../window/stubs/", include: ["window-sidecar-release-0.1.0-alpha01.aar"]))
     stubs(project(":window:window-extensions"))
     docs("androidx.work:work-gcm:2.7.0-alpha01")
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index 69bc9e6..9be8054 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -244,6 +244,9 @@
     docs(project(":wear:wear-ongoing"))
     docs(project(":wear:wear-phone-interactions"))
     docs(project(":wear:wear-remote-interactions"))
+    docs(project(":wear:wear-tiles"))
+    docs(project(":wear:wear-tiles-proto"))
+    docs(project(":wear:wear-tiles-renderer"))
     docs(project(":wear:wear-watchface"))
     docs(project(":wear:wear-watchface-complications-rendering"))
     docs(project(":wear:wear-watchface-client"))
diff --git a/emoji2/emoji2-bundled/build.gradle b/emoji2/emoji2-bundled/build.gradle
index 5b6e687..3c06a08 100644
--- a/emoji2/emoji2-bundled/build.gradle
+++ b/emoji2/emoji2-bundled/build.gradle
@@ -19,7 +19,7 @@
 }
 
 dependencies {
-    api(project(":emoji"))
+    api(project(":emoji2:emoji2"))
 }
 
 androidx {
diff --git a/emoji2/emoji2-bundled/lint-baseline.xml b/emoji2/emoji2-bundled/lint-baseline.xml
deleted file mode 100644
index 27e26a8..0000000
--- a/emoji2/emoji2-bundled/lint-baseline.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.2.0-beta04" client="gradle" variant="debug" version="4.2.0-beta04">
-
-</issues>
diff --git a/emoji2/emoji2-bundled/src/main/java/androidx/emoji/bundled/BundledEmojiCompatConfig.java b/emoji2/emoji2-bundled/src/main/java/androidx/emoji2/bundled/BundledEmojiCompatConfig.java
similarity index 95%
rename from emoji2/emoji2-bundled/src/main/java/androidx/emoji/bundled/BundledEmojiCompatConfig.java
rename to emoji2/emoji2-bundled/src/main/java/androidx/emoji2/bundled/BundledEmojiCompatConfig.java
index 03f5567..5394c9b 100644
--- a/emoji2/emoji2-bundled/src/main/java/androidx/emoji/bundled/BundledEmojiCompatConfig.java
+++ b/emoji2/emoji2-bundled/src/main/java/androidx/emoji2/bundled/BundledEmojiCompatConfig.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.emoji.bundled;
+package androidx.emoji2.bundled;
 
 import android.content.Context;
 import android.content.res.AssetManager;
@@ -22,8 +22,8 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.core.util.Preconditions;
-import androidx.emoji.text.EmojiCompat;
-import androidx.emoji.text.MetadataRepo;
+import androidx.emoji2.text.EmojiCompat;
+import androidx.emoji2.text.MetadataRepo;
 
 /**
  * {@link EmojiCompat.Config} implementation that loads the metadata using AssetManager and
diff --git a/emoji2/emoji2-views-core/AndroidManifest.xml b/emoji2/emoji2-views-core/AndroidManifest.xml
new file mode 100644
index 0000000..2f4b90a5
--- /dev/null
+++ b/emoji2/emoji2-views-core/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?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 package="androidx.emoji2.helpers"/>
diff --git a/emoji2/emoji2-views-core/build.gradle b/emoji2/emoji2-views-core/build.gradle
new file mode 100644
index 0000000..6137849
--- /dev/null
+++ b/emoji2/emoji2-views-core/build.gradle
@@ -0,0 +1,46 @@
+import androidx.build.BundleInsideHelper
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.Publish
+
+import static androidx.build.dependencies.DependenciesKt.*
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("com.github.johnrengelman.shadow")
+}
+
+dependencies {
+    implementation(project(":emoji2:emoji2"))
+
+    api("androidx.core:core:1.3.0-rc01")
+    implementation("androidx.collection:collection:1.1.0")
+
+    androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
+    androidTestImplementation(ANDROIDX_TEST_CORE)
+    androidTestImplementation(ANDROIDX_TEST_RUNNER)
+    androidTestImplementation(ANDROIDX_TEST_RULES)
+    androidTestImplementation(ESPRESSO_CORE, libs.exclude_for_espresso)
+    androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+    androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+    androidTestImplementation project(':internal-testutils-runtime')
+}
+
+android {
+    sourceSets {
+        main {
+            // We use a non-standard manifest path.
+            manifest.srcFile 'AndroidManifest.xml'
+        }
+    }
+}
+
+androidx {
+    name = "Android Emoji2 Compat view helpers"
+    publish = Publish.NONE
+    mavenVersion = LibraryVersions.EMOJI2
+    mavenGroup = LibraryGroups.EMOJI2
+    inceptionYear = "2017"
+    description = "View helpers for Emoji2"
+}
diff --git a/emoji2/emoji2-views-core/src/androidTest/AndroidManifest.xml b/emoji2/emoji2-views-core/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..6c30771
--- /dev/null
+++ b/emoji2/emoji2-views-core/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?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 package="androidx.emoji2.helpers">
+
+    <application>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiEditTextHelperPre19Test.java b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiEditTextHelperPre19Test.java
similarity index 98%
rename from emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiEditTextHelperPre19Test.java
rename to emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiEditTextHelperPre19Test.java
index 2883836..c431518 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiEditTextHelperPre19Test.java
+++ b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiEditTextHelperPre19Test.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.emoji2.widget;
+package androidx.emoji2.helpers;
 
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiEditTextHelperTest.java b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiEditTextHelperTest.java
similarity index 99%
rename from emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiEditTextHelperTest.java
rename to emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiEditTextHelperTest.java
index f995697..c054c74 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiEditTextHelperTest.java
+++ b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiEditTextHelperTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.emoji2.widget;
+package androidx.emoji2.helpers;
 
 import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.junit.Assert.assertEquals;
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiEditableFactoryTest.java b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiEditableFactoryTest.java
similarity index 97%
rename from emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiEditableFactoryTest.java
rename to emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiEditableFactoryTest.java
index 7addec0..36200b0 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiEditableFactoryTest.java
+++ b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiEditableFactoryTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.emoji2.widget;
+package androidx.emoji2.helpers;
 
 import static org.hamcrest.Matchers.arrayWithSize;
 import static org.hamcrest.Matchers.instanceOf;
@@ -30,6 +30,7 @@
 
 import androidx.emoji2.text.EmojiMetadata;
 import androidx.emoji2.text.EmojiSpan;
+import androidx.emoji2.text.SpannableBuilder;
 import androidx.emoji2.text.TypefaceEmojiSpan;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
diff --git a/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiInputConnectionTest.java b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiInputConnectionTest.java
new file mode 100644
index 0000000..b963cba
--- /dev/null
+++ b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiInputConnectionTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2021 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.emoji2.helpers;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Build;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.TextView;
+
+import androidx.emoji2.util.Emoji;
+import androidx.emoji2.util.TestString;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.LargeTest;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+@SdkSuppress(minSdkVersion = 19)
+public class EmojiInputConnectionTest {
+
+    private InputConnection mInputConnection;
+    private TestString mTestString;
+    private Editable mEditable;
+    private EmojiInputConnection mEmojiEmojiInputConnection;
+    private EmojiInputConnection.EmojiCompatDeleteHelper mEmojiCompatDeleteHelper;
+
+    @Before
+    public void setup() {
+        mTestString = new TestString(Emoji.EMOJI_WITH_ZWJ).withPrefix().withSuffix();
+        mEditable = new SpannableStringBuilder(mTestString.toString());
+        mInputConnection = mock(InputConnection.class);
+        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        final TextView textView = spy(new TextView(context));
+        mEmojiCompatDeleteHelper = mock(EmojiInputConnection.EmojiCompatDeleteHelper.class);
+        doNothing().when(mEmojiCompatDeleteHelper).updateEditorInfoAttrs(any());
+
+        doReturn(mEditable).when(textView).getEditableText();
+        when(mInputConnection.deleteSurroundingText(anyInt(), anyInt())).thenReturn(false);
+        setupDeleteSurroundingText();
+
+        mEmojiEmojiInputConnection = new EmojiInputConnection(textView, mInputConnection,
+                new EditorInfo(), mEmojiCompatDeleteHelper);
+    }
+
+    private void setupDeleteSurroundingText() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            when(mInputConnection.deleteSurroundingTextInCodePoints(anyInt(), anyInt())).thenReturn(
+                    false);
+        }
+    }
+
+    @Test
+    public void whenEmojiCompatDelete_doesntDelete_inputConnectionIsCalled() {
+        Selection.setSelection(mEditable, 0, mEditable.length());
+        when(mEmojiCompatDeleteHelper.handleDeleteSurroundingText(any(), any(), anyInt(),
+                anyInt(), anyBoolean())).thenReturn(false);
+        assertFalse(mEmojiEmojiInputConnection.deleteSurroundingText(1, 0));
+        verify(mInputConnection, times(1)).deleteSurroundingText(1, 0);
+    }
+
+    @Test
+    public void whenEmojiCompatDelete_doesDelete_inputConnectionIsNotCalled() {
+        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
+        when(mEmojiCompatDeleteHelper.handleDeleteSurroundingText(any(), any(), anyInt(),
+                anyInt(), anyBoolean())).thenReturn(true);
+        assertTrue(mEmojiEmojiInputConnection.deleteSurroundingText(1, 0));
+        verify(mInputConnection, never()).deleteSurroundingText(anyInt(), anyInt());
+    }
+}
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiInputFilterTest.java b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiInputFilterTest.java
similarity index 98%
rename from emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiInputFilterTest.java
rename to emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiInputFilterTest.java
index dc9b977..1fe748d 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiInputFilterTest.java
+++ b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiInputFilterTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.emoji2.widget;
+package androidx.emoji2.helpers;
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
diff --git a/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiKeyListenerTest.java b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiKeyListenerTest.java
new file mode 100644
index 0000000..e623691
--- /dev/null
+++ b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiKeyListenerTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2021 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.emoji2.helpers;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.text.Editable;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.text.method.KeyListener;
+import android.view.KeyEvent;
+import android.view.View;
+
+import androidx.emoji2.util.Emoji;
+import androidx.emoji2.util.KeyboardUtil;
+import androidx.emoji2.util.TestString;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@SdkSuppress(minSdkVersion = 19)
+public class EmojiKeyListenerTest {
+
+    private KeyListener mKeyListener;
+    private TestString mTestString;
+    private Editable mEditable;
+    private EmojiKeyListener mEmojiKeyListener;
+    private EmojiKeyListener.EmojiCompatHandleKeyDownHelper mEmojiCompatKeydownHelper;
+
+    @Before
+    public void setup() {
+        mKeyListener = mock(KeyListener.class);
+        mTestString = new TestString(Emoji.EMOJI_WITH_ZWJ).withPrefix().withSuffix();
+        mEditable = new SpannableStringBuilder(mTestString.toString());
+        mEmojiCompatKeydownHelper = mock(EmojiKeyListener.EmojiCompatHandleKeyDownHelper.class);
+        mEmojiKeyListener = new EmojiKeyListener(mKeyListener, mEmojiCompatKeydownHelper);
+
+        when(mKeyListener.onKeyDown(any(View.class), any(Editable.class), anyInt(),
+                any(KeyEvent.class))).thenReturn(false);
+    }
+
+    @Test
+    public void whenEmojiCompat_handlesKeyDown_doesntCallKeyListener() {
+        Selection.setSelection(mEditable, 0);
+        final KeyEvent event = KeyboardUtil.zero();
+        when(mEmojiCompatKeydownHelper.handleKeyDown(any(), anyInt(), any())).thenReturn(true);
+        assertTrue(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verifyNoMoreInteractions(mKeyListener);
+    }
+
+    @Test
+    public void whenEmojiCompatDoesnt_handleKeyDown_callsListener() {
+        Selection.setSelection(mEditable, 0);
+        final KeyEvent event = KeyboardUtil.zero();
+        when(mEmojiCompatKeydownHelper.handleKeyDown(any(), anyInt(), any())).thenReturn(false);
+        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
+        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
+                eq(event.getKeyCode()), same(event));
+    }
+}
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiTextViewHelperPre19Test.java b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiTextViewHelperPre19Test.java
similarity index 98%
rename from emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiTextViewHelperPre19Test.java
rename to emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiTextViewHelperPre19Test.java
index eaa6a01..6a9932a 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiTextViewHelperPre19Test.java
+++ b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiTextViewHelperPre19Test.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.emoji2.widget;
+package androidx.emoji2.helpers;
 
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiTextViewHelperTest.java b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiTextViewHelperTest.java
similarity index 97%
rename from emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiTextViewHelperTest.java
rename to emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiTextViewHelperTest.java
index d4b00e9..51b71cf 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiTextViewHelperTest.java
+++ b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiTextViewHelperTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.emoji2.widget;
+package androidx.emoji2.helpers;
 
 import static org.hamcrest.CoreMatchers.hasItem;
 import static org.hamcrest.CoreMatchers.instanceOf;
@@ -35,6 +35,7 @@
 import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 
+import org.hamcrest.CoreMatchers;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -114,7 +115,7 @@
 
         assertEquals(2, newFilters.length);
         assertThat(Arrays.asList(newFilters), hasItem(existingFilter));
-        assertThat(Arrays.asList(newFilters), hasItem(emojiInputFilter));
+        assertThat(Arrays.asList(newFilters), CoreMatchers.hasItem(emojiInputFilter));
     }
 
     private EmojiInputFilter findEmojiInputFilter(final InputFilter[] filters) {
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiTextWatcherTest.java b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiTextWatcherTest.java
similarity index 98%
rename from emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiTextWatcherTest.java
rename to emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiTextWatcherTest.java
index 35b5d2e..e1cf65e 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiTextWatcherTest.java
+++ b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiTextWatcherTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.emoji2.widget;
+package androidx.emoji2.helpers;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiTransformationMethodTest.java b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiTransformationMethodTest.java
similarity index 99%
rename from emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiTransformationMethodTest.java
rename to emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiTransformationMethodTest.java
index 31122c8..4b9d10f 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiTransformationMethodTest.java
+++ b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/helpers/EmojiTransformationMethodTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.emoji2.widget;
+package androidx.emoji2.helpers;
 
 import static junit.framework.TestCase.assertSame;
 
diff --git a/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/util/Emoji.java b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/util/Emoji.java
new file mode 100644
index 0000000..73117a2
--- /dev/null
+++ b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/util/Emoji.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2021 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.emoji2.util;
+
+import androidx.annotation.NonNull;
+
+public class Emoji {
+
+    public static final int CHAR_KEYCAP = 0x20E3;
+    public static final int CHAR_DIGIT = 0x0039;
+    public static final int CHAR_ZWJ = 0x200D;
+    public static final int CHAR_VS_EMOJI = 0xFE0f;
+    public static final int CHAR_VS_TEXT = 0xFE0E;
+    public static final int CHAR_FITZPATRICK = 0x1F3FE;
+    public static final int CHAR_FITZPATRICK_TYPE_1 = 0x1F3fB;
+    public static final int CHAR_DEFAULT_TEXT_STYLE = 0x26F9;
+    public static final int CHAR_DEFAULT_EMOJI_STYLE = 0x1f3A2;
+    public static final int CHAR_FEMALE_SIGN = 0x2640;
+    public static final int CHAR_MAN = 0x1F468;
+    public static final int CHAR_HEART = 0x2764;
+    public static final int CHAR_KISS = 0x1F48B;
+    public static final int CHAR_REGIONAL_SYMBOL = 0x1F1E8;
+    public static final int CHAR_ASTERISK = 0x002A;
+
+    public static final EmojiMapping EMOJI_SINGLE_CODEPOINT = new EmojiMapping(
+            new int[]{CHAR_DEFAULT_EMOJI_STYLE}, 0xF01B4);
+
+    public static final EmojiMapping EMOJI_WITH_ZWJ = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_ZWJ, CHAR_HEART, CHAR_VS_EMOJI, CHAR_ZWJ, CHAR_KISS, CHAR_ZWJ,
+                    CHAR_MAN}, 0xF051F);
+
+    public static final EmojiMapping EMOJI_GENDER = new EmojiMapping(new int[]{
+            CHAR_DEFAULT_TEXT_STYLE, CHAR_VS_EMOJI, CHAR_ZWJ, CHAR_FEMALE_SIGN}, 0xF0950);
+
+    public static final EmojiMapping EMOJI_FLAG = new EmojiMapping(
+            new int[]{CHAR_REGIONAL_SYMBOL, CHAR_REGIONAL_SYMBOL}, 0xF03A0);
+
+    public static final EmojiMapping EMOJI_GENDER_WITHOUT_VS = new EmojiMapping(
+            new int[]{CHAR_DEFAULT_TEXT_STYLE, CHAR_ZWJ, CHAR_FEMALE_SIGN}, 0xF0950);
+
+    public static final EmojiMapping DEFAULT_TEXT_STYLE = new EmojiMapping(
+            new int[]{CHAR_DEFAULT_TEXT_STYLE, CHAR_VS_EMOJI}, 0xF04C6);
+
+    public static final EmojiMapping EMOJI_REGIONAL_SYMBOL = new EmojiMapping(
+            new int[]{CHAR_REGIONAL_SYMBOL}, 0xF0025);
+
+    public static final EmojiMapping EMOJI_UNKNOWN_FLAG = new EmojiMapping(
+            new int[]{0x1F1FA, 0x1F1F3}, 0xF0599);
+
+    public static final EmojiMapping EMOJI_DIGIT_ES = new EmojiMapping(
+            new int[]{CHAR_DIGIT, CHAR_VS_EMOJI}, 0xF0340);
+
+    public static final EmojiMapping EMOJI_DIGIT_KEYCAP = new EmojiMapping(
+            new int[]{CHAR_DIGIT, CHAR_KEYCAP}, 0xF0377);
+
+    public static final EmojiMapping EMOJI_DIGIT_ES_KEYCAP = new EmojiMapping(
+            new int[]{CHAR_DIGIT, CHAR_VS_EMOJI, CHAR_KEYCAP}, 0xF0377);
+
+    public static final EmojiMapping EMOJI_ASTERISK_KEYCAP = new EmojiMapping(
+            new int[]{CHAR_ASTERISK, CHAR_VS_EMOJI, CHAR_KEYCAP}, 0xF051D);
+
+    public static final EmojiMapping EMOJI_SKIN_MODIFIER = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_FITZPATRICK}, 0xF0603);
+
+    public static final EmojiMapping EMOJI_SKIN_MODIFIER_TYPE_ONE = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_FITZPATRICK_TYPE_1}, 0xF0606);
+
+    public static final EmojiMapping EMOJI_SKIN_MODIFIER_WITH_VS = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_VS_EMOJI, CHAR_FITZPATRICK_TYPE_1}, 0xF0606);
+
+    public static class EmojiMapping {
+        private final int[] mCodepoints;
+        private final int mId;
+
+        private EmojiMapping(@NonNull final int[] codepoints, final int id) {
+            mCodepoints = codepoints;
+            mId = id;
+        }
+
+        public final int[] codepoints() {
+            return mCodepoints;
+        }
+
+        public final int id() {
+            return mId;
+        }
+
+        public final int charCount() {
+            int count = 0;
+            for (int i = 0; i < mCodepoints.length; i++) {
+                count += Character.charCount(mCodepoints[i]);
+            }
+            return count;
+        }
+    }
+}
diff --git a/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/util/EmojiMatcher.java b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/util/EmojiMatcher.java
new file mode 100644
index 0000000..32d8e03
--- /dev/null
+++ b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/util/EmojiMatcher.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2021 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.emoji2.util;
+
+import static org.mockito.ArgumentMatchers.argThat;
+
+import android.text.Spanned;
+import android.text.TextUtils;
+
+import androidx.emoji2.text.EmojiSpan;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+import org.mockito.ArgumentMatcher;
+
+/**
+ * Utility class that includes matchers specific to emojis and EmojiSpans.
+ */
+public class EmojiMatcher {
+
+    public static Matcher<CharSequence> hasEmojiAt(final int id, final int start,
+            final int end) {
+        return new EmojiResourceMatcher(id, start, end);
+    }
+
+    public static Matcher<CharSequence> hasEmojiAt(final Emoji.EmojiMapping emojiMapping,
+            final int start, final int end) {
+        return new EmojiResourceMatcher(emojiMapping.id(), start, end);
+    }
+
+    public static Matcher<CharSequence> hasEmojiAt(final int start, final int end) {
+        return new EmojiResourceMatcher(-1, start, end);
+    }
+
+    public static Matcher<CharSequence> hasEmoji(final int id) {
+        return new EmojiResourceMatcher(id, -1, -1);
+    }
+
+    public static Matcher<CharSequence> hasEmoji(final Emoji.EmojiMapping emojiMapping) {
+        return new EmojiResourceMatcher(emojiMapping.id(), -1, -1);
+    }
+
+    public static Matcher<CharSequence> hasEmoji() {
+        return new EmojiSpanMatcher();
+    }
+
+    public static Matcher<CharSequence> hasEmojiCount(final int count) {
+        return new EmojiCountMatcher(count);
+    }
+
+    public static <T extends CharSequence> T sameCharSequence(final T expected) {
+        return argThat(new ArgumentMatcher<T>() {
+            @Override
+            public boolean matches(T o) {
+                if (o instanceof CharSequence) {
+                    return TextUtils.equals(expected, o);
+                }
+                return false;
+            }
+
+            @Override
+            public String toString() {
+                return "doesn't match " + expected;
+            }
+        });
+    }
+
+    private static class EmojiSpanMatcher extends TypeSafeMatcher<CharSequence> {
+
+        private EmojiSpan[] mSpans;
+
+        EmojiSpanMatcher() {
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("should have EmojiSpans");
+        }
+
+        @Override
+        protected void describeMismatchSafely(final CharSequence charSequence,
+                Description mismatchDescription) {
+            mismatchDescription.appendText(" has no EmojiSpans");
+        }
+
+        @Override
+        protected boolean matchesSafely(final CharSequence charSequence) {
+            if (charSequence == null) return false;
+            if (!(charSequence instanceof Spanned)) return false;
+            mSpans = ((Spanned) charSequence).getSpans(0, charSequence.length(), EmojiSpan.class);
+            return mSpans.length != 0;
+        }
+    }
+
+    private static class EmojiCountMatcher extends TypeSafeMatcher<CharSequence> {
+
+        private final int mCount;
+        private EmojiSpan[] mSpans;
+
+        EmojiCountMatcher(final int count) {
+            mCount = count;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("should have ").appendValue(mCount).appendText(" EmojiSpans");
+        }
+
+        @Override
+        protected void describeMismatchSafely(final CharSequence charSequence,
+                Description mismatchDescription) {
+            mismatchDescription.appendText(" has ");
+            if (mSpans == null) {
+                mismatchDescription.appendValue("no");
+            } else {
+                mismatchDescription.appendValue(mSpans.length);
+            }
+
+            mismatchDescription.appendText(" EmojiSpans");
+        }
+
+        @Override
+        protected boolean matchesSafely(final CharSequence charSequence) {
+            if (charSequence == null) return false;
+            if (!(charSequence instanceof Spanned)) return false;
+            mSpans = ((Spanned) charSequence).getSpans(0, charSequence.length(), EmojiSpan.class);
+            return mSpans.length == mCount;
+        }
+    }
+
+    private static class EmojiResourceMatcher extends TypeSafeMatcher<CharSequence> {
+        private static final int ERR_NONE = 0;
+        private static final int ERR_SPANNABLE_NULL = 1;
+        private static final int ERR_NO_SPANS = 2;
+        private static final int ERR_WRONG_INDEX = 3;
+        private final int mResId;
+        private final int mStart;
+        private final int mEnd;
+        private int mError = ERR_NONE;
+        private int mActualStart = -1;
+        private int mActualEnd = -1;
+
+        EmojiResourceMatcher(int resId, int start, int end) {
+            mResId = resId;
+            mStart = start;
+            mEnd = end;
+        }
+
+        @Override
+        public void describeTo(final Description description) {
+            if (mResId == -1) {
+                description.appendText("should have EmojiSpan at ")
+                        .appendValue("[" + mStart + "," + mEnd + "]");
+            } else if (mStart == -1 && mEnd == -1) {
+                description.appendText("should have EmojiSpan with resource id ")
+                        .appendValue(Integer.toHexString(mResId));
+            } else {
+                description.appendText("should have EmojiSpan with resource id ")
+                        .appendValue(Integer.toHexString(mResId))
+                        .appendText(" at ")
+                        .appendValue("[" + mStart + "," + mEnd + "]");
+            }
+        }
+
+        @Override
+        protected void describeMismatchSafely(final CharSequence charSequence,
+                Description mismatchDescription) {
+            int offset = 0;
+            mismatchDescription.appendText("[");
+            while (offset < charSequence.length()) {
+                int codepoint = Character.codePointAt(charSequence, offset);
+                mismatchDescription.appendText(Integer.toHexString(codepoint));
+                offset += Character.charCount(codepoint);
+                if (offset < charSequence.length()) {
+                    mismatchDescription.appendText(",");
+                }
+            }
+            mismatchDescription.appendText("]");
+
+            switch (mError) {
+                case ERR_NO_SPANS:
+                    mismatchDescription.appendText(" had no spans");
+                    break;
+                case ERR_SPANNABLE_NULL:
+                    mismatchDescription.appendText(" was null");
+                    break;
+                case ERR_WRONG_INDEX:
+                    mismatchDescription.appendText(" had Emoji at ")
+                            .appendValue("[" + mActualStart + "," + mActualEnd + "]");
+                    break;
+                default:
+                    mismatchDescription.appendText(" does not have an EmojiSpan with given "
+                            + "resource id ");
+            }
+        }
+
+        @Override
+        protected boolean matchesSafely(final CharSequence charSequence) {
+            if (charSequence == null) {
+                mError = ERR_SPANNABLE_NULL;
+                return false;
+            }
+
+            if (!(charSequence instanceof Spanned)) {
+                mError = ERR_NO_SPANS;
+                return false;
+            }
+
+            Spanned spanned = (Spanned) charSequence;
+            final EmojiSpan[] spans = spanned.getSpans(0, charSequence.length(), EmojiSpan.class);
+
+            if (spans.length == 0) {
+                mError = ERR_NO_SPANS;
+                return false;
+            }
+
+            if (mStart == -1 && mEnd == -1) {
+                for (int index = 0; index < spans.length; index++) {
+                    if (mResId == spans[index].getId()) {
+                        return true;
+                    }
+                }
+                return false;
+            } else {
+                for (int index = 0; index < spans.length; index++) {
+                    if (mResId == -1 || mResId == spans[index].getId()) {
+                        mActualStart = spanned.getSpanStart(spans[index]);
+                        mActualEnd = spanned.getSpanEnd(spans[index]);
+                        if (mActualStart == mStart && mActualEnd == mEnd) {
+                            return true;
+                        }
+                    }
+                }
+
+                if (mActualStart != -1 && mActualEnd != -1) {
+                    mError = ERR_WRONG_INDEX;
+                }
+
+                return false;
+            }
+        }
+    }
+}
diff --git a/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/util/KeyboardUtil.java b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/util/KeyboardUtil.java
new file mode 100644
index 0000000..48a6d2e
--- /dev/null
+++ b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/util/KeyboardUtil.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2021 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.emoji2.util;
+
+import android.app.Instrumentation;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.method.QwertyKeyListener;
+import android.text.method.TextKeyListener;
+import android.view.KeyEvent;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.TextView;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Utility class for KeyEvents
+ */
+public class KeyboardUtil {
+    private static final int ALT = KeyEvent.META_ALT_ON | KeyEvent.META_ALT_LEFT_ON;
+    private static final int CTRL = KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON;
+    private static final int SHIFT = KeyEvent.META_SHIFT_ON | KeyEvent.META_SHIFT_LEFT_ON;
+    private static final int FN = KeyEvent.META_FUNCTION_ON;
+
+    public static KeyEvent zero() {
+        return keyEvent(KeyEvent.KEYCODE_0);
+    }
+
+    public static KeyEvent del() {
+        return keyEvent(KeyEvent.KEYCODE_DEL);
+    }
+
+    public static KeyEvent altDel() {
+        return keyEvent(KeyEvent.KEYCODE_DEL, ALT);
+    }
+
+    public static KeyEvent ctrlDel() {
+        return keyEvent(KeyEvent.KEYCODE_DEL, CTRL);
+    }
+
+    public static KeyEvent shiftDel() {
+        return keyEvent(KeyEvent.KEYCODE_DEL, SHIFT);
+    }
+
+    public static KeyEvent fnDel() {
+        return keyEvent(KeyEvent.KEYCODE_DEL, FN);
+    }
+
+    public static KeyEvent forwardDel() {
+        return keyEvent(KeyEvent.KEYCODE_FORWARD_DEL);
+    }
+
+    public static KeyEvent keyEvent(int keycode, int metaState) {
+        final long currentTime = System.currentTimeMillis();
+        return new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN, keycode, 0, metaState);
+    }
+
+    public static KeyEvent keyEvent(int keycode) {
+        final long currentTime = System.currentTimeMillis();
+        return new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN, keycode, 0);
+    }
+
+    public static void setComposingTextInBatch(final Instrumentation instrumentation,
+            final InputConnection inputConnection, final CharSequence text)
+            throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                inputConnection.beginBatchEdit();
+                inputConnection.setComposingText(text, 1);
+                inputConnection.endBatchEdit();
+                latch.countDown();
+            }
+        });
+
+        latch.await();
+        instrumentation.waitForIdleSync();
+    }
+
+    public static void deleteSurroundingText(final Instrumentation instrumentation,
+            final InputConnection inputConnection, final int before, final int after)
+            throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                inputConnection.beginBatchEdit();
+                inputConnection.deleteSurroundingText(before, after);
+                inputConnection.endBatchEdit();
+                latch.countDown();
+            }
+        });
+        latch.await();
+        instrumentation.waitForIdleSync();
+    }
+
+    public static void setSelection(Instrumentation instrumentation, final Spannable spannable,
+            final int start) throws InterruptedException {
+        setSelection(instrumentation, spannable, start, start);
+    }
+
+    public static void setSelection(Instrumentation instrumentation, final Spannable spannable,
+            final int start, final int end) throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                Selection.setSelection(spannable, start, end);
+                latch.countDown();
+            }
+        });
+        latch.await();
+        instrumentation.waitForIdleSync();
+    }
+
+    public static InputConnection initTextViewForSimulatedIme(Instrumentation instrumentation,
+            final TextView textView) throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                textView.setKeyListener(
+                        QwertyKeyListener.getInstance(false, TextKeyListener.Capitalize.NONE));
+                textView.setText("", TextView.BufferType.EDITABLE);
+                latch.countDown();
+            }
+        });
+        latch.await();
+        instrumentation.waitForIdleSync();
+        return textView.onCreateInputConnection(new EditorInfo());
+    }
+}
diff --git a/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/util/TestString.java b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/util/TestString.java
new file mode 100644
index 0000000..83728da
--- /dev/null
+++ b/emoji2/emoji2-views-core/src/androidTest/java/androidx/emoji2/util/TestString.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2021 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.emoji2.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class used to create strings with emojis during tests.
+ */
+public class TestString {
+
+    private static final List<Integer> EMPTY_LIST = new ArrayList<>();
+
+    private static final String EXTRA = "ab";
+    private final List<Integer> mCodePoints;
+    private String mString;
+    private final String mValue;
+    private boolean mHasSuffix;
+    private boolean mHasPrefix;
+
+    public TestString(int... codePoints) {
+        if (codePoints.length == 0) {
+            mCodePoints = EMPTY_LIST;
+        } else {
+            mCodePoints = new ArrayList<>();
+            append(codePoints);
+        }
+        mValue = null;
+    }
+
+    public TestString(Emoji.EmojiMapping emojiMapping) {
+        this(emojiMapping.codepoints());
+    }
+
+    public TestString(String string) {
+        mCodePoints = EMPTY_LIST;
+        mValue = string;
+    }
+
+    public TestString append(int... codePoints) {
+        for (int i = 0; i < codePoints.length; i++) {
+            mCodePoints.add(codePoints[i]);
+        }
+        return this;
+    }
+
+    public TestString prepend(int... codePoints) {
+        for (int i = codePoints.length - 1; i >= 0; i--) {
+            mCodePoints.add(0, codePoints[i]);
+        }
+        return this;
+    }
+
+    public TestString append(Emoji.EmojiMapping emojiMapping) {
+        return append(emojiMapping.codepoints());
+    }
+
+    public TestString withSuffix() {
+        mHasSuffix = true;
+        return this;
+    }
+
+    public TestString withPrefix() {
+        mHasPrefix = true;
+        return this;
+    }
+
+    @SuppressWarnings("ForLoopReplaceableByForEach")
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        if (mHasPrefix) {
+            builder.append(EXTRA);
+        }
+
+        for (int index = 0; index < mCodePoints.size(); index++) {
+            builder.append(Character.toChars(mCodePoints.get(index)));
+        }
+
+        if (mValue != null) {
+            builder.append(mValue);
+        }
+
+        if (mHasSuffix) {
+            builder.append(EXTRA);
+        }
+        mString = builder.toString();
+        return mString;
+    }
+
+    public int emojiStartIndex() {
+        if (mHasPrefix) return EXTRA.length();
+        return 0;
+    }
+
+    public int emojiEndIndex() {
+        if (mHasSuffix) return mString.lastIndexOf(EXTRA);
+        return mString.length();
+    }
+}
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiEditTextHelper.java b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiEditTextHelper.java
similarity index 96%
rename from emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiEditTextHelper.java
rename to emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiEditTextHelper.java
index 32ee18b..75ab24e 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiEditTextHelper.java
+++ b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiEditTextHelper.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.emoji2.widget;
+package androidx.emoji2.helpers;
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
 
@@ -31,6 +31,7 @@
 import androidx.annotation.RestrictTo;
 import androidx.core.util.Preconditions;
 import androidx.emoji2.text.EmojiCompat;
+import androidx.emoji2.text.EmojiDefaults;
 import androidx.emoji2.text.EmojiSpan;
 
 /**
@@ -70,7 +71,7 @@
  */
 public final class EmojiEditTextHelper {
     private final HelperInternal mHelper;
-    private int mMaxEmojiCount = EditTextAttributeHelper.MAX_EMOJI_COUNT;
+    private int mMaxEmojiCount = EmojiDefaults.MAX_EMOJI_COUNT;
     @EmojiCompat.ReplaceStrategy
     private int mEmojiReplaceStrategy = EmojiCompat.REPLACE_STRATEGY_DEFAULT;
 
@@ -159,7 +160,7 @@
      * @hide
      */
     @RestrictTo(LIBRARY_GROUP_PREFIX)
-    void setEmojiReplaceStrategy(@EmojiCompat.ReplaceStrategy int replaceStrategy) {
+    public void setEmojiReplaceStrategy(@EmojiCompat.ReplaceStrategy int replaceStrategy) {
         mEmojiReplaceStrategy = replaceStrategy;
         mHelper.setEmojiReplaceStrategy(replaceStrategy);
     }
@@ -174,7 +175,7 @@
      * @hide
      */
     @RestrictTo(LIBRARY_GROUP_PREFIX)
-    int getEmojiReplaceStrategy() {
+    public int getEmojiReplaceStrategy() {
         return mEmojiReplaceStrategy;
     }
 
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiEditableFactory.java b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiEditableFactory.java
similarity index 96%
rename from emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiEditableFactory.java
rename to emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiEditableFactory.java
index b9c1abd..bb6a713f 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiEditableFactory.java
+++ b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiEditableFactory.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.emoji2.widget;
+package androidx.emoji2.helpers;
 
 import android.annotation.SuppressLint;
 import android.text.Editable;
@@ -21,6 +21,7 @@
 import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.emoji2.text.SpannableBuilder;
 
 /**
  * EditableFactory used to improve editing operations on an EditText.
diff --git a/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiInputConnection.java b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiInputConnection.java
new file mode 100644
index 0000000..91dcb46
--- /dev/null
+++ b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiInputConnection.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2021 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.emoji2.helpers;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
+
+import android.text.Editable;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputConnectionWrapper;
+import android.widget.TextView;
+
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RestrictTo;
+import androidx.emoji2.text.EmojiCompat;
+
+/**
+ * InputConnectionWrapper for EditText delete operations. Keyboard does not have knowledge about
+ * emojis and therefore might send commands to delete a part of the emoji sequence which creates
+ * invalid codeunits/getCodepointAt in the text.
+ * <p/>
+ * This class tries to correctly delete an emoji checking if there is an emoji span.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP_PREFIX)
+@RequiresApi(19)
+final class EmojiInputConnection extends InputConnectionWrapper {
+    private final TextView mTextView;
+    private final EmojiCompatDeleteHelper mEmojiCompatDeleteHelper;
+
+    EmojiInputConnection(
+            @NonNull final TextView textView,
+            @NonNull final InputConnection inputConnection,
+            @NonNull final EditorInfo outAttrs) {
+        this(textView, inputConnection, outAttrs, new EmojiCompatDeleteHelper());
+    }
+
+    EmojiInputConnection(
+            @NonNull final TextView textView,
+            @NonNull final InputConnection inputConnection,
+            @NonNull final EditorInfo outAttrs,
+            @NonNull final EmojiCompatDeleteHelper emojiCompatDeleteHelper
+    ) {
+        super(inputConnection, false);
+        mTextView = textView;
+        mEmojiCompatDeleteHelper = emojiCompatDeleteHelper;
+        mEmojiCompatDeleteHelper.updateEditorInfoAttrs(outAttrs);
+    }
+
+    @Override
+    public boolean deleteSurroundingText(final int beforeLength, final int afterLength) {
+        final boolean result = mEmojiCompatDeleteHelper.handleDeleteSurroundingText(
+                this, getEditable(), beforeLength, afterLength, false /*inCodePoints*/);
+        return result || super.deleteSurroundingText(beforeLength, afterLength);
+    }
+
+    @Override
+    public boolean deleteSurroundingTextInCodePoints(final int beforeLength,
+            final int afterLength) {
+        final boolean result = mEmojiCompatDeleteHelper.handleDeleteSurroundingText(
+                this, getEditable(), beforeLength, afterLength, true /*inCodePoints*/);
+        return result || super.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
+    }
+
+    private Editable getEditable() {
+        return mTextView.getEditableText();
+    }
+
+    public static class EmojiCompatDeleteHelper {
+        public boolean handleDeleteSurroundingText(
+                @NonNull final InputConnection inputConnection,
+                @NonNull final Editable editable,
+                @IntRange(from = 0) final int beforeLength,
+                @IntRange(from = 0) final int afterLength,
+                final boolean inCodePoints) {
+            return EmojiCompat.handleDeleteSurroundingText(inputConnection, editable,
+                    beforeLength, afterLength, inCodePoints);
+        }
+
+        public void updateEditorInfoAttrs(@NonNull final EditorInfo outAttrs) {
+            EmojiCompat.get().updateEditorInfoAttrs(outAttrs);
+        }
+    }
+}
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiInputFilter.java b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiInputFilter.java
similarity index 98%
rename from emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiInputFilter.java
rename to emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiInputFilter.java
index fb1bd11..ccb3033 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiInputFilter.java
+++ b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiInputFilter.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.emoji2.widget;
+package androidx.emoji2.helpers;
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
 
@@ -96,6 +96,7 @@
         return mInitCallback;
     }
 
+    @RequiresApi(19)
     private static class InitCallbackImpl extends InitCallback {
         private final Reference<TextView> mViewRef;
 
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiKeyListener.java b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiKeyListener.java
similarity index 70%
rename from emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiKeyListener.java
rename to emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiKeyListener.java
index 8bac084e..a5b2129 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiKeyListener.java
+++ b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiKeyListener.java
@@ -13,14 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.emoji2.widget;
+package androidx.emoji2.helpers;
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
 
 import android.text.Editable;
+import android.text.method.KeyListener;
 import android.view.KeyEvent;
 import android.view.View;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.emoji2.text.EmojiCompat;
@@ -34,9 +36,16 @@
 @RequiresApi(19)
 final class EmojiKeyListener implements android.text.method.KeyListener {
     private final android.text.method.KeyListener mKeyListener;
+    private final EmojiCompatHandleKeyDownHelper mEmojiCompatHandleKeyDownHelper;
 
     EmojiKeyListener(android.text.method.KeyListener keyListener) {
+        this(keyListener, new EmojiCompatHandleKeyDownHelper());
+    }
+
+    EmojiKeyListener(KeyListener keyListener,
+            EmojiCompatHandleKeyDownHelper emojiCompatKeydownHelper) {
         mKeyListener = keyListener;
+        mEmojiCompatHandleKeyDownHelper = emojiCompatKeydownHelper;
     }
 
     @Override
@@ -46,7 +55,8 @@
 
     @Override
     public boolean onKeyDown(View view, Editable content, int keyCode, KeyEvent event) {
-        final boolean result = EmojiCompat.handleOnKeyDown(content, keyCode, event);
+        final boolean result = mEmojiCompatHandleKeyDownHelper
+                .handleKeyDown(content, keyCode, event);
         return result || mKeyListener.onKeyDown(view, content, keyCode, event);
     }
 
@@ -64,4 +74,12 @@
     public void clearMetaKeyState(View view, Editable content, int states) {
         mKeyListener.clearMetaKeyState(view, content, states);
     }
+
+    public static class EmojiCompatHandleKeyDownHelper {
+        public boolean handleKeyDown(@NonNull final Editable editable, final int keyCode,
+                @NonNull final KeyEvent event) {
+            return EmojiCompat.handleOnKeyDown(editable, keyCode, event);
+        }
+    }
+
 }
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiTextViewHelper.java b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiTextViewHelper.java
similarity index 99%
rename from emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiTextViewHelper.java
rename to emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiTextViewHelper.java
index d6a34e4..ee45e85 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiTextViewHelper.java
+++ b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiTextViewHelper.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.emoji2.widget;
+package androidx.emoji2.helpers;
 
 import android.os.Build;
 import android.text.InputFilter;
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiTextWatcher.java b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiTextWatcher.java
similarity index 95%
rename from emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiTextWatcher.java
rename to emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiTextWatcher.java
index 46fae2b..43887bb 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiTextWatcher.java
+++ b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiTextWatcher.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.emoji2.widget;
+package androidx.emoji2.helpers;
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
 
@@ -26,6 +26,7 @@
 import androidx.annotation.RestrictTo;
 import androidx.emoji2.text.EmojiCompat;
 import androidx.emoji2.text.EmojiCompat.InitCallback;
+import androidx.emoji2.text.EmojiDefaults;
 
 import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
@@ -40,7 +41,7 @@
 final class EmojiTextWatcher implements android.text.TextWatcher {
     private final EditText mEditText;
     private InitCallback mInitCallback;
-    private int mMaxEmojiCount = EditTextAttributeHelper.MAX_EMOJI_COUNT;
+    private int mMaxEmojiCount = EmojiDefaults.MAX_EMOJI_COUNT;
     @EmojiCompat.ReplaceStrategy
     private int mEmojiReplaceStrategy = EmojiCompat.REPLACE_STRATEGY_DEFAULT;
 
@@ -107,6 +108,7 @@
         return mInitCallback;
     }
 
+    @RequiresApi(19)
     private static class InitCallbackImpl extends InitCallback {
         private final Reference<EditText> mViewRef;
 
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiTransformationMethod.java b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiTransformationMethod.java
similarity index 98%
rename from emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiTransformationMethod.java
rename to emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiTransformationMethod.java
index 16a4780..78756b6 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiTransformationMethod.java
+++ b/emoji2/emoji2-views-core/src/main/java/androidx/emoji2/helpers/EmojiTransformationMethod.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.emoji2.widget;
+package androidx.emoji2.helpers;
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
 
diff --git a/emoji2/emoji2-views/AndroidManifest.xml b/emoji2/emoji2-views/AndroidManifest.xml
new file mode 100644
index 0000000..523feaf
--- /dev/null
+++ b/emoji2/emoji2-views/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?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 package="androidx.emoji2.widget"/>
diff --git a/emoji2/emoji2-views/build.gradle b/emoji2/emoji2-views/build.gradle
new file mode 100644
index 0000000..6876fb1
--- /dev/null
+++ b/emoji2/emoji2-views/build.gradle
@@ -0,0 +1,50 @@
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.Publish
+
+import static androidx.build.dependencies.DependenciesKt.*
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("com.github.johnrengelman.shadow")
+}
+
+dependencies {
+    api("androidx.core:core:1.3.0-rc01")
+    api(project(":emoji2:emoji2"))
+    implementation(project(":emoji2:emoji2-views-core"))
+
+    implementation("androidx.collection:collection:1.1.0")
+
+    androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
+    androidTestImplementation(ANDROIDX_TEST_CORE)
+    androidTestImplementation(ANDROIDX_TEST_RUNNER)
+    androidTestImplementation(ANDROIDX_TEST_RULES)
+    androidTestImplementation(ESPRESSO_CORE, libs.exclude_for_espresso)
+    androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+    androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+    androidTestImplementation project(':internal-testutils-runtime')
+}
+
+android {
+    sourceSets {
+        main {
+            // We use a non-standard manifest path.
+            manifest.srcFile 'AndroidManifest.xml'
+            res.srcDirs += 'src/main/res-public'
+            // TODO(seanmcq): rewrite the tests to avoid needing the font / license files
+            // removed to avoid dupe files
+        }
+    }
+}
+
+androidx {
+    name = "Android Emoji2 Compat Views"
+    publish = Publish.NONE
+    mavenVersion = LibraryVersions.EMOJI2
+    mavenGroup = LibraryGroups.EMOJI2
+    inceptionYear = "2017"
+    description = "Support for using emoji2 directly with Android Views, for use in apps without " +
+            "appcompat"
+}
diff --git a/emoji2/emoji2-views/src/androidTest/AndroidManifest.xml b/emoji2/emoji2-views/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..66a230e
--- /dev/null
+++ b/emoji2/emoji2-views/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?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.emoji2.widget">
+
+    <application>
+        <activity android:name=".ViewsTestActivity"/>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/util/Emoji.java b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/util/Emoji.java
new file mode 100644
index 0000000..73117a2
--- /dev/null
+++ b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/util/Emoji.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2021 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.emoji2.util;
+
+import androidx.annotation.NonNull;
+
+public class Emoji {
+
+    public static final int CHAR_KEYCAP = 0x20E3;
+    public static final int CHAR_DIGIT = 0x0039;
+    public static final int CHAR_ZWJ = 0x200D;
+    public static final int CHAR_VS_EMOJI = 0xFE0f;
+    public static final int CHAR_VS_TEXT = 0xFE0E;
+    public static final int CHAR_FITZPATRICK = 0x1F3FE;
+    public static final int CHAR_FITZPATRICK_TYPE_1 = 0x1F3fB;
+    public static final int CHAR_DEFAULT_TEXT_STYLE = 0x26F9;
+    public static final int CHAR_DEFAULT_EMOJI_STYLE = 0x1f3A2;
+    public static final int CHAR_FEMALE_SIGN = 0x2640;
+    public static final int CHAR_MAN = 0x1F468;
+    public static final int CHAR_HEART = 0x2764;
+    public static final int CHAR_KISS = 0x1F48B;
+    public static final int CHAR_REGIONAL_SYMBOL = 0x1F1E8;
+    public static final int CHAR_ASTERISK = 0x002A;
+
+    public static final EmojiMapping EMOJI_SINGLE_CODEPOINT = new EmojiMapping(
+            new int[]{CHAR_DEFAULT_EMOJI_STYLE}, 0xF01B4);
+
+    public static final EmojiMapping EMOJI_WITH_ZWJ = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_ZWJ, CHAR_HEART, CHAR_VS_EMOJI, CHAR_ZWJ, CHAR_KISS, CHAR_ZWJ,
+                    CHAR_MAN}, 0xF051F);
+
+    public static final EmojiMapping EMOJI_GENDER = new EmojiMapping(new int[]{
+            CHAR_DEFAULT_TEXT_STYLE, CHAR_VS_EMOJI, CHAR_ZWJ, CHAR_FEMALE_SIGN}, 0xF0950);
+
+    public static final EmojiMapping EMOJI_FLAG = new EmojiMapping(
+            new int[]{CHAR_REGIONAL_SYMBOL, CHAR_REGIONAL_SYMBOL}, 0xF03A0);
+
+    public static final EmojiMapping EMOJI_GENDER_WITHOUT_VS = new EmojiMapping(
+            new int[]{CHAR_DEFAULT_TEXT_STYLE, CHAR_ZWJ, CHAR_FEMALE_SIGN}, 0xF0950);
+
+    public static final EmojiMapping DEFAULT_TEXT_STYLE = new EmojiMapping(
+            new int[]{CHAR_DEFAULT_TEXT_STYLE, CHAR_VS_EMOJI}, 0xF04C6);
+
+    public static final EmojiMapping EMOJI_REGIONAL_SYMBOL = new EmojiMapping(
+            new int[]{CHAR_REGIONAL_SYMBOL}, 0xF0025);
+
+    public static final EmojiMapping EMOJI_UNKNOWN_FLAG = new EmojiMapping(
+            new int[]{0x1F1FA, 0x1F1F3}, 0xF0599);
+
+    public static final EmojiMapping EMOJI_DIGIT_ES = new EmojiMapping(
+            new int[]{CHAR_DIGIT, CHAR_VS_EMOJI}, 0xF0340);
+
+    public static final EmojiMapping EMOJI_DIGIT_KEYCAP = new EmojiMapping(
+            new int[]{CHAR_DIGIT, CHAR_KEYCAP}, 0xF0377);
+
+    public static final EmojiMapping EMOJI_DIGIT_ES_KEYCAP = new EmojiMapping(
+            new int[]{CHAR_DIGIT, CHAR_VS_EMOJI, CHAR_KEYCAP}, 0xF0377);
+
+    public static final EmojiMapping EMOJI_ASTERISK_KEYCAP = new EmojiMapping(
+            new int[]{CHAR_ASTERISK, CHAR_VS_EMOJI, CHAR_KEYCAP}, 0xF051D);
+
+    public static final EmojiMapping EMOJI_SKIN_MODIFIER = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_FITZPATRICK}, 0xF0603);
+
+    public static final EmojiMapping EMOJI_SKIN_MODIFIER_TYPE_ONE = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_FITZPATRICK_TYPE_1}, 0xF0606);
+
+    public static final EmojiMapping EMOJI_SKIN_MODIFIER_WITH_VS = new EmojiMapping(
+            new int[]{CHAR_MAN, CHAR_VS_EMOJI, CHAR_FITZPATRICK_TYPE_1}, 0xF0606);
+
+    public static class EmojiMapping {
+        private final int[] mCodepoints;
+        private final int mId;
+
+        private EmojiMapping(@NonNull final int[] codepoints, final int id) {
+            mCodepoints = codepoints;
+            mId = id;
+        }
+
+        public final int[] codepoints() {
+            return mCodepoints;
+        }
+
+        public final int id() {
+            return mId;
+        }
+
+        public final int charCount() {
+            int count = 0;
+            for (int i = 0; i < mCodepoints.length; i++) {
+                count += Character.charCount(mCodepoints[i]);
+            }
+            return count;
+        }
+    }
+}
diff --git a/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/util/EmojiMatcher.java b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/util/EmojiMatcher.java
new file mode 100644
index 0000000..0a37ebc
--- /dev/null
+++ b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/util/EmojiMatcher.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2021 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.emoji2.util;
+
+import static org.mockito.ArgumentMatchers.argThat;
+
+import android.text.Spanned;
+import android.text.TextUtils;
+
+import androidx.emoji2.text.EmojiSpan;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+import org.mockito.ArgumentMatcher;
+
+/**
+ * Utility class that includes matchers specific to emojis and EmojiSpans.
+ */
+public class EmojiMatcher {
+
+    public static Matcher<CharSequence> hasEmojiCount(final int count) {
+        return new EmojiCountMatcher(count);
+    }
+
+    public static <T extends CharSequence> T sameCharSequence(final T expected) {
+        return argThat(new ArgumentMatcher<T>() {
+            @Override
+            public boolean matches(T o) {
+                if (o instanceof CharSequence) {
+                    return TextUtils.equals(expected, o);
+                }
+                return false;
+            }
+
+            @Override
+            public String toString() {
+                return "doesn't match " + expected;
+            }
+        });
+    }
+
+    private static class EmojiCountMatcher extends TypeSafeMatcher<CharSequence> {
+
+        private final int mCount;
+        private EmojiSpan[] mSpans;
+
+        EmojiCountMatcher(final int count) {
+            mCount = count;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("should have ").appendValue(mCount).appendText(" EmojiSpans");
+        }
+
+        @Override
+        protected void describeMismatchSafely(final CharSequence charSequence,
+                Description mismatchDescription) {
+            mismatchDescription.appendText(" has ");
+            if (mSpans == null) {
+                mismatchDescription.appendValue("no");
+            } else {
+                mismatchDescription.appendValue(mSpans.length);
+            }
+
+            mismatchDescription.appendText(" EmojiSpans");
+        }
+
+        @Override
+        protected boolean matchesSafely(final CharSequence charSequence) {
+            if (charSequence == null) return false;
+            if (!(charSequence instanceof Spanned)) return false;
+            mSpans = ((Spanned) charSequence).getSpans(0, charSequence.length(), EmojiSpan.class);
+            return mSpans.length == mCount;
+        }
+    }
+
+}
diff --git a/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/util/TestString.java b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/util/TestString.java
new file mode 100644
index 0000000..83728da
--- /dev/null
+++ b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/util/TestString.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2021 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.emoji2.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class used to create strings with emojis during tests.
+ */
+public class TestString {
+
+    private static final List<Integer> EMPTY_LIST = new ArrayList<>();
+
+    private static final String EXTRA = "ab";
+    private final List<Integer> mCodePoints;
+    private String mString;
+    private final String mValue;
+    private boolean mHasSuffix;
+    private boolean mHasPrefix;
+
+    public TestString(int... codePoints) {
+        if (codePoints.length == 0) {
+            mCodePoints = EMPTY_LIST;
+        } else {
+            mCodePoints = new ArrayList<>();
+            append(codePoints);
+        }
+        mValue = null;
+    }
+
+    public TestString(Emoji.EmojiMapping emojiMapping) {
+        this(emojiMapping.codepoints());
+    }
+
+    public TestString(String string) {
+        mCodePoints = EMPTY_LIST;
+        mValue = string;
+    }
+
+    public TestString append(int... codePoints) {
+        for (int i = 0; i < codePoints.length; i++) {
+            mCodePoints.add(codePoints[i]);
+        }
+        return this;
+    }
+
+    public TestString prepend(int... codePoints) {
+        for (int i = codePoints.length - 1; i >= 0; i--) {
+            mCodePoints.add(0, codePoints[i]);
+        }
+        return this;
+    }
+
+    public TestString append(Emoji.EmojiMapping emojiMapping) {
+        return append(emojiMapping.codepoints());
+    }
+
+    public TestString withSuffix() {
+        mHasSuffix = true;
+        return this;
+    }
+
+    public TestString withPrefix() {
+        mHasPrefix = true;
+        return this;
+    }
+
+    @SuppressWarnings("ForLoopReplaceableByForEach")
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        if (mHasPrefix) {
+            builder.append(EXTRA);
+        }
+
+        for (int index = 0; index < mCodePoints.size(); index++) {
+            builder.append(Character.toChars(mCodePoints.get(index)));
+        }
+
+        if (mValue != null) {
+            builder.append(mValue);
+        }
+
+        if (mHasSuffix) {
+            builder.append(EXTRA);
+        }
+        mString = builder.toString();
+        return mString;
+    }
+
+    public int emojiStartIndex() {
+        if (mHasPrefix) return EXTRA.length();
+        return 0;
+    }
+
+    public int emojiEndIndex() {
+        if (mHasSuffix) return mString.lastIndexOf(EXTRA);
+        return mString.length();
+    }
+}
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiEditTextTest.java b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/EmojiEditTextTest.java
similarity index 70%
rename from emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiEditTextTest.java
rename to emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/EmojiEditTextTest.java
index 9db816f..fb58f76 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiEditTextTest.java
+++ b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/EmojiEditTextTest.java
@@ -22,13 +22,11 @@
 
 import android.app.Instrumentation;
 
-import androidx.emoji2.test.R;
 import androidx.emoji2.text.EmojiCompat;
-import androidx.emoji2.text.TestActivity;
-import androidx.emoji2.text.TestConfigBuilder;
 import androidx.emoji2.util.Emoji;
 import androidx.emoji2.util.EmojiMatcher;
 import androidx.emoji2.util.TestString;
+import androidx.emoji2.widget.test.R;
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
@@ -37,6 +35,7 @@
 
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -47,8 +46,8 @@
 
     @SuppressWarnings("deprecation")
     @Rule
-    public androidx.test.rule.ActivityTestRule<TestActivity> mActivityRule =
-            new androidx.test.rule.ActivityTestRule<>(TestActivity.class);
+    public androidx.test.rule.ActivityTestRule<ViewsTestActivity> mActivityRule =
+            new androidx.test.rule.ActivityTestRule<>(ViewsTestActivity.class);
     private Instrumentation mInstrumentation;
 
     @BeforeClass
@@ -63,7 +62,7 @@
 
     @Test
     public void testInflateWithMaxEmojiCount() {
-        final TestActivity activity = mActivityRule.getActivity();
+        final ViewsTestActivity activity = mActivityRule.getActivity();
         final EmojiEditText editText = activity.findViewById(R.id.editTextWithMaxCount);
 
         // value set in XML
@@ -84,16 +83,18 @@
     @Test
     @UiThreadTest
     public void testSetKeyListener_withNull() {
-        final TestActivity activity = mActivityRule.getActivity();
+        final ViewsTestActivity activity = mActivityRule.getActivity();
         final EmojiEditText editText = activity.findViewById(R.id.editTextWithMaxCount);
         editText.setKeyListener(null);
         assertNull(editText.getKeyListener());
     }
 
+    //TODO(seanmcq): re-enable without dependency on font
     @Test
     @SdkSuppress(minSdkVersion = 19)
+    @Ignore("Disabled to avoid adding dependency on emoji font to this artifact")
     public void testSetMaxCount() {
-        final TestActivity activity = mActivityRule.getActivity();
+        final ViewsTestActivity activity = mActivityRule.getActivity();
         final EmojiEditText editText = activity.findViewById(R.id.editTextWithMaxCount);
 
         // set max emoji count to 1 and set text with 2 emojis
@@ -110,4 +111,25 @@
 
         assertThat(editText.getText(), EmojiMatcher.hasEmojiCount(1));
     }
+
+    //TODO(seanmcq): re-enable without dependency on font
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    @Ignore("Disabled to avoid adding dependency on emoji font to this artifact")
+    public void testDoesReplaceEmoji() {
+        final ViewsTestActivity activity = mActivityRule.getActivity();
+        final EmojiEditText editText = activity.findViewById(R.id.editText);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                final String string = new TestString(Emoji.EMOJI_FLAG).append(
+                        Emoji.EMOJI_FLAG).toString();
+                editText.setText(string);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertThat(editText.getText(), EmojiMatcher.hasEmojiCount(2));
+    }
 }
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiExtractTextLayoutTest.java b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/EmojiExtractTextLayoutTest.java
similarity index 93%
rename from emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiExtractTextLayoutTest.java
rename to emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/EmojiExtractTextLayoutTest.java
index 2bb4ec04..a3144230 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiExtractTextLayoutTest.java
+++ b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/EmojiExtractTextLayoutTest.java
@@ -36,7 +36,6 @@
 import android.view.ViewGroup;
 import android.view.inputmethod.EditorInfo;
 
-import androidx.emoji2.R;
 import androidx.emoji2.text.EmojiCompat;
 import androidx.emoji2.util.EmojiMatcher;
 import androidx.test.annotation.UiThreadTest;
@@ -71,7 +70,7 @@
     public void testInflate() {
         final Context context = ApplicationProvider.getApplicationContext();
         final EmojiExtractTextLayout layout = (EmojiExtractTextLayout) LayoutInflater.from(context)
-                .inflate(androidx.emoji2.test.R.layout.extract_view, null);
+                .inflate(androidx.emoji2.widget.test.R.layout.extract_view, null);
 
         final EmojiExtractEditText extractEditText = layout.findViewById(
                 android.R.id.inputExtractEditText);
@@ -91,7 +90,7 @@
     public void testSetKeyListener_withNull() {
         final Context context = ApplicationProvider.getApplicationContext();
         final EmojiExtractTextLayout layout = (EmojiExtractTextLayout) LayoutInflater.from(context)
-                .inflate(androidx.emoji2.test.R.layout.extract_view, null);
+                .inflate(androidx.emoji2.widget.test.R.layout.extract_view, null);
 
         final EmojiExtractEditText extractEditText = layout.findViewById(
                 android.R.id.inputExtractEditText);
@@ -107,7 +106,7 @@
         final Context context = ApplicationProvider.getApplicationContext();
 
         final EmojiExtractTextLayout layout = (EmojiExtractTextLayout) LayoutInflater.from(context)
-                .inflate(androidx.emoji2.test.R.layout.extract_view_with_attrs, null);
+                .inflate(androidx.emoji2.widget.test.R.layout.extract_view_with_attrs, null);
 
         assertEquals(EmojiCompat.REPLACE_STRATEGY_NON_EXISTENT, layout.getEmojiReplaceStrategy());
 
@@ -129,7 +128,7 @@
         final Context context = ApplicationProvider.getApplicationContext();
 
         final EmojiExtractTextLayout layout = (EmojiExtractTextLayout) LayoutInflater.from(context)
-                .inflate(androidx.emoji2.test.R.layout.extract_view_with_attrs, null);
+                .inflate(androidx.emoji2.widget.test.R.layout.extract_view_with_attrs, null);
 
         final EmojiExtractEditText extractEditText = layout.findViewById(
                 android.R.id.inputExtractEditText);
@@ -156,7 +155,7 @@
     public void testOnUpdateExtractingViews() {
         final Context context = ApplicationProvider.getApplicationContext();
         final EmojiExtractTextLayout layout = (EmojiExtractTextLayout) LayoutInflater.from(context)
-                .inflate(androidx.emoji2.test.R.layout.extract_view, null);
+                .inflate(androidx.emoji2.widget.test.R.layout.extract_view, null);
 
         final EditorInfo editorInfo = new EditorInfo();
         editorInfo.actionLabel = "My Action Label";
@@ -184,7 +183,7 @@
     public void testOnUpdateExtractingViews_hidesAccessoriesIfNoAction() {
         final Context context = ApplicationProvider.getApplicationContext();
         final EmojiExtractTextLayout layout = (EmojiExtractTextLayout) LayoutInflater.from(context)
-                .inflate(androidx.emoji2.test.R.layout.extract_view, null);
+                .inflate(androidx.emoji2.widget.test.R.layout.extract_view, null);
 
         final EditorInfo editorInfo = new EditorInfo();
         editorInfo.imeOptions = EditorInfo.IME_ACTION_NONE;
diff --git a/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/EmojiTextViewTest.java b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/EmojiTextViewTest.java
new file mode 100644
index 0000000..f217a7a
--- /dev/null
+++ b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/EmojiTextViewTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2021 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.emoji2.widget;
+
+import static org.junit.Assert.assertThat;
+
+import android.app.Instrumentation;
+import android.widget.TextView;
+
+import androidx.emoji2.text.EmojiCompat;
+import androidx.emoji2.util.Emoji;
+import androidx.emoji2.util.EmojiMatcher;
+import androidx.emoji2.util.TestString;
+import androidx.emoji2.widget.test.R;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiTextViewTest {
+
+    @SuppressWarnings("deprecation")
+    @Rule
+    public androidx.test.rule.ActivityTestRule<ViewsTestActivity> mActivityRule =
+            new androidx.test.rule.ActivityTestRule<>(ViewsTestActivity.class);
+    private Instrumentation mInstrumentation;
+
+    @BeforeClass
+    public static void setupEmojiCompat() {
+        EmojiCompat.reset(TestConfigBuilder.config());
+    }
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+    }
+
+    //TODO(seanmcq): re-enable without dependency on font
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    @Ignore("Disabled to avoid adding dependency on emoji font to this artifact")
+    public void whenEmojiTextView_setText_emojiIsProcessedToSpans() {
+        final ViewsTestActivity activity = mActivityRule.getActivity();
+        final TextView textView = activity.findViewById(R.id.emojiTextView);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                final String string = new TestString(Emoji.EMOJI_FLAG).append(
+                        Emoji.EMOJI_FLAG).toString();
+                textView.setText(string);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertThat(textView.getText(), EmojiMatcher.hasEmojiCount(2));
+    }
+}
diff --git a/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/TestConfigBuilder.java b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/TestConfigBuilder.java
new file mode 100644
index 0000000..27c77cc
--- /dev/null
+++ b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/TestConfigBuilder.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2021 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.emoji2.widget;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+import androidx.emoji2.text.EmojiCompat;
+import androidx.emoji2.text.MetadataRepo;
+import androidx.test.core.app.ApplicationProvider;
+
+public class TestConfigBuilder {
+    private static final String FONT_FILE = "NotoColorEmojiCompat.ttf";
+
+    private TestConfigBuilder() { }
+
+    public static EmojiCompat.Config config() {
+        return new TestConfig().setReplaceAll(true);
+    }
+
+    /**
+     * Forces the creation of Metadata instead of relying on cached metadata. If GlyphChecker is
+     * mocked, a new metadata has to be used instead of the statically cached metadata since the
+     * result of GlyphChecker on the same device might effect other tests.
+     */
+    public static EmojiCompat.Config freshConfig() {
+        return new TestConfig(new ResettingTestDataLoader()).setReplaceAll(true);
+    }
+
+    public static class TestConfig extends EmojiCompat.Config {
+        TestConfig() {
+            super(new TestEmojiDataLoader());
+        }
+
+        TestConfig(final EmojiCompat.MetadataRepoLoader metadataLoader) {
+            super(metadataLoader);
+        }
+    }
+
+    public static class TestEmojiDataLoader implements EmojiCompat.MetadataRepoLoader {
+        static final Object S_METADATA_REPO_LOCK = new Object();
+        // keep a static instance to in order not to slow down the tests
+        @GuardedBy("sMetadataRepoLock")
+        static volatile MetadataRepo sMetadataRepo;
+
+        TestEmojiDataLoader() {
+        }
+
+        @Override
+        public void load(@NonNull EmojiCompat.MetadataRepoLoaderCallback loaderCallback) {
+            if (sMetadataRepo == null) {
+                synchronized (S_METADATA_REPO_LOCK) {
+                    if (sMetadataRepo == null) {
+                        try {
+                            final Context context = ApplicationProvider.getApplicationContext();
+                            final AssetManager assetManager = context.getAssets();
+                            sMetadataRepo = MetadataRepo.create(assetManager, FONT_FILE);
+                        } catch (Throwable e) {
+                            loaderCallback.onFailed(e);
+                            throw new RuntimeException(e);
+                        }
+                    }
+                }
+            }
+
+            loaderCallback.onLoaded(sMetadataRepo);
+        }
+    }
+
+    public static class ResettingTestDataLoader implements EmojiCompat.MetadataRepoLoader {
+        private MetadataRepo mMetadataRepo;
+
+        ResettingTestDataLoader() {
+        }
+
+        @Override
+        public void load(@NonNull EmojiCompat.MetadataRepoLoaderCallback loaderCallback) {
+            if (mMetadataRepo == null) {
+                try {
+                    final Context context = ApplicationProvider.getApplicationContext();
+                    final AssetManager assetManager = context.getAssets();
+                    mMetadataRepo = MetadataRepo.create(assetManager, FONT_FILE);
+                } catch (Throwable e) {
+                    loaderCallback.onFailed(e);
+                    throw new RuntimeException(e);
+                }
+            }
+
+            loaderCallback.onLoaded(mMetadataRepo);
+        }
+    }
+
+}
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/ViewsTestActivity.java
similarity index 62%
copy from compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
copy to emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/ViewsTestActivity.java
index 7e01354..5727acd 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
+++ b/emoji2/emoji2-views/src/androidTest/java/androidx/emoji2/widget/ViewsTestActivity.java
@@ -1,5 +1,3 @@
-// ktlint-disable filename
-
 /*
  * Copyright 2021 The Android Open Source Project
  *
@@ -15,7 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package androidx.emoji2.widget;
 
-package androidx.compose.foundation
+import android.app.Activity;
+import android.os.Bundle;
 
-internal actual typealias AtomicReference<V> = java.util.concurrent.atomic.AtomicReference<V>
\ No newline at end of file
+import androidx.emoji2.widget.test.R;
+
+public class ViewsTestActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.views_activity_default);
+    }
+}
diff --git a/emoji2/emoji2/src/androidTest/res/layout/extract_view.xml b/emoji2/emoji2-views/src/androidTest/res/layout/extract_view.xml
similarity index 100%
rename from emoji2/emoji2/src/androidTest/res/layout/extract_view.xml
rename to emoji2/emoji2-views/src/androidTest/res/layout/extract_view.xml
diff --git a/emoji2/emoji2/src/androidTest/res/layout/extract_view_with_attrs.xml b/emoji2/emoji2-views/src/androidTest/res/layout/extract_view_with_attrs.xml
similarity index 100%
rename from emoji2/emoji2/src/androidTest/res/layout/extract_view_with_attrs.xml
rename to emoji2/emoji2-views/src/androidTest/res/layout/extract_view_with_attrs.xml
diff --git a/emoji2/emoji2-views/src/androidTest/res/layout/views_activity_default.xml b/emoji2/emoji2-views/src/androidTest/res/layout/views_activity_default.xml
new file mode 100644
index 0000000..b8905da
--- /dev/null
+++ b/emoji2/emoji2-views/src/androidTest/res/layout/views_activity_default.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              xmlns:app="http://schemas.android.com/apk/res-auto"
+              android:id="@+id/root"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="8sp"/>
+
+    <androidx.emoji2.widget.EmojiTextView
+        android:id="@+id/emojiTextView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textSize="8sp" />
+
+    <androidx.emoji2.widget.EmojiEditText
+        android:id="@+id/editText"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <androidx.emoji2.widget.EmojiEditText
+        android:id="@+id/editTextWithMaxCount"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:maxEmojiCount="5"/>
+
+</LinearLayout>
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EditTextAttributeHelper.java b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EditTextAttributeHelper.java
similarity index 79%
rename from emoji2/emoji2/src/main/java/androidx/emoji2/widget/EditTextAttributeHelper.java
rename to emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EditTextAttributeHelper.java
index 7157c64..1fee3e1 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EditTextAttributeHelper.java
+++ b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EditTextAttributeHelper.java
@@ -16,7 +16,7 @@
 
 package androidx.emoji2.widget;
 
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 
 import android.content.Context;
 import android.content.res.TypedArray;
@@ -24,26 +24,27 @@
 import android.view.View;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
-import androidx.emoji2.R;
+import androidx.emoji2.text.EmojiDefaults;
 
 /**
  * Helper class to parse EmojiCompat EditText attributes.
  *
  * @hide
  */
-@RestrictTo(LIBRARY_GROUP_PREFIX)
+@RestrictTo(LIBRARY)
 public class EditTextAttributeHelper {
-    static final int MAX_EMOJI_COUNT = Integer.MAX_VALUE;
     private int mMaxEmojiCount;
 
-    public EditTextAttributeHelper(@NonNull View view, AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
+    public EditTextAttributeHelper(@NonNull View view, @Nullable AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
         if (attrs != null) {
             final Context context = view.getContext();
             TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.EmojiEditText,
                     defStyleAttr, defStyleRes);
-            mMaxEmojiCount = a.getInteger(R.styleable.EmojiEditText_maxEmojiCount, MAX_EMOJI_COUNT);
+            mMaxEmojiCount = a.getInteger(R.styleable.EmojiEditText_maxEmojiCount,
+                    EmojiDefaults.MAX_EMOJI_COUNT);
             a.recycle();
         }
     }
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiButton.java b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiButton.java
similarity index 77%
rename from emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiButton.java
rename to emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiButton.java
index 3fb4089..1b20ab5 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiButton.java
+++ b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiButton.java
@@ -15,6 +15,7 @@
  */
 package androidx.emoji2.widget;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.os.Build;
 import android.text.InputFilter;
@@ -22,8 +23,11 @@
 import android.view.ActionMode;
 import android.widget.Button;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.core.widget.TextViewCompat;
+import androidx.emoji2.helpers.EmojiTextViewHelper;
 
 /**
  * Button widget enhanced with emoji capability by using {@link EmojiTextViewHelper}. When used
@@ -38,23 +42,25 @@
      */
     private boolean mInitialized;
 
-    public EmojiButton(Context context) {
+    public EmojiButton(@NonNull Context context) {
         super(context);
         init();
     }
 
-    public EmojiButton(Context context, AttributeSet attrs) {
+    public EmojiButton(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
         init();
     }
 
-    public EmojiButton(Context context, AttributeSet attrs, int defStyleAttr) {
+    public EmojiButton(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         init();
     }
 
+    @SuppressLint("UnsafeNewApiCall")
     @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
-    public EmojiButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public EmojiButton(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         init();
     }
@@ -67,7 +73,7 @@
     }
 
     @Override
-    public void setFilters(InputFilter[] filters) {
+    public void setFilters(@NonNull InputFilter[] filters) {
         super.setFilters(getEmojiTextViewHelper().getFilters(filters));
     }
 
@@ -89,7 +95,9 @@
      * {@link TextViewCompat#setCustomSelectionActionModeCallback(TextView, ActionMode.Callback)}
      */
     @Override
-    public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
+    public void setCustomSelectionActionModeCallback(
+            @NonNull ActionMode.Callback actionModeCallback
+    ) {
         super.setCustomSelectionActionModeCallback(TextViewCompat
                 .wrapCustomSelectionActionModeCallback(this, actionModeCallback));
     }
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiEditText.java b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiEditText.java
similarity index 85%
rename from emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiEditText.java
rename to emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiEditText.java
index a97688b..1dae701 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiEditText.java
+++ b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiEditText.java
@@ -15,6 +15,7 @@
  */
 package androidx.emoji2.widget;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.os.Build;
 import android.text.method.KeyListener;
@@ -25,9 +26,11 @@
 import android.widget.EditText;
 
 import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.core.widget.TextViewCompat;
+import androidx.emoji2.helpers.EmojiEditTextHelper;
 import androidx.emoji2.text.EmojiCompat;
 
 /**
@@ -45,23 +48,25 @@
      */
     private boolean mInitialized;
 
-    public EmojiEditText(Context context) {
+    public EmojiEditText(@NonNull Context context) {
         super(context);
         init(null /*attrs*/, 0 /*defStyleAttr*/, 0 /*defStyleRes*/);
     }
 
-    public EmojiEditText(Context context, AttributeSet attrs) {
+    public EmojiEditText(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
         init(attrs, android.R.attr.editTextStyle, 0 /*defStyleRes*/);
     }
 
-    public EmojiEditText(Context context, AttributeSet attrs, int defStyleAttr) {
+    public EmojiEditText(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         init(attrs, defStyleAttr, 0 /*defStyleRes*/);
     }
 
+    @SuppressLint("UnsafeNewApiCall")
     @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
-    public EmojiEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public EmojiEditText(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         init(attrs, defStyleAttr, defStyleRes);
     }
@@ -84,8 +89,9 @@
         super.setKeyListener(keyListener);
     }
 
+    @Nullable
     @Override
-    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+    public InputConnection onCreateInputConnection(@NonNull EditorInfo outAttrs) {
         final InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
         return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs);
     }
@@ -130,7 +136,9 @@
      * {@link TextViewCompat#setCustomSelectionActionModeCallback(TextView, ActionMode.Callback)}
      */
     @Override
-    public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
+    public void setCustomSelectionActionModeCallback(
+            @NonNull ActionMode.Callback actionModeCallback
+    ) {
         super.setCustomSelectionActionModeCallback(TextViewCompat
                 .wrapCustomSelectionActionModeCallback(this, actionModeCallback));
     }
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java
similarity index 87%
rename from emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java
rename to emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java
index 288d3d9..95df225 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java
+++ b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java
@@ -18,6 +18,7 @@
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.inputmethodservice.ExtractEditText;
 import android.os.Build;
@@ -29,10 +30,12 @@
 import android.widget.TextView;
 
 import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.core.widget.TextViewCompat;
+import androidx.emoji2.helpers.EmojiEditTextHelper;
 import androidx.emoji2.text.EmojiCompat;
 import androidx.emoji2.text.EmojiSpan;
 
@@ -53,24 +56,26 @@
      */
     private boolean mInitialized;
 
-    public EmojiExtractEditText(Context context) {
+    public EmojiExtractEditText(@NonNull Context context) {
         super(context);
         init(null /*attrs*/, 0 /*defStyleAttr*/, 0 /*defStyleRes*/);
     }
 
-    public EmojiExtractEditText(Context context, AttributeSet attrs) {
+    public EmojiExtractEditText(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
         init(attrs, android.R.attr.editTextStyle, 0 /*defStyleRes*/);
     }
 
-    public EmojiExtractEditText(Context context, AttributeSet attrs, int defStyleAttr) {
+    public EmojiExtractEditText(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         init(attrs, defStyleAttr, 0 /*defStyleRes*/);
     }
 
+    @SuppressLint("UnsafeNewApiCall")
     @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
-    public EmojiExtractEditText(Context context, AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
+    public EmojiExtractEditText(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         init(attrs, defStyleAttr, defStyleRes);
     }
@@ -93,8 +98,9 @@
         super.setKeyListener(keyListener);
     }
 
+    @Nullable
     @Override
-    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+    public InputConnection onCreateInputConnection(@NonNull EditorInfo outAttrs) {
         final InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
         return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs);
     }
@@ -158,7 +164,9 @@
      * {@link TextViewCompat#setCustomSelectionActionModeCallback(TextView, ActionMode.Callback)}
      */
     @Override
-    public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
+    public void setCustomSelectionActionModeCallback(
+            @NonNull ActionMode.Callback actionModeCallback
+    ) {
         super.setCustomSelectionActionModeCallback(TextViewCompat
                 .wrapCustomSelectionActionModeCallback(this, actionModeCallback));
     }
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiExtractTextLayout.java b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiExtractTextLayout.java
similarity index 94%
rename from emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiExtractTextLayout.java
rename to emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiExtractTextLayout.java
index ba476e1..c930389 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiExtractTextLayout.java
+++ b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiExtractTextLayout.java
@@ -16,6 +16,7 @@
 
 package androidx.emoji2.widget;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.inputmethodservice.InputMethodService;
@@ -33,7 +34,6 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.core.view.ViewCompat;
-import androidx.emoji2.R;
 import androidx.emoji2.text.EmojiCompat;
 import androidx.emoji2.text.EmojiSpan;
 
@@ -76,25 +76,26 @@
      */
     private boolean mInitialized;
 
-    public EmojiExtractTextLayout(Context context) {
+    public EmojiExtractTextLayout(@NonNull Context context) {
         super(context);
         init(context, null /*attrs*/, 0 /*defStyleAttr*/, 0 /*defStyleRes*/);
     }
 
-    public EmojiExtractTextLayout(Context context,
+    public EmojiExtractTextLayout(@NonNull Context context,
             @Nullable AttributeSet attrs) {
         super(context, attrs);
         init(context, attrs, 0 /*defStyleAttr*/, 0 /*defStyleRes*/);
     }
 
-    public EmojiExtractTextLayout(Context context,
+    public EmojiExtractTextLayout(@NonNull Context context,
             @Nullable AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         init(context, attrs, defStyleAttr, 0 /*defStyleRes*/);
     }
 
+    @SuppressLint("UnsafeNewApiCall")
     @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
-    public EmojiExtractTextLayout(Context context, AttributeSet attrs,
+    public EmojiExtractTextLayout(@NonNull Context context, @Nullable AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         init(context, attrs, defStyleAttr, defStyleRes);
@@ -160,7 +161,8 @@
      * {@link InputMethodService#onUpdateExtractingViews(EditorInfo)
      * InputMethodService#onUpdateExtractingViews(EditorInfo)}.
      */
-    public void onUpdateExtractingViews(InputMethodService inputMethodService, EditorInfo ei) {
+    public void onUpdateExtractingViews(@NonNull InputMethodService inputMethodService,
+            @NonNull EditorInfo ei) {
         // the following code is ported as it is from InputMethodService.onUpdateExtractingViews
         if (!inputMethodService.isExtractViewShown()) {
             return;
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiTextView.java b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiTextView.java
similarity index 77%
rename from emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiTextView.java
rename to emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiTextView.java
index a9a7492..709ddd3 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiTextView.java
+++ b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/EmojiTextView.java
@@ -15,6 +15,7 @@
  */
 package androidx.emoji2.widget;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.os.Build;
 import android.text.InputFilter;
@@ -22,8 +23,11 @@
 import android.view.ActionMode;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.core.widget.TextViewCompat;
+import androidx.emoji2.helpers.EmojiTextViewHelper;
 
 /**
  * TextView widget enhanced with emoji capability by using {@link EmojiTextViewHelper}. When used
@@ -38,23 +42,25 @@
      */
     private boolean mInitialized;
 
-    public EmojiTextView(Context context) {
+    public EmojiTextView(@NonNull Context context) {
         super(context);
         init();
     }
 
-    public EmojiTextView(Context context, AttributeSet attrs) {
+    public EmojiTextView(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
         init();
     }
 
-    public EmojiTextView(Context context, AttributeSet attrs, int defStyleAttr) {
+    public EmojiTextView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         init();
     }
 
+    @SuppressLint("UnsafeNewApiCall")
     @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
-    public EmojiTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+    public EmojiTextView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         init();
     }
@@ -67,7 +73,7 @@
     }
 
     @Override
-    public void setFilters(InputFilter[] filters) {
+    public void setFilters(@NonNull InputFilter[] filters) {
         super.setFilters(getEmojiTextViewHelper().getFilters(filters));
     }
 
@@ -89,7 +95,9 @@
      * {@link TextViewCompat#setCustomSelectionActionModeCallback(TextView, ActionMode.Callback)}
      */
     @Override
-    public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
+    public void setCustomSelectionActionModeCallback(
+            @NonNull ActionMode.Callback actionModeCallback
+    ) {
         super.setCustomSelectionActionModeCallback(TextViewCompat
                 .wrapCustomSelectionActionModeCallback(this, actionModeCallback));
     }
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/ExtractButtonCompat.java b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/ExtractButtonCompat.java
similarity index 72%
rename from emoji2/emoji2/src/main/java/androidx/emoji2/widget/ExtractButtonCompat.java
rename to emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/ExtractButtonCompat.java
index 26070ab..cf839e0 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/ExtractButtonCompat.java
+++ b/emoji2/emoji2-views/src/main/java/androidx/emoji2/widget/ExtractButtonCompat.java
@@ -18,12 +18,15 @@
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.os.Build;
 import android.util.AttributeSet;
 import android.view.ActionMode;
 import android.widget.Button;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.core.widget.TextViewCompat;
@@ -35,21 +38,23 @@
  */
 @RestrictTo(LIBRARY_GROUP_PREFIX)
 public class ExtractButtonCompat extends Button {
-    public ExtractButtonCompat(Context context) {
+    public ExtractButtonCompat(@NonNull Context context) {
         super(context, null);
     }
 
-    public ExtractButtonCompat(Context context, AttributeSet attrs) {
+    public ExtractButtonCompat(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
     }
 
-    public ExtractButtonCompat(Context context, AttributeSet attrs, int defStyleAttr) {
+    public ExtractButtonCompat(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr) {
         super(context, attrs, defStyleAttr);
     }
 
+    @SuppressLint("UnsafeNewApiCall")
     @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
-    public ExtractButtonCompat(Context context, AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
+    public ExtractButtonCompat(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
     }
 
@@ -59,7 +64,7 @@
      */
     @Override
     public boolean hasWindowFocus() {
-        return isEnabled() && getVisibility() == VISIBLE ? true : false;
+        return isEnabled() && getVisibility() == VISIBLE;
     }
 
     /**
@@ -67,7 +72,9 @@
      * {@link TextViewCompat#setCustomSelectionActionModeCallback(TextView, ActionMode.Callback)}
      */
     @Override
-    public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {
+    public void setCustomSelectionActionModeCallback(
+            @NonNull ActionMode.Callback actionModeCallback
+    ) {
         super.setCustomSelectionActionModeCallback(TextViewCompat
                 .wrapCustomSelectionActionModeCallback(this, actionModeCallback));
     }
diff --git a/emoji2/emoji2/src/main/res-public/values/public_attrs.xml b/emoji2/emoji2-views/src/main/res-public/values/public_attrs.xml
similarity index 100%
rename from emoji2/emoji2/src/main/res-public/values/public_attrs.xml
rename to emoji2/emoji2-views/src/main/res-public/values/public_attrs.xml
diff --git a/emoji2/emoji2/src/main/res/layout/input_method_extract_view.xml b/emoji2/emoji2-views/src/main/res/layout/input_method_extract_view.xml
similarity index 62%
rename from emoji2/emoji2/src/main/res/layout/input_method_extract_view.xml
rename to emoji2/emoji2-views/src/main/res/layout/input_method_extract_view.xml
index 0a4d9b0..c7f18b8 100644
--- a/emoji2/emoji2/src/main/res/layout/input_method_extract_view.xml
+++ b/emoji2/emoji2-views/src/main/res/layout/input_method_extract_view.xml
@@ -1,18 +1,18 @@
 <?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.
+  Copyright 2021 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.
   -->
 
 <merge
diff --git a/emoji2/emoji2/src/main/res/values/attrs.xml b/emoji2/emoji2-views/src/main/res/values/attrs.xml
similarity index 100%
rename from emoji2/emoji2/src/main/res/values/attrs.xml
rename to emoji2/emoji2-views/src/main/res/values/attrs.xml
diff --git a/emoji2/emoji2/build.gradle b/emoji2/emoji2/build.gradle
index ec4a8ea..b85383f 100644
--- a/emoji2/emoji2/build.gradle
+++ b/emoji2/emoji2/build.gradle
@@ -43,7 +43,6 @@
         main {
             // We use a non-standard manifest path.
             manifest.srcFile 'AndroidManifest.xml'
-            res.srcDirs += 'src/main/res-public'
             resources {
                 srcDirs += [fontDir.getAbsolutePath()]
                 includes += ["LICENSE_UNICODE", "LICENSE_OFL"]
diff --git a/emoji2/emoji2/lint-baseline.xml b/emoji2/emoji2/lint-baseline.xml
deleted file mode 100644
index d6d91ea..0000000
--- a/emoji2/emoji2/lint-baseline.xml
+++ /dev/null
@@ -1,1416 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.2.0-beta04" client="gradle" variant="debug" version="4.2.0-beta04">
-
-    <issue
-        id="PrivateConstructorForUtilityClass"
-        message="Utility class with non private constructor"
-        errorLine1="    private static final class CodepointIndexFinder {"
-        errorLine2="                               ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiProcessor.java"
-            line="654"
-            column="32"/>
-    </issue>
-
-    <issue
-        id="UnsafeNewApiCall"
-        message="This call is to a method from API 21, the call containing class androidx.emoji2.widget.EmojiButton is not annotated with @RequiresApi(x) where x is at least 21. Either annotate the containing class with at least @RequiresApi(21) or move the call to a static method in a wrapper class annotated with at least @RequiresApi(21)."
-        errorLine1="        super(context, attrs, defStyleAttr, defStyleRes);"
-        errorLine2="        ~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiButton.java"
-            line="58"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="UnsafeNewApiCall"
-        message="This call is to a method from API 21, the call containing class androidx.emoji2.widget.EmojiEditText is not annotated with @RequiresApi(x) where x is at least 21. Either annotate the containing class with at least @RequiresApi(21) or move the call to a static method in a wrapper class annotated with at least @RequiresApi(21)."
-        errorLine1="        super(context, attrs, defStyleAttr, defStyleRes);"
-        errorLine2="        ~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiEditText.java"
-            line="65"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="UnsafeNewApiCall"
-        message="This call is to a method from API 21, the call containing class androidx.emoji2.widget.EmojiExtractEditText is not annotated with @RequiresApi(x) where x is at least 21. Either annotate the containing class with at least @RequiresApi(21) or move the call to a static method in a wrapper class annotated with at least @RequiresApi(21)."
-        errorLine1="        super(context, attrs, defStyleAttr, defStyleRes);"
-        errorLine2="        ~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java"
-            line="74"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="UnsafeNewApiCall"
-        message="This call is to a method from API 21, the call containing class androidx.emoji2.widget.EmojiExtractTextLayout is not annotated with @RequiresApi(x) where x is at least 21. Either annotate the containing class with at least @RequiresApi(21) or move the call to a static method in a wrapper class annotated with at least @RequiresApi(21)."
-        errorLine1="        super(context, attrs, defStyleAttr, defStyleRes);"
-        errorLine2="        ~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractTextLayout.java"
-            line="99"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="UnsafeNewApiCall"
-        message="This call is to a method from API 19, the call containing class androidx.emoji2.widget.EmojiInputFilter.InitCallbackImpl is not annotated with @RequiresApi(x) where x is at least 19. Either annotate the containing class with at least @RequiresApi(19) or move the call to a static method in a wrapper class annotated with at least @RequiresApi(19)."
-        errorLine1="            if (textView != null &amp;&amp; textView.isAttachedToWindow()) {"
-        errorLine2="                                             ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiInputFilter.java"
-            line="110"
-            column="46"/>
-    </issue>
-
-    <issue
-        id="UnsafeNewApiCall"
-        message="This call is to a method from API 19, the call containing class androidx.emoji2.text.EmojiProcessor.CodepointIndexFinder is not annotated with @RequiresApi(x) where x is at least 19. Either annotate the containing class with at least @RequiresApi(19) or move the call to a static method in a wrapper class annotated with at least @RequiresApi(19)."
-        errorLine1="                if (!Character.isSurrogate(c)) {"
-        errorLine2="                               ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiProcessor.java"
-            line="702"
-            column="32"/>
-    </issue>
-
-    <issue
-        id="UnsafeNewApiCall"
-        message="This call is to a method from API 19, the call containing class androidx.emoji2.text.EmojiProcessor.CodepointIndexFinder is not annotated with @RequiresApi(x) where x is at least 19. Either annotate the containing class with at least @RequiresApi(19) or move the call to a static method in a wrapper class annotated with at least @RequiresApi(19)."
-        errorLine1="                if (!Character.isSurrogate(c)) {"
-        errorLine2="                               ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiProcessor.java"
-            line="759"
-            column="32"/>
-    </issue>
-
-    <issue
-        id="UnsafeNewApiCall"
-        message="This call is to a method from API 21, the call containing class androidx.emoji2.widget.EmojiTextView is not annotated with @RequiresApi(x) where x is at least 21. Either annotate the containing class with at least @RequiresApi(21) or move the call to a static method in a wrapper class annotated with at least @RequiresApi(21)."
-        errorLine1="        super(context, attrs, defStyleAttr, defStyleRes);"
-        errorLine2="        ~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiTextView.java"
-            line="58"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="UnsafeNewApiCall"
-        message="This call is to a method from API 19, the call containing class androidx.emoji2.widget.EmojiTextWatcher.InitCallbackImpl is not annotated with @RequiresApi(x) where x is at least 19. Either annotate the containing class with at least @RequiresApi(19) or move the call to a static method in a wrapper class annotated with at least @RequiresApi(19)."
-        errorLine1="            if (editText != null &amp;&amp; editText.isAttachedToWindow()) {"
-        errorLine2="                                             ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiTextWatcher.java"
-            line="121"
-            column="46"/>
-    </issue>
-
-    <issue
-        id="UnsafeNewApiCall"
-        message="This call is to a method from API 21, the call containing class androidx.emoji2.widget.ExtractButtonCompat is not annotated with @RequiresApi(x) where x is at least 21. Either annotate the containing class with at least @RequiresApi(21) or move the call to a static method in a wrapper class annotated with at least @RequiresApi(21)."
-        errorLine1="        super(context, attrs, defStyleAttr, defStyleRes);"
-        errorLine2="        ~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/ExtractButtonCompat.java"
-            line="53"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="KotlinPropertyAccess"
-        message="The getter return type (`int`) and setter parameter type (`boolean`) getter and setter methods for property `hasGlyph` should have exactly the same type to allow be accessed as a property from Kotlin; see https://android.github.io/kotlin-guides/interop.html#property-prefixes"
-        errorLine1="    public int getHasGlyph() {"
-        errorLine2="               ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiMetadata.java"
-            line="184"
-            column="16"/>
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiMetadata.java"
-            line="193"
-            column="17"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EditTextAttributeHelper(@NonNull View view, AttributeSet attrs, int defStyleAttr,"
-        errorLine2="                                                       ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EditTextAttributeHelper.java"
-            line="40"
-            column="56"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiButton(Context context) {"
-        errorLine2="                       ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiButton.java"
-            line="41"
-            column="24"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiButton(Context context, AttributeSet attrs) {"
-        errorLine2="                       ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiButton.java"
-            line="46"
-            column="24"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiButton(Context context, AttributeSet attrs) {"
-        errorLine2="                                        ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiButton.java"
-            line="46"
-            column="41"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiButton(Context context, AttributeSet attrs, int defStyleAttr) {"
-        errorLine2="                       ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiButton.java"
-            line="51"
-            column="24"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiButton(Context context, AttributeSet attrs, int defStyleAttr) {"
-        errorLine2="                                        ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiButton.java"
-            line="51"
-            column="41"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {"
-        errorLine2="                       ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiButton.java"
-            line="57"
-            column="24"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {"
-        errorLine2="                                        ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiButton.java"
-            line="57"
-            column="41"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public void setFilters(InputFilter[] filters) {"
-        errorLine2="                           ~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiButton.java"
-            line="70"
-            column="28"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {"
-        errorLine2="                                                     ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiButton.java"
-            line="92"
-            column="54"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public static EmojiCompat init(@NonNull final Config config) {"
-        errorLine2="                  ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="302"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public static EmojiCompat reset(@NonNull final Config config) {"
-        errorLine2="                  ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="322"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public static EmojiCompat reset(final EmojiCompat emojiCompat) {"
-        errorLine2="                  ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="337"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public static EmojiCompat reset(final EmojiCompat emojiCompat) {"
-        errorLine2="                                          ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="337"
-            column="43"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public static EmojiCompat get() {"
-        errorLine2="                  ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="352"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="            final KeyEvent event) {"
-        errorLine2="                  ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="541"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public CharSequence process(@NonNull final CharSequence charSequence) {"
-        errorLine2="           ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="625"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public CharSequence process(@NonNull final CharSequence charSequence,"
-        errorLine2="           ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="662"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public CharSequence process(@NonNull final CharSequence charSequence,"
-        errorLine2="           ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="698"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public CharSequence process(@NonNull final CharSequence charSequence,"
-        errorLine2="           ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="739"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="        public Config registerInitCallback(@NonNull InitCallback initCallback) {"
-        errorLine2="               ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="982"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="        public Config unregisterInitCallback(@NonNull InitCallback initCallback) {"
-        errorLine2="               ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="1000"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="        public Config setReplaceAll(final boolean replaceAll) {"
-        errorLine2="               ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="1017"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="        public Config setUseEmojiAsDefaultStyle(final boolean useEmojiAsDefaultStyle) {"
-        errorLine2="               ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="1037"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="        public Config setUseEmojiAsDefaultStyle(final boolean useEmojiAsDefaultStyle,"
-        errorLine2="               ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="1057"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="        public Config setEmojiSpanIndicatorEnabled(boolean emojiSpanIndicatorEnabled) {"
-        errorLine2="               ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="1081"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="        public Config setEmojiSpanIndicatorColor(@ColorInt int color) {"
-        errorLine2="               ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="1092"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="        public Config setMetadataLoadStrategy(@LoadStrategy int strategy) {"
-        errorLine2="               ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="1133"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="        protected final MetadataRepoLoader getMetadataRepoLoader() {"
-        errorLine2="                        ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiCompat.java"
-            line="1154"
-            column="25"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiEditText(Context context) {"
-        errorLine2="                         ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiEditText.java"
-            line="48"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiEditText(Context context, AttributeSet attrs) {"
-        errorLine2="                         ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiEditText.java"
-            line="53"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiEditText(Context context, AttributeSet attrs) {"
-        errorLine2="                                          ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiEditText.java"
-            line="53"
-            column="43"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiEditText(Context context, AttributeSet attrs, int defStyleAttr) {"
-        errorLine2="                         ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiEditText.java"
-            line="58"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiEditText(Context context, AttributeSet attrs, int defStyleAttr) {"
-        errorLine2="                                          ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiEditText.java"
-            line="58"
-            column="43"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {"
-        errorLine2="                         ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiEditText.java"
-            line="64"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiEditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {"
-        errorLine2="                                          ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiEditText.java"
-            line="64"
-            column="43"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {"
-        errorLine2="           ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiEditText.java"
-            line="88"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {"
-        errorLine2="                                                   ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiEditText.java"
-            line="88"
-            column="52"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {"
-        errorLine2="                                                     ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiEditText.java"
-            line="133"
-            column="54"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiExtractEditText(Context context) {"
-        errorLine2="                                ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java"
-            line="56"
-            column="33"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiExtractEditText(Context context, AttributeSet attrs) {"
-        errorLine2="                                ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java"
-            line="61"
-            column="33"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiExtractEditText(Context context, AttributeSet attrs) {"
-        errorLine2="                                                 ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java"
-            line="61"
-            column="50"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiExtractEditText(Context context, AttributeSet attrs, int defStyleAttr) {"
-        errorLine2="                                ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java"
-            line="66"
-            column="33"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiExtractEditText(Context context, AttributeSet attrs, int defStyleAttr) {"
-        errorLine2="                                                 ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java"
-            line="66"
-            column="50"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiExtractEditText(Context context, AttributeSet attrs, int defStyleAttr,"
-        errorLine2="                                ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java"
-            line="72"
-            column="33"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiExtractEditText(Context context, AttributeSet attrs, int defStyleAttr,"
-        errorLine2="                                                 ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java"
-            line="72"
-            column="50"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {"
-        errorLine2="           ~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java"
-            line="97"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {"
-        errorLine2="                                                   ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java"
-            line="97"
-            column="52"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {"
-        errorLine2="                                                     ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractEditText.java"
-            line="161"
-            column="54"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiExtractTextLayout(Context context) {"
-        errorLine2="                                  ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractTextLayout.java"
-            line="79"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiExtractTextLayout(Context context,"
-        errorLine2="                                  ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractTextLayout.java"
-            line="84"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiExtractTextLayout(Context context,"
-        errorLine2="                                  ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractTextLayout.java"
-            line="90"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiExtractTextLayout(Context context, AttributeSet attrs,"
-        errorLine2="                                  ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractTextLayout.java"
-            line="97"
-            column="35"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiExtractTextLayout(Context context, AttributeSet attrs,"
-        errorLine2="                                                   ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractTextLayout.java"
-            line="97"
-            column="52"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public void onUpdateExtractingViews(InputMethodService inputMethodService, EditorInfo ei) {"
-        errorLine2="                                        ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractTextLayout.java"
-            line="163"
-            column="41"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public void onUpdateExtractingViews(InputMethodService inputMethodService, EditorInfo ei) {"
-        errorLine2="                                                                               ~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiExtractTextLayout.java"
-            line="163"
-            column="80"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public Typeface getTypeface() {"
-        errorLine2="           ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiMetadata.java"
-            line="120"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public int getSize(@NonNull final Paint paint, final CharSequence text, final int start,"
-        errorLine2="                                                         ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiSpan.java"
-            line="77"
-            column="58"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="            final int end, final Paint.FontMetricsInt fm) {"
-        errorLine2="                                 ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/EmojiSpan.java"
-            line="78"
-            column="34"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiTextView(Context context) {"
-        errorLine2="                         ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiTextView.java"
-            line="41"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiTextView(Context context, AttributeSet attrs) {"
-        errorLine2="                         ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiTextView.java"
-            line="46"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiTextView(Context context, AttributeSet attrs) {"
-        errorLine2="                                          ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiTextView.java"
-            line="46"
-            column="43"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiTextView(Context context, AttributeSet attrs, int defStyleAttr) {"
-        errorLine2="                         ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiTextView.java"
-            line="51"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiTextView(Context context, AttributeSet attrs, int defStyleAttr) {"
-        errorLine2="                                          ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiTextView.java"
-            line="51"
-            column="43"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {"
-        errorLine2="                         ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiTextView.java"
-            line="57"
-            column="26"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public EmojiTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {"
-        errorLine2="                                          ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiTextView.java"
-            line="57"
-            column="43"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public void setFilters(InputFilter[] filters) {"
-        errorLine2="                           ~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiTextView.java"
-            line="70"
-            column="28"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {"
-        errorLine2="                                                     ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/EmojiTextView.java"
-            line="92"
-            column="54"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public ExtractButtonCompat(Context context) {"
-        errorLine2="                               ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/ExtractButtonCompat.java"
-            line="38"
-            column="32"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public ExtractButtonCompat(Context context, AttributeSet attrs) {"
-        errorLine2="                               ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/ExtractButtonCompat.java"
-            line="42"
-            column="32"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public ExtractButtonCompat(Context context, AttributeSet attrs) {"
-        errorLine2="                                                ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/ExtractButtonCompat.java"
-            line="42"
-            column="49"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public ExtractButtonCompat(Context context, AttributeSet attrs, int defStyleAttr) {"
-        errorLine2="                               ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/ExtractButtonCompat.java"
-            line="46"
-            column="32"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public ExtractButtonCompat(Context context, AttributeSet attrs, int defStyleAttr) {"
-        errorLine2="                                                ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/ExtractButtonCompat.java"
-            line="46"
-            column="49"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public ExtractButtonCompat(Context context, AttributeSet attrs, int defStyleAttr,"
-        errorLine2="                               ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/ExtractButtonCompat.java"
-            line="51"
-            column="32"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public ExtractButtonCompat(Context context, AttributeSet attrs, int defStyleAttr,"
-        errorLine2="                                                ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/ExtractButtonCompat.java"
-            line="51"
-            column="49"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public void setCustomSelectionActionModeCallback(ActionMode.Callback actionModeCallback) {"
-        errorLine2="                                                     ~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/ExtractButtonCompat.java"
-            line="70"
-            column="54"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public FontRequestEmojiCompatConfig setHandler(Handler handler) {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java"
-            line="143"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public FontRequestEmojiCompatConfig setHandler(Handler handler) {"
-        errorLine2="                                                   ~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java"
-            line="143"
-            column="52"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public FontRequestEmojiCompatConfig setRetryPolicy(RetryPolicy policy) {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java"
-            line="156"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public FontRequestEmojiCompatConfig setRetryPolicy(RetryPolicy policy) {"
-        errorLine2="                                                       ~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java"
-            line="156"
-            column="56"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="        public FontFamilyResult fetchFonts(@NonNull Context context,"
-        errorLine2="               ~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java"
-            line="335"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="        public Typeface buildTypeface(@NonNull Context context,"
-        errorLine2="               ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java"
-            line="341"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public static MetadataRepo create(@NonNull final Typeface typeface,"
-        errorLine2="                  ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/MetadataRepo.java"
-            line="103"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public static MetadataRepo create(@NonNull final Typeface typeface,"
-        errorLine2="                  ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/MetadataRepo.java"
-            line="115"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public static MetadataRepo create(@NonNull final AssetManager assetManager,"
-        errorLine2="                  ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/MetadataRepo.java"
-            line="127"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="            final String assetPath) throws IOException {"
-        errorLine2="                  ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/MetadataRepo.java"
-            line="128"
-            column="19"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public char[] getEmojiCharArray() {"
-        errorLine2="           ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/MetadataRepo.java"
-            line="176"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public MetadataList getMetadataList() {"
-        errorLine2="           ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/MetadataRepo.java"
-            line="184"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public CharSequence subSequence(int start, int end) {"
-        errorLine2="           ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="124"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public void setSpan(Object what, int start, int end, int flags) {"
-        errorLine2="                        ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="134"
-            column="25"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public &lt;T> T[] getSpans(int queryStart, int queryEnd, Class&lt;T> kind) {"
-        errorLine2="               ~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="149"
-            column="16"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public &lt;T> T[] getSpans(int queryStart, int queryEnd, Class&lt;T> kind) {"
-        errorLine2="                                                          ~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="149"
-            column="59"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public void removeSpan(Object what) {"
-        errorLine2="                           ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="167"
-            column="28"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public int getSpanStart(Object tag) {"
-        errorLine2="                            ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="189"
-            column="29"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public int getSpanEnd(Object tag) {"
-        errorLine2="                          ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="203"
-            column="27"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public int getSpanFlags(Object tag) {"
-        errorLine2="                            ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="217"
-            column="29"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public int nextSpanTransition(int start, int limit, Class type) {"
-        errorLine2="                                                        ~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="231"
-            column="57"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder replace(int start, int end, CharSequence tb) {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="301"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder replace(int start, int end, CharSequence tb) {"
-        errorLine2="                                                              ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="301"
-            column="63"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder replace(int start, int end, CharSequence tb, int tbstart,"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="309"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder replace(int start, int end, CharSequence tb, int tbstart,"
-        errorLine2="                                                              ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="309"
-            column="63"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder insert(int where, CharSequence tb) {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="318"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder insert(int where, CharSequence tb) {"
-        errorLine2="                                                    ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="318"
-            column="53"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder insert(int where, CharSequence tb, int start, int end) {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="324"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder insert(int where, CharSequence tb, int start, int end) {"
-        errorLine2="                                                    ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="324"
-            column="53"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder delete(int start, int end) {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="330"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder append(CharSequence text) {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="336"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder append(CharSequence text) {"
-        errorLine2="                                         ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="336"
-            column="42"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder append(char text) {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="342"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder append(CharSequence text, int start, int end) {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="348"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder append(CharSequence text, int start, int end) {"
-        errorLine2="                                         ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="348"
-            column="42"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder append(CharSequence text, Object what, int flags) {"
-        errorLine2="           ~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="354"
-            column="12"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder append(CharSequence text, Object what, int flags) {"
-        errorLine2="                                         ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="354"
-            column="42"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public SpannableStringBuilder append(CharSequence text, Object what, int flags) {"
-        errorLine2="                                                            ~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/widget/SpannableBuilder.java"
-            line="354"
-            column="61"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public TypefaceEmojiSpan(final EmojiMetadata metadata) {"
-        errorLine2="                                   ~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/TypefaceEmojiSpan.java"
-            line="48"
-            column="36"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
-        errorLine1="    public void draw(@NonNull final Canvas canvas, final CharSequence text,"
-        errorLine2="                                                         ~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/emoji2/text/TypefaceEmojiSpan.java"
-            line="53"
-            column="58"/>
-    </issue>
-
-</issues>
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/MetadataRepoTest.java b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/MetadataRepoTest.java
index cead30d..3039f17 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/MetadataRepoTest.java
+++ b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/MetadataRepoTest.java
@@ -15,12 +15,16 @@
  */
 package androidx.emoji2.text;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+
+import android.graphics.Typeface;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
+import androidx.text.emoji.flatbuffer.MetadataList;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -35,7 +39,7 @@
 
     @Before
     public void clearResourceIndex() {
-        mMetadataRepo = new MetadataRepo();
+        mMetadataRepo = MetadataRepo.create(mock(Typeface.class), new MetadataList());
     }
 
     @Test(expected = NullPointerException.class)
@@ -63,10 +67,10 @@
         mMetadataRepo.put(metadata);
         assertSame(metadata, getNode(codePoint));
 
-        assertEquals(null, getNode(new int[]{1}));
-        assertEquals(null, getNode(new int[]{1, 2}));
-        assertEquals(null, getNode(new int[]{1, 2, 3}));
-        assertEquals(null, getNode(new int[]{1, 2, 3, 5}));
+        assertNull(getNode(new int[]{1}));
+        assertNull(getNode(new int[]{1, 2}));
+        assertNull(getNode(new int[]{1, 2, 3}));
+        assertNull(getNode(new int[]{1, 2, 3, 5}));
     }
 
     @Test
@@ -88,8 +92,8 @@
         assertSame(metadata2, getNode(codePoint2));
         assertSame(metadata3, getNode(codePoint3));
 
-        assertEquals(null, getNode(new int[]{1}));
-        assertEquals(null, getNode(new int[]{1, 2, 3, 4, 5}));
+        assertNull(getNode(new int[]{1}));
+        assertNull(getNode(new int[]{1, 2, 3, 4, 5}));
     }
 
     final EmojiMetadata getNode(final int[] codepoints) {
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/SpannableBuilderTest.java b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/SpannableBuilderTest.java
similarity index 98%
rename from emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/SpannableBuilderTest.java
rename to emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/SpannableBuilderTest.java
index 919ba54..bbbbe48 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/SpannableBuilderTest.java
+++ b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/SpannableBuilderTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.emoji2.widget;
+package androidx.emoji2.text;
 
 import static org.hamcrest.Matchers.arrayWithSize;
 import static org.hamcrest.Matchers.instanceOf;
@@ -39,7 +39,6 @@
 import android.text.TextWatcher;
 import android.text.style.QuoteSpan;
 
-import androidx.emoji2.text.EmojiSpan;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.MediumTest;
 
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/TestConfigBuilder.java b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/TestConfigBuilder.java
index 6753840..e44b5a4 100644
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/TestConfigBuilder.java
+++ b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/text/TestConfigBuilder.java
@@ -16,13 +16,16 @@
 package androidx.emoji2.text;
 
 import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
 
 import android.content.Context;
 import android.content.res.AssetManager;
+import android.graphics.Typeface;
 
 import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
 import androidx.test.core.app.ApplicationProvider;
+import androidx.text.emoji.flatbuffer.MetadataList;
 
 import java.util.concurrent.CountDownLatch;
 
@@ -85,7 +88,8 @@
                     try {
                         mLoaderLatch.await();
                         if (mSuccess) {
-                            loaderCallback.onLoaded(new MetadataRepo());
+                            loaderCallback.onLoaded(MetadataRepo.create(mock(Typeface.class),
+                                    new MetadataList()));
                         } else {
                             loaderCallback.onFailed(null);
                         }
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiInputConnectionTest.java b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiInputConnectionTest.java
deleted file mode 100644
index 11d580a..0000000
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiInputConnectionTest.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright 2021 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.emoji2.widget;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.Build;
-import android.text.Editable;
-import android.text.Selection;
-import android.text.SpannableStringBuilder;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputConnection;
-import android.widget.TextView;
-
-import androidx.emoji2.text.EmojiCompat;
-import androidx.emoji2.text.TestConfigBuilder;
-import androidx.emoji2.util.Emoji;
-import androidx.emoji2.util.EmojiMatcher;
-import androidx.emoji2.util.TestString;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.LargeTest;
-import androidx.test.filters.SdkSuppress;
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import org.hamcrest.MatcherAssert;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-@SdkSuppress(minSdkVersion = 19)
-public class EmojiInputConnectionTest {
-
-    private InputConnection mInputConnection;
-    private TestString mTestString;
-    private Editable mEditable;
-    private EmojiInputConnection mEmojiEmojiInputConnection;
-
-    @BeforeClass
-    public static void setupEmojiCompat() {
-        EmojiCompat.reset(TestConfigBuilder.config());
-    }
-
-    @Before
-    public void setup() {
-        mTestString = new TestString(Emoji.EMOJI_WITH_ZWJ).withPrefix().withSuffix();
-        mEditable = new SpannableStringBuilder(mTestString.toString());
-        mInputConnection = mock(InputConnection.class);
-        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        final TextView textView = spy(new TextView(context));
-        EmojiCompat.get().process(mEditable);
-        MatcherAssert.assertThat(mEditable, EmojiMatcher.hasEmoji());
-
-        doReturn(mEditable).when(textView).getEditableText();
-        when(mInputConnection.deleteSurroundingText(anyInt(), anyInt())).thenReturn(false);
-        setupDeleteSurroundingText();
-
-        mEmojiEmojiInputConnection = new EmojiInputConnection(textView, mInputConnection,
-                new EditorInfo());
-    }
-
-    private void setupDeleteSurroundingText() {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-            when(mInputConnection.deleteSurroundingTextInCodePoints(anyInt(), anyInt())).thenReturn(
-                    false);
-        }
-    }
-
-    @Test
-    public void testDeleteSurroundingText_doesNotDelete() {
-        Selection.setSelection(mEditable, 0, mEditable.length());
-        assertFalse(mEmojiEmojiInputConnection.deleteSurroundingText(1, 0));
-        verify(mInputConnection, times(1)).deleteSurroundingText(1, 0);
-    }
-
-    @Test
-    public void testDeleteSurroundingText_deletesEmojiBackward() {
-        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
-        assertTrue(mEmojiEmojiInputConnection.deleteSurroundingText(1, 0));
-        verify(mInputConnection, never()).deleteSurroundingText(anyInt(), anyInt());
-    }
-
-    @Test
-    public void testDeleteSurroundingText_doesNotDeleteEmojiIfSelectionAtStartIndex() {
-        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
-        assertFalse(mEmojiEmojiInputConnection.deleteSurroundingText(1, 0));
-        verify(mInputConnection, times(1)).deleteSurroundingText(1, 0);
-    }
-
-    @Test
-    public void testDeleteSurroundingText_deletesEmojiForward() {
-        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
-        assertTrue(mEmojiEmojiInputConnection.deleteSurroundingText(0, 1));
-        verify(mInputConnection, never()).deleteSurroundingText(anyInt(), anyInt());
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
-    @Test
-    public void testDeleteSurroundingTextInCodePoints_doesNotDelete() {
-        Selection.setSelection(mEditable, 0, mEditable.length());
-        assertFalse(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(1, 0));
-        verify(mInputConnection, times(1)).deleteSurroundingTextInCodePoints(1, 0);
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
-    @Test
-    public void testDeleteSurroundingTextInCodePoints_deletesEmojiBackward() {
-        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
-        assertTrue(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(1, 0));
-        verify(mInputConnection, never()).deleteSurroundingTextInCodePoints(anyInt(), anyInt());
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
-    @Test
-    public void testDeleteSurroundingTextInCodePoints_deletesEmojiForward() {
-        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
-        assertTrue(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(0, 1));
-        verify(mInputConnection, never()).deleteSurroundingTextInCodePoints(anyInt(), anyInt());
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
-    @Test
-    public void testDeleteSurroundingTextInCodePoints_doesNotDeleteEmojiIfSelectionAtStartIndex() {
-        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
-        assertFalse(mEmojiEmojiInputConnection.deleteSurroundingTextInCodePoints(1, 0));
-        verify(mInputConnection, times(1)).deleteSurroundingTextInCodePoints(1, 0);
-    }
-}
diff --git a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiKeyListenerTest.java b/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiKeyListenerTest.java
deleted file mode 100644
index 3bee8fe..0000000
--- a/emoji2/emoji2/src/androidTest/java/androidx/emoji2/widget/EmojiKeyListenerTest.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2021 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.emoji2.widget;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.same;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.text.Editable;
-import android.text.Selection;
-import android.text.SpannableStringBuilder;
-import android.text.method.KeyListener;
-import android.view.KeyEvent;
-import android.view.View;
-
-import androidx.emoji2.text.EmojiCompat;
-import androidx.emoji2.text.TestConfigBuilder;
-import androidx.emoji2.util.Emoji;
-import androidx.emoji2.util.EmojiMatcher;
-import androidx.emoji2.util.KeyboardUtil;
-import androidx.emoji2.util.TestString;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SdkSuppress;
-import androidx.test.filters.SmallTest;
-
-import org.hamcrest.MatcherAssert;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-@SdkSuppress(minSdkVersion = 19)
-public class EmojiKeyListenerTest {
-
-    private KeyListener mKeyListener;
-    private TestString mTestString;
-    private Editable mEditable;
-    private EmojiKeyListener mEmojiKeyListener;
-
-    @BeforeClass
-    public static void setupEmojiCompat() {
-        EmojiCompat.reset(TestConfigBuilder.config());
-    }
-
-    @Before
-    public void setup() {
-        mKeyListener = mock(KeyListener.class);
-        mTestString = new TestString(Emoji.EMOJI_WITH_ZWJ).withPrefix().withSuffix();
-        mEditable = new SpannableStringBuilder(mTestString.toString());
-        mEmojiKeyListener = new EmojiKeyListener(mKeyListener);
-        EmojiCompat.get().process(mEditable);
-        MatcherAssert.assertThat(mEditable, EmojiMatcher.hasEmoji());
-
-        when(mKeyListener.onKeyDown(any(View.class), any(Editable.class), anyInt(),
-                any(KeyEvent.class))).thenReturn(false);
-    }
-
-    @Test
-    public void testOnKeyDown_doesNotDelete_whenKeyCodeIsNotDelOrForwardDel() {
-        Selection.setSelection(mEditable, 0);
-        final KeyEvent event = KeyboardUtil.zero();
-        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
-        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
-                eq(event.getKeyCode()), same(event));
-    }
-
-    @Test
-    public void testOnKeyDown_doesNotDelete_withOtherModifiers() {
-        Selection.setSelection(mEditable, 0);
-        final KeyEvent event = KeyboardUtil.fnDel();
-        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
-        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
-                eq(event.getKeyCode()), same(event));
-    }
-
-    @Test
-    public void testOnKeyDown_doesNotDelete_withAltModifier() {
-        Selection.setSelection(mEditable, 0);
-        final KeyEvent event = KeyboardUtil.altDel();
-        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
-        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
-                eq(event.getKeyCode()), same(event));
-    }
-
-    @Test
-    public void testOnKeyDown_doesNotDelete_withCtrlModifier() {
-        Selection.setSelection(mEditable, 0);
-        final KeyEvent event = KeyboardUtil.ctrlDel();
-        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
-        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
-                eq(event.getKeyCode()), same(event));
-    }
-
-    @Test
-    public void testOnKeyDown_doesNotDelete_withShiftModifier() {
-        Selection.setSelection(mEditable, 0);
-        final KeyEvent event = KeyboardUtil.shiftDel();
-        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
-        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
-                eq(event.getKeyCode()), same(event));
-    }
-
-    @Test
-    public void testOnKeyDown_doesNotDelete_withSelection() {
-        Selection.setSelection(mEditable, 0, mEditable.length());
-        final KeyEvent event = KeyboardUtil.del();
-        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
-        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
-                eq(event.getKeyCode()), same(event));
-    }
-
-    @Test
-    public void testOnKeyDown_doesNotDelete_withoutEmojiSpans() {
-        Editable editable = new SpannableStringBuilder("abc");
-        Selection.setSelection(editable, 1);
-        final KeyEvent event = KeyboardUtil.del();
-        assertFalse(mEmojiKeyListener.onKeyDown(null, editable, event.getKeyCode(), event));
-        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(editable),
-                eq(event.getKeyCode()), same(event));
-    }
-
-    @Test
-    public void testOnKeyDown_doesNotDelete_whenNoSpansBefore() {
-        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
-        final KeyEvent event = KeyboardUtil.del();
-        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
-        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
-                eq(event.getKeyCode()), same(event));
-    }
-
-    @Test
-    public void testOnKeyDown_deletesEmoji() {
-        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
-        final KeyEvent event = KeyboardUtil.del();
-        assertTrue(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
-        verifyNoMoreInteractions(mKeyListener);
-    }
-
-    @Test
-    public void testOnKeyDown_doesNotForwardDeleteEmoji_withNoSpansAfter() {
-        Selection.setSelection(mEditable, mTestString.emojiEndIndex());
-        final KeyEvent event = KeyboardUtil.forwardDel();
-        assertFalse(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
-        verify(mKeyListener, times(1)).onKeyDown((View) eq(null), same(mEditable),
-                eq(event.getKeyCode()), same(event));
-    }
-
-    @Test
-    public void testOnKeyDown_forwardDeletesEmoji() {
-        Selection.setSelection(mEditable, mTestString.emojiStartIndex());
-        final KeyEvent event = KeyboardUtil.forwardDel();
-        assertTrue(mEmojiKeyListener.onKeyDown(null, mEditable, event.getKeyCode(), event));
-        verifyNoMoreInteractions(mKeyListener);
-    }
-}
diff --git a/emoji2/emoji2/src/androidTest/res/layout/activity_default.xml b/emoji2/emoji2/src/androidTest/res/layout/activity_default.xml
index 2d7968c..486dfbd 100644
--- a/emoji2/emoji2/src/androidTest/res/layout/activity_default.xml
+++ b/emoji2/emoji2/src/androidTest/res/layout/activity_default.xml
@@ -1,11 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              xmlns:app="http://schemas.android.com/apk/res-auto"
-              android:id="@+id/root"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
+    android:id="@+id/root"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
 
     <TextView
         android:id="@+id/text"
@@ -13,15 +12,8 @@
         android:layout_height="wrap_content"
         android:textSize="8sp"/>
 
-    <androidx.emoji2.widget.EmojiEditText
+    <EditText
         android:id="@+id/editText"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"/>
-
-    <androidx.emoji2.widget.EmojiEditText
-        android:id="@+id/editTextWithMaxCount"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        app:maxEmojiCount="5"/>
-
 </LinearLayout>
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompat.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompat.java
index 1dc1ac4..86c3588 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompat.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiCompat.java
@@ -197,12 +197,12 @@
     private static final Object INSTANCE_LOCK = new Object();
 
     @GuardedBy("INSTANCE_LOCK")
-    private static volatile EmojiCompat sInstance;
+    private static volatile @Nullable EmojiCompat sInstance;
 
-    private final ReadWriteLock mInitLock;
+    private final @NonNull ReadWriteLock mInitLock;
 
     @GuardedBy("mInitLock")
-    private final Set<InitCallback> mInitCallbacks;
+    private final @NonNull Set<InitCallback> mInitCallbacks;
 
     @GuardedBy("mInitLock")
     @LoadState
@@ -211,18 +211,18 @@
     /**
      * Handler with main looper to run the callbacks on.
      */
-    private final Handler mMainHandler;
+    private final @NonNull Handler mMainHandler;
 
     /**
      * Helper class for pre 19 compatibility.
      */
-    private final CompatInternal mHelper;
+    private final @NonNull CompatInternal mHelper;
 
     /**
      * Metadata loader instance given in the Config instance.
      */
     @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final MetadataRepoLoader mMetadataLoader;
+    final @NonNull MetadataRepoLoader mMetadataLoader;
 
     /**
      * @see Config#setReplaceAll(boolean)
@@ -240,7 +240,7 @@
      * @see Config#setUseEmojiAsDefaultStyle(boolean, List)
      */
     @SuppressWarnings("WeakerAccess") /* synthetic access */
-    final int[] mEmojiAsDefaultStyleExceptions;
+    final @Nullable int[] mEmojiAsDefaultStyleExceptions;
 
     /**
      * @see Config#setEmojiSpanIndicatorEnabled(boolean)
@@ -299,15 +299,20 @@
      * @see EmojiCompat.Config
      */
     @SuppressWarnings("GuardedBy")
+    @NonNull
     public static EmojiCompat init(@NonNull final Config config) {
-        if (sInstance == null) {
+        EmojiCompat localInstance = sInstance;
+        if (localInstance == null) {
             synchronized (INSTANCE_LOCK) {
-                if (sInstance == null) {
-                    sInstance = new EmojiCompat(config);
+                // copy ref to local for nullness checker
+                localInstance = sInstance;
+                if (localInstance == null) {
+                    localInstance = new EmojiCompat(config);
+                    sInstance = localInstance;
                 }
             }
         }
-        return sInstance;
+        return localInstance;
     }
 
     /**
@@ -319,11 +324,13 @@
     @SuppressWarnings("GuardedBy")
     @RestrictTo(LIBRARY_GROUP_PREFIX)
     @VisibleForTesting
+    @NonNull
     public static EmojiCompat reset(@NonNull final Config config) {
         synchronized (INSTANCE_LOCK) {
-            sInstance = new EmojiCompat(config);
+            EmojiCompat localInstance = new EmojiCompat(config);
+            sInstance = localInstance;
+            return localInstance;
         }
-        return sInstance;
     }
 
     /**
@@ -334,7 +341,8 @@
     @SuppressWarnings("GuardedBy")
     @RestrictTo(LIBRARY_GROUP_PREFIX)
     @VisibleForTesting
-    public static EmojiCompat reset(final EmojiCompat emojiCompat) {
+    @Nullable
+    public static EmojiCompat reset(@Nullable final EmojiCompat emojiCompat) {
         synchronized (INSTANCE_LOCK) {
             sInstance = emojiCompat;
         }
@@ -349,11 +357,13 @@
      *
      * @throws IllegalStateException if called before {@link #init(EmojiCompat.Config)}
      */
+    @NonNull
     public static EmojiCompat get() {
         synchronized (INSTANCE_LOCK) {
-            Preconditions.checkState(sInstance != null,
+            EmojiCompat localInstance = sInstance;
+            Preconditions.checkState(localInstance != null,
                     "EmojiCompat is not initialized. Please call EmojiCompat.init() first");
-            return sInstance;
+            return localInstance;
         }
     }
 
@@ -538,7 +548,7 @@
      * @return {@code true} if an {@link EmojiSpan} is deleted
      */
     public static boolean handleOnKeyDown(@NonNull final Editable editable, final int keyCode,
-            final KeyEvent event) {
+            @NonNull final KeyEvent event) {
         if (Build.VERSION.SDK_INT >= 19) {
             return EmojiProcessor.handleOnKeyDown(editable, keyCode, event);
         } else {
@@ -621,11 +631,13 @@
      * @throws IllegalStateException if not initialized yet
      * @see #process(CharSequence, int, int)
      */
+    @Nullable
     @CheckResult
-    public CharSequence process(@NonNull final CharSequence charSequence) {
+    public CharSequence process(@Nullable final CharSequence charSequence) {
         // since charSequence might be null here we have to check it. Passing through here to the
         // main function so that it can do all the checks including isInitialized. It will also
         // be the main point that decides what to return.
+
         //noinspection ConstantConditions
         @IntRange(from = 0) final int length = charSequence == null ? 0 : charSequence.length();
         return process(charSequence, 0, length);
@@ -658,8 +670,9 @@
      *                                  {@code start > charSequence.length()},
      *                                  {@code end > charSequence.length()}
      */
+    @Nullable
     @CheckResult
-    public CharSequence process(@NonNull final CharSequence charSequence,
+    public CharSequence process(@Nullable final CharSequence charSequence,
             @IntRange(from = 0) final int start, @IntRange(from = 0) final int end) {
         return process(charSequence, start, end, EMOJI_COUNT_UNLIMITED);
     }
@@ -694,8 +707,9 @@
      *                                  {@code end > charSequence.length()}
      *                                  {@code maxEmojiCount < 0}
      */
+    @Nullable
     @CheckResult
-    public CharSequence process(@NonNull final CharSequence charSequence,
+    public CharSequence process(@Nullable final CharSequence charSequence,
             @IntRange(from = 0) final int start, @IntRange(from = 0) final int end,
             @IntRange(from = 0) final int maxEmojiCount) {
         return process(charSequence, start, end, maxEmojiCount, REPLACE_STRATEGY_DEFAULT);
@@ -735,8 +749,9 @@
      *                                  {@code end > charSequence.length()}
      *                                  {@code maxEmojiCount < 0}
      */
+    @Nullable
     @CheckResult
-    public CharSequence process(@NonNull final CharSequence charSequence,
+    public CharSequence process(@Nullable final CharSequence charSequence,
             @IntRange(from = 0) final int start, @IntRange(from = 0) final int end,
             @IntRange(from = 0) final int maxEmojiCount, @ReplaceStrategy int replaceStrategy) {
         Preconditions.checkState(isInitialized(), "Not initialized yet");
@@ -944,14 +959,17 @@
      */
     public abstract static class Config {
         @SuppressWarnings("WeakerAccess") /* synthetic access */
+        @NonNull
         final MetadataRepoLoader mMetadataLoader;
         @SuppressWarnings("WeakerAccess") /* synthetic access */
         boolean mReplaceAll;
         @SuppressWarnings("WeakerAccess") /* synthetic access */
         boolean mUseEmojiAsDefaultStyle;
         @SuppressWarnings("WeakerAccess") /* synthetic access */
+        @Nullable
         int[] mEmojiAsDefaultStyleExceptions;
         @SuppressWarnings("WeakerAccess") /* synthetic access */
+        @Nullable
         Set<InitCallback> mInitCallbacks;
         @SuppressWarnings("WeakerAccess") /* synthetic access */
         boolean mEmojiSpanIndicatorEnabled;
@@ -960,6 +978,7 @@
         @SuppressWarnings("WeakerAccess") /* synthetic access */
         @LoadStrategy int mMetadataLoadStrategy = LOAD_STRATEGY_DEFAULT;
         @SuppressWarnings("WeakerAccess") /* synthetic access */
+        @NonNull
         GlyphChecker mGlyphChecker = new EmojiProcessor.DefaultGlyphChecker();
 
         /**
@@ -979,6 +998,7 @@
          *
          * @return EmojiCompat.Config instance
          */
+        @NonNull
         public Config registerInitCallback(@NonNull InitCallback initCallback) {
             Preconditions.checkNotNull(initCallback, "initCallback cannot be null");
             if (mInitCallbacks == null) {
@@ -997,6 +1017,7 @@
          *
          * @return EmojiCompat.Config instance
          */
+        @NonNull
         public Config unregisterInitCallback(@NonNull InitCallback initCallback) {
             Preconditions.checkNotNull(initCallback, "initCallback cannot be null");
             if (mInitCallbacks != null) {
@@ -1014,6 +1035,7 @@
          *
          * @return EmojiCompat.Config instance
          */
+        @NonNull
         public Config setReplaceAll(final boolean replaceAll) {
             mReplaceAll = replaceAll;
             return this;
@@ -1034,6 +1056,7 @@
          * @param useEmojiAsDefaultStyle whether to use the emoji style presentation for all emojis
          *                               that would be presented as text style by default
          */
+        @NonNull
         public Config setUseEmojiAsDefaultStyle(final boolean useEmojiAsDefaultStyle) {
             return setUseEmojiAsDefaultStyle(useEmojiAsDefaultStyle,
                     null);
@@ -1054,6 +1077,7 @@
          *                                      {@link #setUseEmojiAsDefaultStyle(boolean)} should
          *                                      be used instead.
          */
+        @NonNull
         public Config setUseEmojiAsDefaultStyle(final boolean useEmojiAsDefaultStyle,
                 @Nullable final List<Integer> emojiAsDefaultStyleExceptions) {
             mUseEmojiAsDefaultStyle = useEmojiAsDefaultStyle;
@@ -1078,6 +1102,7 @@
          * @param emojiSpanIndicatorEnabled when {@code true} a background is drawn for each emoji
          *                                  that is replaced
          */
+        @NonNull
         public Config setEmojiSpanIndicatorEnabled(boolean emojiSpanIndicatorEnabled) {
             mEmojiSpanIndicatorEnabled = emojiSpanIndicatorEnabled;
             return this;
@@ -1089,6 +1114,7 @@
          *
          * @see #setEmojiSpanIndicatorEnabled(boolean)
          */
+        @NonNull
         public Config setEmojiSpanIndicatorColor(@ColorInt int color) {
             mEmojiSpanIndicatorColor = color;
             return this;
@@ -1130,6 +1156,7 @@
          *                  {@link EmojiCompat#LOAD_STRATEGY_MANUAL}
          *
          */
+        @NonNull
         public Config setMetadataLoadStrategy(@LoadStrategy int strategy) {
             mMetadataLoadStrategy = strategy;
             return this;
@@ -1151,6 +1178,7 @@
         /**
          * Returns the {@link MetadataRepoLoader}.
          */
+        @NonNull
         protected final MetadataRepoLoader getMetadataRepoLoader() {
             return mMetadataLoader;
         }
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiDefaults.java
similarity index 62%
copy from compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
copy to emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiDefaults.java
index 7e01354..9818af1 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiDefaults.java
@@ -1,5 +1,3 @@
-// ktlint-disable filename
-
 /*
  * Copyright 2021 The Android Open Source Project
  *
@@ -16,6 +14,22 @@
  * limitations under the License.
  */
 
-package androidx.compose.foundation
+package androidx.emoji2.text;
 
-internal actual typealias AtomicReference<V> = java.util.concurrent.atomic.AtomicReference<V>
\ No newline at end of file
+import androidx.annotation.RestrictTo;
+
+/**
+ * Defaults for emojicompat
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class EmojiDefaults {
+
+    private EmojiDefaults() {}
+
+    /**
+     * Default value for maxEmojiCount if not specified.
+     */
+    public static final int MAX_EMOJI_COUNT = Integer.MAX_VALUE;
+}
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiMetadata.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiMetadata.java
index ba46f82..d6ef218 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiMetadata.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiMetadata.java
@@ -17,6 +17,7 @@
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
 
+import android.annotation.SuppressLint;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Typeface;
@@ -78,6 +79,7 @@
     /**
      * MetadataRepo that holds this instance.
      */
+    @NonNull
     private final MetadataRepo mMetadataRepo;
 
     /**
@@ -117,6 +119,7 @@
     /**
      * @return return typeface to be used to render this metadata
      */
+    @NonNull
     public Typeface getTypeface() {
         return mMetadataRepo.getTypeface();
     }
@@ -181,6 +184,7 @@
      * style selector 0xFE0F)
      */
     @HasGlyph
+    @SuppressLint("KotlinPropertyAccess")
     public int getHasGlyph() {
         return mHasGlyph;
     }
@@ -190,6 +194,7 @@
      *
      * @param hasGlyph {@code true} if system can render the emoji
      */
+    @SuppressLint("KotlinPropertyAccess")
     public void setHasGlyph(boolean hasGlyph) {
         mHasGlyph = hasGlyph ? HAS_GLYPH_EXISTS : HAS_GLYPH_ABSENT;
     }
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiProcessor.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiProcessor.java
index d8c4765..98849eb 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiProcessor.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiProcessor.java
@@ -37,7 +37,6 @@
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.core.graphics.PaintCompat;
-import androidx.emoji2.widget.SpannableBuilder;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -81,16 +80,19 @@
     /**
      * Factory used to create EmojiSpans.
      */
+    @NonNull
     private final EmojiCompat.SpanFactory mSpanFactory;
 
     /**
      * Emoji metadata repository.
      */
+    @NonNull
     private final MetadataRepo mMetadataRepo;
 
     /**
      * Utility class that checks if the system can render a given glyph.
      */
+    @NonNull
     private EmojiCompat.GlyphChecker mGlyphChecker;
 
     /**
@@ -101,6 +103,7 @@
     /**
      * @see EmojiCompat.Config#setUseEmojiAsDefaultStyle(boolean, List)
      */
+    @Nullable
     private final int[] mEmojiAsDefaultStyleExceptions;
 
     EmojiProcessor(
@@ -298,7 +301,7 @@
      * @return {@code true} if an {@link EmojiSpan} is deleted
      */
     static boolean handleOnKeyDown(@NonNull final Editable editable, final int keyCode,
-            final KeyEvent event) {
+            @NonNull final KeyEvent event) {
         final boolean handled;
         switch (keyCode) {
             case KeyEvent.KEYCODE_DEL:
@@ -320,7 +323,7 @@
         return false;
     }
 
-    private static boolean delete(final Editable content, final KeyEvent event,
+    private static boolean delete(@NonNull final Editable content, @NonNull final KeyEvent event,
             final boolean forwardDelete) {
         if (hasModifiers(event)) {
             return false;
@@ -431,7 +434,7 @@
         return start == -1 || end == -1 || start != end;
     }
 
-    private static boolean hasModifiers(KeyEvent event) {
+    private static boolean hasModifiers(@NonNull KeyEvent event) {
         return !KeyEvent.metaStateHasNoModifiers(event.getMetaState());
     }
 
@@ -651,9 +654,12 @@
     /**
      * Copy of BaseInputConnection findIndexBackward and findIndexForward functions.
      */
+    @RequiresApi(19)
     private static final class CodepointIndexFinder {
         private static final int INVALID_INDEX = -1;
 
+        private CodepointIndexFinder() {}
+
         /**
          * Find start index of the character in {@code cs} that is {@code numCodePoints} behind
          * starting from {@code from}.
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiSpan.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiSpan.java
index 70dd537..dd07ff1 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiSpan.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/EmojiSpan.java
@@ -17,10 +17,12 @@
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
 
+import android.annotation.SuppressLint;
 import android.graphics.Paint;
 import android.text.style.ReplacementSpan;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.VisibleForTesting;
@@ -43,6 +45,7 @@
      * representing same emoji to be in memory. When unparcelled, EmojiSpan tries to set it back
      * using the singleton EmojiCompat instance.
      */
+    @NonNull
     private final EmojiMetadata mMetadata;
 
     /**
@@ -74,8 +77,11 @@
     }
 
     @Override
-    public int getSize(@NonNull final Paint paint, final CharSequence text, final int start,
-            final int end, final Paint.FontMetricsInt fm) {
+    public int getSize(@NonNull final Paint paint,
+            @SuppressLint("UnknownNullness") final CharSequence text,
+            final int start,
+            final int end,
+            @Nullable final Paint.FontMetricsInt fm) {
         paint.getFontMetricsInt(mTmpFontMetrics);
         final int fontHeight = Math.abs(mTmpFontMetrics.descent - mTmpFontMetrics.ascent);
 
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java
index 4ade79f..f20049c 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/FontRequestEmojiCompatConfig.java
@@ -140,7 +140,8 @@
      *               of {@code null}, the metadata loader creates own {@link HandlerThread} for
      *               initialization.
      */
-    public FontRequestEmojiCompatConfig setHandler(Handler handler) {
+    @NonNull
+    public FontRequestEmojiCompatConfig setHandler(@Nullable Handler handler) {
         ((FontRequestMetadataLoader) getMetadataRepoLoader()).setHandler(handler);
         return this;
     }
@@ -153,7 +154,8 @@
      *              file. Can be {@code null}. In case of {@code null}, the metadata loader never
      *              retries.
      */
-    public FontRequestEmojiCompatConfig setRetryPolicy(RetryPolicy policy) {
+    @NonNull
+    public FontRequestEmojiCompatConfig setRetryPolicy(@Nullable RetryPolicy policy) {
         ((FontRequestMetadataLoader) getMetadataRepoLoader()).setRetryPolicy(policy);
         return this;
     }
@@ -163,23 +165,23 @@
      * given FontRequest.
      */
     private static class FontRequestMetadataLoader implements EmojiCompat.MetadataRepoLoader {
-        private final Context mContext;
-        private final FontRequest mRequest;
-        private final FontProviderHelper mFontProviderHelper;
+        private final @NonNull Context mContext;
+        private final @NonNull FontRequest mRequest;
+        private final @NonNull FontProviderHelper mFontProviderHelper;
 
-        private final Object mLock = new Object();
+        private final @NonNull Object mLock = new Object();
         @GuardedBy("mLock")
-        private Handler mHandler;
+        private @Nullable Handler mHandler;
         @GuardedBy("mLock")
-        private HandlerThread mThread;
+        private @Nullable HandlerThread mThread;
         @GuardedBy("mLock")
         private @Nullable RetryPolicy mRetryPolicy;
 
         // Following three variables must be touched only on the thread associated with mHandler.
         @SuppressWarnings("WeakerAccess") /* synthetic access */
         EmojiCompat.MetadataRepoLoaderCallback mCallback;
-        private ContentObserver mObserver;
-        private Runnable mHandleMetadataCreationRunner;
+        private @Nullable ContentObserver mObserver;
+        private @Nullable Runnable mHandleMetadataCreationRunner;
 
         FontRequestMetadataLoader(@NonNull Context context, @NonNull FontRequest request,
                 @NonNull FontProviderHelper fontProviderHelper) {
@@ -190,13 +192,13 @@
             mFontProviderHelper = fontProviderHelper;
         }
 
-        public void setHandler(Handler handler) {
+        public void setHandler(@Nullable Handler handler) {
             synchronized (mLock) {
                 mHandler = handler;
             }
         }
 
-        public void setRetryPolicy(RetryPolicy policy) {
+        public void setRetryPolicy(@Nullable RetryPolicy policy) {
             synchronized (mLock) {
                 mRetryPolicy = policy;
             }
@@ -332,12 +334,14 @@
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
     public static class FontProviderHelper {
         /** Calls FontsContractCompat.fetchFonts. */
+        @NonNull
         public FontFamilyResult fetchFonts(@NonNull Context context,
                 @NonNull FontRequest request) throws NameNotFoundException {
             return FontsContractCompat.fetchFonts(context, null /* cancellation signal */, request);
         }
 
         /** Calls FontsContractCompat.buildTypeface. */
+        @Nullable
         public Typeface buildTypeface(@NonNull Context context,
                 @NonNull FontsContractCompat.FontInfo font) throws NameNotFoundException {
             return FontsContractCompat.buildTypeface(context, null /* cancellation signal */,
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/MetadataListReader.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/MetadataListReader.java
index f9f397f..6db7379 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/MetadataListReader.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/MetadataListReader.java
@@ -21,6 +21,7 @@
 
 import androidx.annotation.AnyThread;
 import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.text.emoji.flatbuffer.MetadataList;
@@ -236,9 +237,9 @@
      */
     private static class InputStreamOpenTypeReader implements OpenTypeReader {
 
-        private final byte[] mByteArray;
-        private final ByteBuffer mByteBuffer;
-        private final InputStream mInputStream;
+        private final @NonNull byte[] mByteArray;
+        private final @NonNull ByteBuffer mByteBuffer;
+        private final @NonNull InputStream mInputStream;
         private long mPosition = 0;
 
         /**
@@ -247,7 +248,7 @@
          *
          * @param inputStream InputStream to read from
          */
-        InputStreamOpenTypeReader(final InputStream inputStream) {
+        InputStreamOpenTypeReader(@NonNull final InputStream inputStream) {
             mInputStream = inputStream;
             mByteArray = new byte[UINT32_BYTE_COUNT];
             mByteBuffer = ByteBuffer.wrap(mByteArray);
@@ -306,14 +307,14 @@
      */
     private static class ByteBufferReader implements OpenTypeReader {
 
-        private final ByteBuffer mByteBuffer;
+        private final @NonNull ByteBuffer mByteBuffer;
 
         /**
          * Constructs the reader with the given ByteBuffer.
          *
          * @param byteBuffer ByteBuffer to read from
          */
-        ByteBufferReader(final ByteBuffer byteBuffer) {
+        ByteBufferReader(@NonNull final ByteBuffer byteBuffer) {
             mByteBuffer = byteBuffer;
             mByteBuffer.order(ByteOrder.BIG_ENDIAN);
         }
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/MetadataRepo.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/MetadataRepo.java
index 2f5ea66..00fef53 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/MetadataRepo.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/MetadataRepo.java
@@ -47,36 +47,23 @@
     /**
      * MetadataList that contains the emoji metadata.
      */
-    private final MetadataList mMetadataList;
+    private final @NonNull MetadataList mMetadataList;
 
     /**
      * char presentation of all EmojiMetadata's in a single array. All emojis we have are mapped to
      * Private Use Area A, in the range U+F0000..U+FFFFD. Therefore each emoji takes 2 chars.
      */
-    private final char[] mEmojiCharArray;
+    private final @NonNull char[] mEmojiCharArray;
 
     /**
      * Empty root node of the trie.
      */
-    private final Node mRootNode;
+    private final @NonNull Node mRootNode;
 
     /**
      * Typeface to be used to render emojis.
      */
-    private final Typeface mTypeface;
-
-    /**
-     * Constructor used for tests.
-     *
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP_PREFIX)
-    MetadataRepo() {
-        mTypeface = null;
-        mMetadataList = null;
-        mRootNode = new Node(DEFAULT_ROOT_SIZE);
-        mEmojiCharArray = new char[0];
-    }
+    private final @NonNull Typeface mTypeface;
 
     /**
      * Private constructor that is called by one of {@code create} methods.
@@ -94,12 +81,22 @@
     }
 
     /**
+     * Construct MetadataRepo from a preloaded MetadatList.
+     */
+    @NonNull
+    static MetadataRepo create(@NonNull final Typeface typeface,
+            @NonNull final MetadataList metadataList) {
+        return new MetadataRepo(typeface, metadataList);
+    }
+
+    /**
      * Construct MetadataRepo from an input stream. The library does not close the given
      * InputStream, therefore it is caller's responsibility to properly close the stream.
      *
      * @param typeface Typeface to be used to render emojis
      * @param inputStream InputStream to read emoji metadata from
      */
+    @NonNull
     public static MetadataRepo create(@NonNull final Typeface typeface,
             @NonNull final InputStream inputStream) throws IOException {
         return new MetadataRepo(typeface, MetadataListReader.read(inputStream));
@@ -112,6 +109,7 @@
      * @param typeface Typeface to be used to render emojis
      * @param byteBuffer ByteBuffer to read emoji metadata from
      */
+    @NonNull
     public static MetadataRepo create(@NonNull final Typeface typeface,
             @NonNull final ByteBuffer byteBuffer) throws IOException {
         return new MetadataRepo(typeface, MetadataListReader.read(byteBuffer));
@@ -124,8 +122,9 @@
      * @param assetPath asset manager path of the file that the Typeface and metadata will be
      *                  created from
      */
+    @NonNull
     public static MetadataRepo create(@NonNull final AssetManager assetManager,
-            final String assetPath) throws IOException {
+            @NonNull final String assetPath) throws IOException {
         final Typeface typeface = Typeface.createFromAsset(assetManager, assetPath);
         return new MetadataRepo(typeface, MetadataListReader.read(assetManager, assetPath));
     }
@@ -148,6 +147,7 @@
     /**
      * @hide
      */
+    @NonNull
     @RestrictTo(LIBRARY_GROUP_PREFIX)
     Typeface getTypeface() {
         return mTypeface;
@@ -164,6 +164,7 @@
     /**
      * @hide
      */
+    @NonNull
     @RestrictTo(LIBRARY_GROUP_PREFIX)
     Node getRootNode() {
         return mRootNode;
@@ -172,6 +173,7 @@
     /**
      * @hide
      */
+    @NonNull
     @RestrictTo(LIBRARY_GROUP_PREFIX)
     public char[] getEmojiCharArray() {
         return mEmojiCharArray;
@@ -180,6 +182,7 @@
     /**
      * @hide
      */
+    @NonNull
     @RestrictTo(LIBRARY_GROUP_PREFIX)
     public MetadataList getMetadataList() {
         return mMetadataList;
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/SpannableBuilder.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/SpannableBuilder.java
similarity index 89%
rename from emoji2/emoji2/src/main/java/androidx/emoji2/widget/SpannableBuilder.java
rename to emoji2/emoji2/src/main/java/androidx/emoji2/text/SpannableBuilder.java
index 97fd4e7..01399a4 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/SpannableBuilder.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/SpannableBuilder.java
@@ -13,10 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package androidx.emoji2.widget;
+package androidx.emoji2.text;
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
 
+import android.annotation.SuppressLint;
 import android.text.Editable;
 import android.text.SpanWatcher;
 import android.text.Spannable;
@@ -27,7 +28,6 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.core.util.Preconditions;
-import androidx.emoji2.text.EmojiSpan;
 
 import java.lang.reflect.Array;
 import java.util.ArrayList;
@@ -46,19 +46,18 @@
  * the framework.
  *
  * @hide
- * @see EmojiEditableFactory
  */
 @RestrictTo(LIBRARY_GROUP_PREFIX)
 public final class SpannableBuilder extends SpannableStringBuilder {
     /**
      * DynamicLayout$ChangeWatcher class.
      */
-    private final Class<?> mWatcherClass;
+    private final @NonNull Class<?> mWatcherClass;
 
     /**
      * All WatcherWrappers.
      */
-    private final List<WatcherWrapper> mWatchers = new ArrayList<>();
+    private final @NonNull List<WatcherWrapper> mWatchers = new ArrayList<>();
 
     /**
      * @hide
@@ -93,8 +92,9 @@
     /**
      * @hide
      */
+    @NonNull
     @RestrictTo(LIBRARY_GROUP_PREFIX)
-    static SpannableBuilder create(@NonNull Class<?> clazz, @NonNull CharSequence text) {
+    public static SpannableBuilder create(@NonNull Class<?> clazz, @NonNull CharSequence text) {
         return new SpannableBuilder(clazz, text);
     }
 
@@ -120,6 +120,7 @@
         return mWatcherClass == clazz;
     }
 
+    @SuppressLint("UnknownNullness")
     @Override
     public CharSequence subSequence(int start, int end) {
         return new SpannableBuilder(mWatcherClass, this, start, end);
@@ -131,7 +132,7 @@
      * this new mObject as the span.
      */
     @Override
-    public void setSpan(Object what, int start, int end, int flags) {
+    public void setSpan(@Nullable Object what, int start, int end, int flags) {
         if (isWatcher(what)) {
             final WatcherWrapper span = new WatcherWrapper(what);
             mWatchers.add(span);
@@ -144,9 +145,10 @@
      * If previously a DynamicLayout$ChangeWatcher was wrapped in a WatcherWrapper, return the
      * correct Object that the client has set.
      */
+    @SuppressLint("UnknownNullness")
     @SuppressWarnings("unchecked")
     @Override
-    public <T> T[] getSpans(int queryStart, int queryEnd, Class<T> kind) {
+    public <T> T[] getSpans(int queryStart, int queryEnd, @NonNull Class<T> kind) {
         if (isWatcher(kind)) {
             final WatcherWrapper[] spans = super.getSpans(queryStart, queryEnd,
                     WatcherWrapper.class);
@@ -164,7 +166,7 @@
      * instead.
      */
     @Override
-    public void removeSpan(Object what) {
+    public void removeSpan(@Nullable Object what) {
         final WatcherWrapper watcher;
         if (isWatcher(what)) {
             watcher = getWatcherFor(what);
@@ -186,7 +188,7 @@
      * Return the correct start for the DynamicLayout$ChangeWatcher span.
      */
     @Override
-    public int getSpanStart(Object tag) {
+    public int getSpanStart(@Nullable Object tag) {
         if (isWatcher(tag)) {
             final WatcherWrapper watcher = getWatcherFor(tag);
             if (watcher != null) {
@@ -200,7 +202,7 @@
      * Return the correct end for the DynamicLayout$ChangeWatcher span.
      */
     @Override
-    public int getSpanEnd(Object tag) {
+    public int getSpanEnd(@Nullable Object tag) {
         if (isWatcher(tag)) {
             final WatcherWrapper watcher = getWatcherFor(tag);
             if (watcher != null) {
@@ -214,7 +216,7 @@
      * Return the correct flags for the DynamicLayout$ChangeWatcher span.
      */
     @Override
-    public int getSpanFlags(Object tag) {
+    public int getSpanFlags(@Nullable Object tag) {
         if (isWatcher(tag)) {
             final WatcherWrapper watcher = getWatcherFor(tag);
             if (watcher != null) {
@@ -228,8 +230,8 @@
      * Return the correct transition for the DynamicLayout$ChangeWatcher span.
      */
     @Override
-    public int nextSpanTransition(int start, int limit, Class type) {
-        if (isWatcher(type)) {
+    public int nextSpanTransition(int start, int limit, @Nullable Class type) {
+        if (type == null || isWatcher(type)) {
             type = WatcherWrapper.class;
         }
         return super.nextSpanTransition(start, limit, type);
@@ -297,6 +299,7 @@
         }
     }
 
+    @SuppressLint("UnknownNullness")
     @Override
     public SpannableStringBuilder replace(int start, int end, CharSequence tb) {
         blockWatchers();
@@ -305,6 +308,7 @@
         return this;
     }
 
+    @SuppressLint("UnknownNullness")
     @Override
     public SpannableStringBuilder replace(int start, int end, CharSequence tb, int tbstart,
             int tbend) {
@@ -314,42 +318,51 @@
         return this;
     }
 
+    @SuppressLint("UnknownNullness")
     @Override
     public SpannableStringBuilder insert(int where, CharSequence tb) {
         super.insert(where, tb);
         return this;
     }
 
+    @SuppressLint("UnknownNullness")
     @Override
     public SpannableStringBuilder insert(int where, CharSequence tb, int start, int end) {
         super.insert(where, tb, start, end);
         return this;
     }
 
+    @SuppressLint("UnknownNullness")
     @Override
     public SpannableStringBuilder delete(int start, int end) {
         super.delete(start, end);
         return this;
     }
 
+    @NonNull
     @Override
-    public SpannableStringBuilder append(CharSequence text) {
+    public SpannableStringBuilder append(@SuppressLint("UnknownNullness") CharSequence text) {
         super.append(text);
         return this;
     }
 
+    @NonNull
     @Override
     public SpannableStringBuilder append(char text) {
         super.append(text);
         return this;
     }
 
+    @NonNull
     @Override
-    public SpannableStringBuilder append(CharSequence text, int start, int end) {
+    public SpannableStringBuilder append(@SuppressLint("UnknownNullness") CharSequence text,
+            int start,
+            int end) {
         super.append(text, start, end);
         return this;
     }
 
+    @SuppressLint("UnknownNullness")
     @Override
     public SpannableStringBuilder append(CharSequence text, Object what, int flags) {
         super.append(text, what, flags);
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/text/TypefaceEmojiSpan.java b/emoji2/emoji2/src/main/java/androidx/emoji2/text/TypefaceEmojiSpan.java
index 2c3ab58..5eb3ff9 100644
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/text/TypefaceEmojiSpan.java
+++ b/emoji2/emoji2/src/main/java/androidx/emoji2/text/TypefaceEmojiSpan.java
@@ -17,12 +17,14 @@
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
 
+import android.annotation.SuppressLint;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.text.TextPaint;
 
 import androidx.annotation.IntRange;
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 
@@ -38,19 +40,20 @@
     /**
      * Paint object used to draw a background in debug mode.
      */
-    private static Paint sDebugPaint;
+    private static @Nullable Paint sDebugPaint;
 
     /**
      * Default constructor.
      *
      * @param metadata metadata representing the emoji that this span will draw
      */
-    public TypefaceEmojiSpan(final EmojiMetadata metadata) {
+    public TypefaceEmojiSpan(final @NonNull EmojiMetadata metadata) {
         super(metadata);
     }
 
     @Override
-    public void draw(@NonNull final Canvas canvas, final CharSequence text,
+    public void draw(@NonNull final Canvas canvas,
+            @SuppressLint("UnknownNullness") final CharSequence text,
             @IntRange(from = 0) final int start, @IntRange(from = 0) final int end, final float x,
             final int top, final int y, final int bottom, @NonNull final Paint paint) {
         if (EmojiCompat.get().isEmojiSpanIndicatorEnabled()) {
@@ -59,6 +62,7 @@
         getMetadata().draw(canvas, x, y, paint);
     }
 
+    @NonNull
     private static Paint getDebugPaint() {
         if (sDebugPaint == null) {
             sDebugPaint = new TextPaint();
diff --git a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiInputConnection.java b/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiInputConnection.java
deleted file mode 100644
index 53e8ee4..0000000
--- a/emoji2/emoji2/src/main/java/androidx/emoji2/widget/EmojiInputConnection.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2021 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.emoji2.widget;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;
-
-import android.text.Editable;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputConnection;
-import android.view.inputmethod.InputConnectionWrapper;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
-import androidx.annotation.RestrictTo;
-import androidx.emoji2.text.EmojiCompat;
-
-/**
- * InputConnectionWrapper for EditText delete operations. Keyboard does not have knowledge about
- * emojis and therefore might send commands to delete a part of the emoji sequence which creates
- * invalid codeunits/getCodepointAt in the text.
- * <p/>
- * This class tries to correctly delete an emoji checking if there is an emoji span.
- *
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP_PREFIX)
-@RequiresApi(19)
-final class EmojiInputConnection extends InputConnectionWrapper {
-    private final TextView mTextView;
-
-    EmojiInputConnection(
-            @NonNull final TextView textView,
-            @NonNull final InputConnection inputConnection,
-            @NonNull final EditorInfo outAttrs) {
-        super(inputConnection, false);
-        mTextView = textView;
-        EmojiCompat.get().updateEditorInfoAttrs(outAttrs);
-    }
-
-    @Override
-    public boolean deleteSurroundingText(final int beforeLength, final int afterLength) {
-        final boolean result = EmojiCompat.handleDeleteSurroundingText(this, getEditable(),
-                beforeLength, afterLength, false /*inCodePoints*/);
-        return result || super.deleteSurroundingText(beforeLength, afterLength);
-    }
-
-    @Override
-    public boolean deleteSurroundingTextInCodePoints(final int beforeLength,
-            final int afterLength) {
-        final boolean result = EmojiCompat.handleDeleteSurroundingText(this, getEditable(),
-                beforeLength, afterLength, true /*inCodePoints*/);
-        return result || super.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
-    }
-
-    private Editable getEditable() {
-        return mTextView.getEditableText();
-    }
-}
diff --git a/exifinterface/exifinterface/lint-baseline.xml b/exifinterface/exifinterface/lint-baseline.xml
index 439d7e6..1cd9c9f 100644
--- a/exifinterface/exifinterface/lint-baseline.xml
+++ b/exifinterface/exifinterface/lint-baseline.xml
@@ -2,24 +2,13 @@
 <issues format="5" by="lint 4.2.0-beta02" client="gradle" variant="debug" version="4.2.0-beta02">
 
     <issue
-        id="BanSynchronizedMethods"
-        message="Use of synchronized methods is not recommended"
-        errorLine1="        @Override"
-        errorLine2="        ^">
-        <location
-            file="src/main/java/androidx/exifinterface/media/ExifInterface.java"
-            line="7952"
-            column="9"/>
-    </issue>
-
-    <issue
         id="UnsafeNewApiCall"
         message="This call is to a method from API 21, the call containing class androidx.exifinterface.media.ExifInterface is not annotated with @RequiresApi(x) where x is at least 21. Either annotate the containing class with at least @RequiresApi(21) or move the call to a static method in a wrapper class annotated with at least @RequiresApi(21)."
         errorLine1="                fileDescriptor = Os.dup(fileDescriptor);"
         errorLine2="                                    ~~~">
         <location
             file="src/main/java/androidx/exifinterface/media/ExifInterface.java"
-            line="3980"
+            line="3983"
             column="37"/>
     </issue>
 
@@ -30,7 +19,7 @@
         errorLine2="                   ~~~~~">
         <location
             file="src/main/java/androidx/exifinterface/media/ExifInterface.java"
-            line="4659"
+            line="4642"
             column="20"/>
     </issue>
 
@@ -41,7 +30,7 @@
         errorLine2="                       ~~~~~">
         <location
             file="src/main/java/androidx/exifinterface/media/ExifInterface.java"
-            line="4729"
+            line="4712"
             column="24"/>
     </issue>
 
@@ -52,7 +41,7 @@
         errorLine2="                       ~~~~~">
         <location
             file="src/main/java/androidx/exifinterface/media/ExifInterface.java"
-            line="4756"
+            line="4739"
             column="24"/>
     </issue>
 
@@ -63,7 +52,7 @@
         errorLine2="                           ~~~~~">
         <location
             file="src/main/java/androidx/exifinterface/media/ExifInterface.java"
-            line="4779"
+            line="4762"
             column="28"/>
     </issue>
 
@@ -74,7 +63,7 @@
         errorLine2="                                           ~~~">
         <location
             file="src/main/java/androidx/exifinterface/media/ExifInterface.java"
-            line="4866"
+            line="4849"
             column="44"/>
     </issue>
 
@@ -85,7 +74,7 @@
         errorLine2="                       ~~~~~">
         <location
             file="src/main/java/androidx/exifinterface/media/ExifInterface.java"
-            line="4867"
+            line="4850"
             column="24"/>
     </issue>
 
@@ -96,18 +85,18 @@
         errorLine2="                          ~~~~~~~~~~~~~">
         <location
             file="src/main/java/androidx/exifinterface/media/ExifInterface.java"
-            line="5848"
+            line="5819"
             column="27"/>
     </issue>
 
     <issue
         id="UnsafeNewApiCall"
-        message="This call is to a method from API 21, the call containing class androidx.exifinterface.media.ExifInterface is not annotated with @RequiresApi(x) where x is at least 21. Either annotate the containing class with at least @RequiresApi(21) or move the call to a static method in a wrapper class annotated with at least @RequiresApi(21)."
+        message="This call is to a method from API 21, the call containing class androidx.exifinterface.media.ExifInterfaceUtils is not annotated with @RequiresApi(x) where x is at least 21. Either annotate the containing class with at least @RequiresApi(21) or move the call to a static method in a wrapper class annotated with at least @RequiresApi(21)."
         errorLine1="                Os.close(fd);"
         errorLine2="                   ~~~~~">
         <location
-            file="src/main/java/androidx/exifinterface/media/ExifInterface.java"
-            line="8089"
+            file="src/main/java/androidx/exifinterface/media/ExifInterfaceUtils.java"
+            line="147"
             column="20"/>
     </issue>
 
@@ -118,7 +107,7 @@
         errorLine2="                              ~~~~~">
         <location
             file="src/main/java/androidx/exifinterface/media/ExifInterface.java"
-            line="5032"
+            line="5015"
             column="31"/>
     </issue>
 
@@ -129,7 +118,7 @@
         errorLine2="                           ~~~~~~~~">
         <location
             file="src/main/java/androidx/exifinterface/media/ExifInterface.java"
-            line="5077"
+            line="5060"
             column="28"/>
     </issue>
 
diff --git a/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java b/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
index 47702d9..a2c919f 100644
--- a/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
+++ b/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
@@ -17,9 +17,10 @@
 package androidx.exifinterface.media;
 
 import static androidx.exifinterface.media.ExifInterfaceUtils.byteArrayToHexString;
+import static androidx.exifinterface.media.ExifInterfaceUtils.closeFileDescriptor;
+import static androidx.exifinterface.media.ExifInterfaceUtils.closeQuietly;
 import static androidx.exifinterface.media.ExifInterfaceUtils.convertToLongArray;
 import static androidx.exifinterface.media.ExifInterfaceUtils.copy;
-import static androidx.exifinterface.media.ExifInterfaceUtils.isSupportedFormatForSavingAttributes;
 import static androidx.exifinterface.media.ExifInterfaceUtils.parseSubSeconds;
 import static androidx.exifinterface.media.ExifInterfaceUtils.startsWith;
 
@@ -45,7 +46,6 @@
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
 import java.io.DataInput;
 import java.io.DataInputStream;
 import java.io.EOFException;
@@ -3048,6 +3048,9 @@
     private static final int IFD_FORMAT_DOUBLE = 12;
     // Format indicating a new IFD entry (See Adobe PageMaker® 6.0 TIFF Technical Notes, "New Tag")
     private static final int IFD_FORMAT_IFD = 13;
+
+    private static final int SKIP_BUFFER_SIZE = 8192;
+
     // Names for the data formats for debugging purpose.
     static final String[] IFD_FORMAT_NAMES = new String[] {
             "", "BYTE", "STRING", "USHORT", "ULONG", "URATIONAL", "SBYTE", "UNDEFINED", "SSHORT",
@@ -4031,7 +4034,7 @@
 
         boolean shouldBeExifDataOnly = (streamType == STREAM_TYPE_EXIF_DATA_ONLY);
         if (shouldBeExifDataOnly) {
-            inputStream = new BufferedInputStream(inputStream, SIGNATURE_CHECK_SIZE);
+            inputStream = new BufferedInputStream(inputStream, IDENTIFIER_EXIF_APP1.length);
             if (!isExifDataOnly((BufferedInputStream) inputStream)) {
                 Log.w(TAG, "Given data does not follow the structure of an Exif-only data.");
                 return;
@@ -4584,58 +4587,38 @@
                 mMimeType = getMimeType((BufferedInputStream) in);
             }
 
-            // Create byte-ordered input stream
-            ByteOrderedDataInputStream inputStream = new ByteOrderedDataInputStream(in);
-
-            if (!mIsExifDataOnly) {
-                switch (mMimeType) {
-                    case IMAGE_TYPE_JPEG: {
-                        getJpegAttributes(inputStream, /* offsetToJpeg= */ 0,
-                                IFD_TYPE_PRIMARY);
-                        return;
-                    }
-                    case IMAGE_TYPE_RAF: {
-                        getRafAttributes(inputStream);
-                        return;
-                    }
-                    case IMAGE_TYPE_HEIF: {
+            if (shouldSupportSeek(mMimeType)) {
+                SeekableByteOrderedDataInputStream inputStream =
+                        new SeekableByteOrderedDataInputStream(in);
+                if (mIsExifDataOnly) {
+                    getStandaloneAttributes(inputStream);
+                } else {
+                    if (mMimeType == IMAGE_TYPE_HEIF) {
                         getHeifAttributes(inputStream);
-                        break;
-                    }
-                    case IMAGE_TYPE_ORF: {
+                    } else if (mMimeType == IMAGE_TYPE_ORF) {
                         getOrfAttributes(inputStream);
-                        break;
-                    }
-                    case IMAGE_TYPE_RW2: {
+                    } else if (mMimeType == IMAGE_TYPE_RW2) {
                         getRw2Attributes(inputStream);
-                        return;
-                    }
-                    case IMAGE_TYPE_PNG: {
-                        getPngAttributes(inputStream);
-                        return;
-                    }
-                    case IMAGE_TYPE_WEBP: {
-                        getWebpAttributes(inputStream);
-                        return;
-                    }
-                    case IMAGE_TYPE_ARW:
-                    case IMAGE_TYPE_CR2:
-                    case IMAGE_TYPE_DNG:
-                    case IMAGE_TYPE_NEF:
-                    case IMAGE_TYPE_NRW:
-                    case IMAGE_TYPE_PEF:
-                    case IMAGE_TYPE_SRW:
-                    case IMAGE_TYPE_UNKNOWN: {
+                    } else {
                         getRawAttributes(inputStream);
-                        break;
                     }
                 }
+                // Set thumbnail image offset and length
+                inputStream.seek(mOffsetToExifData);
+                setThumbnailData(inputStream);
             } else {
-                getStandaloneAttributes(inputStream);
+                ByteOrderedDataInputStream inputStream = new ByteOrderedDataInputStream(in);
+                if (mMimeType == IMAGE_TYPE_JPEG) {
+                    getJpegAttributes(inputStream, /* offsetToJpeg= */ 0,
+                            IFD_TYPE_PRIMARY);
+                } else if (mMimeType == IMAGE_TYPE_PNG) {
+                    getPngAttributes(inputStream);
+                } else if (mMimeType == IMAGE_TYPE_RAF) {
+                    getRafAttributes(inputStream);
+                } else if (mMimeType == IMAGE_TYPE_WEBP) {
+                    getWebpAttributes(inputStream);
+                }
             }
-            // Set thumbnail image offset and length
-            inputStream.seek(mOffsetToExifData);
-            setThumbnailData(inputStream);
         } catch (IOException | UnsupportedOperationException e) {
             // Ignore exceptions in order to keep the compatibility with the old versions of
             // ExifInterface.
@@ -5353,7 +5336,6 @@
 
     // Checks the type of image file
     private int getMimeType(BufferedInputStream in) throws IOException {
-        // TODO (b/142218289): Need to handle case where input stream does not support mark
         in.mark(SIGNATURE_CHECK_SIZE);
         byte[] signatureCheckBytes = new byte[SIGNATURE_CHECK_SIZE];
         in.read(signatureCheckBytes);
@@ -5597,10 +5579,6 @@
         if (DEBUG) {
             Log.d(TAG, "getJpegAttributes starting with: " + in);
         }
-        // Do not buffer any bytes from this input stream since we don't need to rewind to an
-        // earlier position.
-        in.mark(0);
-
         // JPEG uses Big Endian by default. See https://people.cs.umass.edu/~verts/cs32/endian.html
         in.setByteOrder(ByteOrder.BIG_ENDIAN);
 
@@ -5701,9 +5679,7 @@
                 case MARKER_SOF13:
                 case MARKER_SOF14:
                 case MARKER_SOF15: {
-                    if (in.skipBytes(1) != 1) {
-                        throw new IOException("Invalid SOFx");
-                    }
+                    in.skipFully(1);
                     mAttributes[imageType].put(TAG_IMAGE_LENGTH, ExifAttribute.createULong(
                             in.readUnsignedShort(), mExifByteOrder));
                     mAttributes[imageType].put(TAG_IMAGE_WIDTH, ExifAttribute.createULong(
@@ -5719,18 +5695,16 @@
             if (length < 0) {
                 throw new IOException("Invalid length");
             }
-            if (in.skipBytes(length) != length) {
-                throw new IOException("Invalid JPEG segment");
-            }
+            in.skipFully(length);
             bytesRead += length;
         }
         // Restore original byte order
         in.setByteOrder(mExifByteOrder);
     }
 
-    private void getRawAttributes(ByteOrderedDataInputStream in) throws IOException {
+    private void getRawAttributes(SeekableByteOrderedDataInputStream in) throws IOException {
         // Parse TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1.
-        parseTiffHeaders(in, in.available());
+        parseTiffHeaders(in);
 
         // Read TIFF image file directories. See JEITA CP-3451C Section 4.5.2. Figure 6.
         readImageFileDirectory(in, IFD_TYPE_PRIMARY);
@@ -5750,12 +5724,12 @@
                     (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_MAKER_NOTE);
             if (makerNoteAttribute != null) {
                 // Create an ordered DataInputStream for MakerNote
-                ByteOrderedDataInputStream makerNoteDataInputStream =
-                        new ByteOrderedDataInputStream(makerNoteAttribute.bytes);
+                SeekableByteOrderedDataInputStream makerNoteDataInputStream =
+                        new SeekableByteOrderedDataInputStream(makerNoteAttribute.bytes);
                 makerNoteDataInputStream.setByteOrder(mExifByteOrder);
 
-                // Seek to MakerNote data
-                makerNoteDataInputStream.seek(PEF_MAKER_NOTE_SKIP_SIZE);
+                // Skip to MakerNote data
+                makerNoteDataInputStream.skipFully(PEF_MAKER_NOTE_SKIP_SIZE);
 
                 // Read IFD data from MakerNote
                 readImageFileDirectory(makerNoteDataInputStream, IFD_TYPE_PEF);
@@ -5783,11 +5757,8 @@
         if (DEBUG) {
             Log.d(TAG, "getRafAttributes starting with: " + in);
         }
-        // Do not buffer any bytes from this input stream since we don't need to rewind to an
-        // earlier position.
-        in.mark(0);
         // Retrieve offset & length values
-        in.skipBytes(RAF_OFFSET_TO_JPEG_IMAGE_OFFSET);
+        in.skipFully(RAF_OFFSET_TO_JPEG_IMAGE_OFFSET);
         byte[] offsetToJpegBytes = new byte[4];
         byte[] jpegLengthBytes = new byte[4];
         byte[] cfaHeaderOffsetBytes = new byte[4];
@@ -5799,7 +5770,7 @@
         int cfaHeaderOffset = ByteBuffer.wrap(cfaHeaderOffsetBytes).getInt();
 
         byte[] jpegBytes = new byte[jpegLength];
-        in.seek(offsetToJpeg);
+        in.skipFully(offsetToJpeg - in.position());
         in.read(jpegBytes);
 
         // Retrieve JPEG image metadata
@@ -5807,7 +5778,7 @@
         getJpegAttributes(jpegInputStream, offsetToJpeg, IFD_TYPE_PREVIEW);
 
         // Skip to CFA header offset.
-        in.seek(cfaHeaderOffset);
+        in.skipFully(cfaHeaderOffset - in.position());
 
         // Retrieve primary image length/width values, if TAG_RAF_IMAGE_SIZE exists
         in.setByteOrder(ByteOrder.BIG_ENDIAN);
@@ -5835,13 +5806,13 @@
                 }
                 return;
             }
-            in.skipBytes(numberOfBytes);
+            in.skipFully(numberOfBytes);
         }
     }
 
     // Support for getting MediaMetadataRetriever.METADATA_KEY_EXIF_OFFSET and
     // MediaMetadataRetriever.METADATA_KEY_EXIF_LENGTH was added SDK 28.
-    private void getHeifAttributes(final ByteOrderedDataInputStream in) throws IOException {
+    private void getHeifAttributes(final SeekableByteOrderedDataInputStream in) throws IOException {
         if (Build.VERSION.SDK_INT >= 28) {
             MediaMetadataRetriever retriever = new MediaMetadataRetriever();
             try {
@@ -5999,8 +5970,8 @@
         }
     }
 
-    private void getStandaloneAttributes(ByteOrderedDataInputStream in) throws IOException {
-        in.skipBytes(IDENTIFIER_EXIF_APP1.length);
+    private void getStandaloneAttributes(SeekableByteOrderedDataInputStream in) throws IOException {
+        in.skipFully(IDENTIFIER_EXIF_APP1.length);
         // TODO: Need to handle potential OutOfMemoryError
         byte[] data = new byte[in.available()];
         in.readFully(data);
@@ -6019,7 +5990,7 @@
      * http://fileformats.archiveteam.org/wiki/Olympus_ORF
      * https://libopenraw.freedesktop.org/wiki/Olympus_ORF
      */
-    private void getOrfAttributes(ByteOrderedDataInputStream in) throws IOException {
+    private void getOrfAttributes(SeekableByteOrderedDataInputStream in) throws IOException {
         // Retrieve primary image data
         // Other Exif data will be located in the Makernote.
         getRawAttributes(in);
@@ -6031,8 +6002,8 @@
                 (ExifAttribute) mAttributes[IFD_TYPE_EXIF].get(TAG_MAKER_NOTE);
         if (makerNoteAttribute != null) {
             // Create an ordered DataInputStream for MakerNote
-            ByteOrderedDataInputStream makerNoteDataInputStream =
-                    new ByteOrderedDataInputStream(makerNoteAttribute.bytes);
+            SeekableByteOrderedDataInputStream makerNoteDataInputStream =
+                    new SeekableByteOrderedDataInputStream(makerNoteAttribute.bytes);
             makerNoteDataInputStream.setByteOrder(mExifByteOrder);
 
             // There are two types of headers for Olympus MakerNotes
@@ -6102,7 +6073,7 @@
     // RW2 contains the primary image data in IFD0 and the preview and/or thumbnail image data in
     // the JpgFromRaw tag
     // See https://libopenraw.freedesktop.org/wiki/Panasonic_RAW/ and piex.cc Rw2GetPreviewData()
-    private void getRw2Attributes(ByteOrderedDataInputStream in) throws IOException {
+    private void getRw2Attributes(SeekableByteOrderedDataInputStream in) throws IOException {
         if (DEBUG) {
             Log.d(TAG, "getRw2Attributes starting with: " + in);
         }
@@ -6135,10 +6106,6 @@
         if (DEBUG) {
             Log.d(TAG, "getPngAttributes starting with: " + in);
         }
-        // Do not buffer any bytes from this input stream since we don't need to rewind to an
-        // earlier position.
-        in.mark(0);
-
         // PNG uses Big Endian by default.
         // See PNG (Portable Network Graphics) Specification, Version 1.2,
         // 2.1. Integers and byte order
@@ -6147,7 +6114,7 @@
         int bytesRead = 0;
 
         // Skip the signature bytes
-        in.skipBytes(PNG_SIGNATURE.length);
+        in.skipFully(PNG_SIGNATURE.length);
         bytesRead += PNG_SIGNATURE.length;
 
         // Each chunk is made up of four parts:
@@ -6209,7 +6176,7 @@
                     break;
                 } else {
                     // Skip to next chunk
-                    in.skipBytes(length + PNG_CHUNK_CRC_BYTE_LENGTH);
+                    in.skipFully(length + PNG_CHUNK_CRC_BYTE_LENGTH);
                     bytesRead += length + PNG_CHUNK_CRC_BYTE_LENGTH;
                 }
             }
@@ -6227,20 +6194,18 @@
         if (DEBUG) {
             Log.d(TAG, "getWebpAttributes starting with: " + in);
         }
-        // Do not buffer any bytes from this input stream since we don't need to rewind to an
-        // earlier position.
-        in.mark(0);
-
         // WebP uses little-endian by default.
         // See Section "Terminology & Basics"
         in.setByteOrder(ByteOrder.LITTLE_ENDIAN);
 
-        in.skipBytes(WEBP_SIGNATURE_1.length);
+        in.skipFully(WEBP_SIGNATURE_1.length);
         // File size corresponds to the size of the entire file from offset 8.
         // See Section "WebP File Header"
         int fileSize = in.readInt() + 8;
         int bytesRead = 8;
-        bytesRead += in.skipBytes(WEBP_SIGNATURE_2.length);
+
+        in.skipFully(WEBP_SIGNATURE_2.length);
+        bytesRead += WEBP_SIGNATURE_2.length;
 
         try {
             while (true) {
@@ -6290,11 +6255,8 @@
                     }
 
                     // Skip to next chunk
-                    int skipped = in.skipBytes(chunkSize);
-                    if (skipped != chunkSize) {
-                        throw new IOException("Encountered WebP file with invalid chunk size");
-                    }
-                    bytesRead += skipped;
+                    in.skipFully(chunkSize);
+                    bytesRead += chunkSize;
                 }
             }
         } catch (EOFException e) {
@@ -6312,7 +6274,7 @@
             Log.d(TAG, "saveJpegAttributes starting with (inputStream: " + inputStream
                     + ", outputStream: " + outputStream + ")");
         }
-        DataInputStream dataInputStream = new DataInputStream(inputStream);
+        ByteOrderedDataInputStream dataInputStream = new ByteOrderedDataInputStream(inputStream);
         ByteOrderedDataOutputStream dataOutputStream =
                 new ByteOrderedDataOutputStream(outputStream, ByteOrder.BIG_ENDIAN);
         if (dataInputStream.readByte() != MARKER) {
@@ -6363,9 +6325,7 @@
                         }
                         if (Arrays.equals(identifier, IDENTIFIER_EXIF_APP1)) {
                             // Skip the original EXIF APP1 segment.
-                            if (dataInputStream.skipBytes(length - 6) != length - 6) {
-                                throw new IOException("Invalid length");
-                            }
+                            dataInputStream.skipFully(length - 6);
                             break;
                         }
                     }
@@ -6421,7 +6381,7 @@
             Log.d(TAG, "savePngAttributes starting with (inputStream: " + inputStream
                     + ", outputStream: " + outputStream + ")");
         }
-        DataInputStream dataInputStream = new DataInputStream(inputStream);
+        ByteOrderedDataInputStream dataInputStream = new ByteOrderedDataInputStream(inputStream);
         ByteOrderedDataOutputStream dataOutputStream =
                 new ByteOrderedDataOutputStream(outputStream, ByteOrder.BIG_ENDIAN);
 
@@ -6449,7 +6409,7 @@
 
             // Skip to the start of the chunk after the EXIF chunk
             int exifChunkLength = dataInputStream.readInt();
-            dataInputStream.skipBytes(PNG_CHUNK_TYPE_BYTE_LENGTH + exifChunkLength
+            dataInputStream.skipFully(PNG_CHUNK_TYPE_BYTE_LENGTH + exifChunkLength
                     + PNG_CHUNK_CRC_BYTE_LENGTH);
         }
 
@@ -6529,7 +6489,7 @@
         // WebP signature
         copy(totalInputStream, totalOutputStream, WEBP_SIGNATURE_1.length);
         // File length will be written after all the chunks have been written
-        totalInputStream.skipBytes(WEBP_FILE_SIZE_BYTE_LENGTH + WEBP_SIGNATURE_2.length);
+        totalInputStream.skipFully(WEBP_FILE_SIZE_BYTE_LENGTH + WEBP_SIGNATURE_2.length);
 
         // Create a separate byte array to calculate file length
         ByteArrayOutputStream nonHeaderByteArrayOutputStream = null;
@@ -6549,9 +6509,9 @@
                                 - WEBP_CHUNK_SIZE_BYTE_LENGTH);
 
                 // Skip input stream to the end of the EXIF chunk
-                totalInputStream.skipBytes(WEBP_CHUNK_TYPE_BYTE_LENGTH);
+                totalInputStream.skipFully(WEBP_CHUNK_TYPE_BYTE_LENGTH);
                 int exifChunkLength = totalInputStream.readInt();
-                totalInputStream.skipBytes(exifChunkLength);
+                totalInputStream.skipFully(exifChunkLength);
 
                 // Write new EXIF chunk to output stream
                 writeExifSegment(nonHeaderOutputStream);
@@ -6743,11 +6703,11 @@
 
     // Reads the given EXIF byte area and save its tag data into attributes.
     private void readExifSegment(byte[] exifBytes, int imageType) throws IOException {
-        ByteOrderedDataInputStream dataInputStream =
-                new ByteOrderedDataInputStream(exifBytes);
+        SeekableByteOrderedDataInputStream dataInputStream =
+                new SeekableByteOrderedDataInputStream(exifBytes);
 
         // Parse TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1.
-        parseTiffHeaders(dataInputStream, exifBytes.length);
+        parseTiffHeaders(dataInputStream);
 
         // Read TIFF image file directories. See JEITA CP-3451C Section 4.5.2. Figure 6.
         readImageFileDirectory(dataInputStream, imageType);
@@ -6800,8 +6760,7 @@
         }
     }
 
-    private void parseTiffHeaders(ByteOrderedDataInputStream dataInputStream,
-            int exifBytesLength) throws IOException {
+    private void parseTiffHeaders(ByteOrderedDataInputStream dataInputStream) throws IOException {
         // Read byte order
         mExifByteOrder = readByteOrder(dataInputStream);
         // Set byte order
@@ -6815,35 +6774,28 @@
 
         // Read and skip to first ifd offset
         int firstIfdOffset = dataInputStream.readInt();
-        if (firstIfdOffset < 8 || firstIfdOffset >= exifBytesLength) {
+        if (firstIfdOffset < 8) {
             throw new IOException("Invalid first Ifd offset: " + firstIfdOffset);
         }
         firstIfdOffset -= 8;
         if (firstIfdOffset > 0) {
-            if (dataInputStream.skipBytes(firstIfdOffset) != firstIfdOffset) {
-                throw new IOException("Couldn't jump to first Ifd: " + firstIfdOffset);
-            }
+            dataInputStream.skipFully(firstIfdOffset);
         }
     }
 
     // Reads image file directory, which is a tag group in EXIF.
-    private void readImageFileDirectory(ByteOrderedDataInputStream dataInputStream,
+    private void readImageFileDirectory(SeekableByteOrderedDataInputStream dataInputStream,
             @IfdType int ifdType) throws IOException {
         // Save offset of current IFD to prevent reading an IFD that is already read.
         mAttributesOffsets.add(dataInputStream.mPosition);
 
-        if (dataInputStream.mPosition + 2 > dataInputStream.mLength) {
-            // Return if there is no data from the offset.
-            return;
-        }
         // See TIFF 6.0 Section 2: TIFF Structure, Figure 1.
         short numberOfDirectoryEntry = dataInputStream.readShort();
         if (DEBUG) {
             Log.d(TAG, "numberOfDirectoryEntry: " + numberOfDirectoryEntry);
         }
-        if (dataInputStream.mPosition + 12 * numberOfDirectoryEntry > dataInputStream.mLength
-                || numberOfDirectoryEntry <= 0) {
-            // Return if the size of entries is either too big or negative.
+        if (numberOfDirectoryEntry <= 0) {
+            // Return if the size of entries is negative.
             return;
         }
 
@@ -6853,7 +6805,7 @@
             int dataFormat = dataInputStream.readUnsignedShort();
             int numberOfComponents = dataInputStream.readInt();
             // Next four bytes is for data offset or value.
-            long nextEntryOffset = dataInputStream.peek() + 4L;
+            long nextEntryOffset = dataInputStream.position() + 4L;
 
             // Look up a corresponding tag from tag number
             ExifTag tag = (ExifTag) sExifTagMapsForReading[ifdType].get(tagNumber);
@@ -6930,16 +6882,7 @@
                                 jpegInterchangeFormatLengthAttribute);
                     }
                 }
-                if (offset + byteCount <= dataInputStream.mLength) {
-                    dataInputStream.seek(offset);
-                } else {
-                    // Skip if invalid data offset.
-                    if (DEBUG) {
-                        Log.d(TAG, "Skip the tag entry since data offset is invalid: " + offset);
-                    }
-                    dataInputStream.seek(nextEntryOffset);
-                    continue;
-                }
+                dataInputStream.seek(offset);
             }
 
             // Recursively parse IFD when a IFD pointer tag appears.
@@ -6979,9 +6922,9 @@
                 }
 
                 // Check if the next IFD offset
-                // 1. Exists within the boundaries of the input stream
+                // 1. Is a non-negative value, and
                 // 2. Does not point to a previously read IFD.
-                if (offset > 0L && offset < dataInputStream.mLength) {
+                if (offset > 0L) {
                     if (!mAttributesOffsets.contains((int) offset)) {
                         dataInputStream.seek(offset);
                         readImageFileDirectory(dataInputStream, nextIfdType);
@@ -7001,7 +6944,7 @@
                 continue;
             }
 
-            final int bytesOffset = dataInputStream.peek() + mOffsetToExifData;
+            final int bytesOffset = dataInputStream.position() + mOffsetToExifData;
             final byte[] bytes = new byte[(int) byteCount];
             dataInputStream.readFully(bytes);
             ExifAttribute attribute = new ExifAttribute(dataFormat, numberOfComponents,
@@ -7026,40 +6969,38 @@
             }
 
             // Seek to next tag offset
-            if (dataInputStream.peek() != nextEntryOffset) {
+            if (dataInputStream.position() != nextEntryOffset) {
                 dataInputStream.seek(nextEntryOffset);
             }
         }
 
-        if (dataInputStream.peek() + 4 <= dataInputStream.mLength) {
-            int nextIfdOffset = dataInputStream.readInt();
-            if (DEBUG) {
-                Log.d(TAG, String.format("nextIfdOffset: %d", nextIfdOffset));
-            }
-            // Check if the next IFD offset
-            // 1. Exists within the boundaries of the input stream
-            // 2. Does not point to a previously read IFD.
-            if (nextIfdOffset > 0L && nextIfdOffset < dataInputStream.mLength) {
-                if (!mAttributesOffsets.contains(nextIfdOffset)) {
-                    dataInputStream.seek(nextIfdOffset);
-                    if (mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) {
-                        // Do not overwrite thumbnail IFD data if it alreay exists.
-                        readImageFileDirectory(dataInputStream, IFD_TYPE_THUMBNAIL);
-                    } else if (mAttributes[IFD_TYPE_PREVIEW].isEmpty()) {
-                        readImageFileDirectory(dataInputStream, IFD_TYPE_PREVIEW);
-                    }
-                } else {
-                    if (DEBUG) {
-                        Log.d(TAG, "Stop reading file since re-reading an IFD may cause an "
-                                + "infinite loop: " + nextIfdOffset);
-                    }
+        int nextIfdOffset = dataInputStream.readInt();
+        if (DEBUG) {
+            Log.d(TAG, String.format("nextIfdOffset: %d", nextIfdOffset));
+        }
+        // Check if the next IFD offset
+        // 1. Is a non-negative value, and
+        // 2. Does not point to a previously read IFD.
+        if (nextIfdOffset > 0L) {
+            if (!mAttributesOffsets.contains(nextIfdOffset)) {
+                dataInputStream.seek(nextIfdOffset);
+                if (mAttributes[IFD_TYPE_THUMBNAIL].isEmpty()) {
+                    // Do not overwrite thumbnail IFD data if it already exists.
+                    readImageFileDirectory(dataInputStream, IFD_TYPE_THUMBNAIL);
+                } else if (mAttributes[IFD_TYPE_PREVIEW].isEmpty()) {
+                    readImageFileDirectory(dataInputStream, IFD_TYPE_PREVIEW);
                 }
             } else {
                 if (DEBUG) {
-                    Log.d(TAG, "Stop reading file since a wrong offset may cause an infinite loop: "
-                            + nextIfdOffset);
+                    Log.d(TAG, "Stop reading file since re-reading an IFD may cause an "
+                            + "infinite loop: " + nextIfdOffset);
                 }
             }
+        } else {
+            if (DEBUG) {
+                Log.d(TAG, "Stop reading file since a wrong offset may cause an infinite loop: "
+                        + nextIfdOffset);
+            }
         }
     }
 
@@ -7069,7 +7010,7 @@
      * to locate SOF(Start of Frame) marker and update the image length & width values.
      * See JEITA CP-3451C Table 5 and Section 4.8.1. B.
      */
-    private void retrieveJpegImageSize(ByteOrderedDataInputStream in, int imageType)
+    private void retrieveJpegImageSize(SeekableByteOrderedDataInputStream in, int imageType)
             throws IOException {
         // Check if image already has IMAGE_LENGTH & IMAGE_WIDTH values
         ExifAttribute imageLengthAttribute =
@@ -7145,8 +7086,6 @@
                 // Update offset value since RAF files have IFD data preceding MakerNote data.
                 thumbnailOffset += mOrfMakerNoteOffset;
             }
-            // The following code limits the size of thumbnail size not to overflow EXIF data area.
-            thumbnailLength = Math.min(thumbnailLength, in.getLength() - thumbnailOffset);
 
             if (thumbnailOffset > 0 && thumbnailLength > 0) {
                 mHasThumbnail = true;
@@ -7348,7 +7287,7 @@
      * If image is a RW2 file, valid image sizes are stored in SensorBorder tags.
      * See tiff_parser.cc GetFullDimension32()
      * */
-    private void updateImageSizeValues(ByteOrderedDataInputStream in, int imageType)
+    private void updateImageSizeValues(SeekableByteOrderedDataInputStream in, int imageType)
             throws IOException {
         // Uncompressed image valid image size values
         ExifAttribute defaultCropSizeAttribute =
@@ -7695,56 +7634,79 @@
         return new Pair<>(IFD_FORMAT_STRING, -1);
     }
 
-    // An input stream to parse EXIF data area, which can be written in either little or big endian
-    // order.
+    // An input stream class that can parse both little and big endian order data and also
+    // supports seeking to any position in the stream via mark/reset.
+    private static class SeekableByteOrderedDataInputStream extends ByteOrderedDataInputStream {
+        SeekableByteOrderedDataInputStream(byte[] bytes) throws IOException {
+            super(bytes);
+            // No need to check if mark is supported here since ByteOrderedDataInputStream will
+            // create a ByteArrayInputStream, which supports mark by default.
+            mDataInputStream.mark(Integer.MAX_VALUE);
+        }
+
+        /**
+         * Given input stream should support mark/reset, and should be set to the beginning of
+         * the stream.
+         */
+        SeekableByteOrderedDataInputStream(InputStream in) throws IOException {
+            super(in);
+            if (!in.markSupported()) {
+                throw new IllegalArgumentException("Cannot create "
+                        + "SeekableByteOrderedDataInputStream with stream that does not support "
+                        + "mark/reset");
+            }
+            // Mark given InputStream to the maximum value (we can't know the length of the
+            // stream for certain) so that InputStream.reset() may be called at any point in the
+            // stream to reset the stream to an earlier position.
+            mDataInputStream.mark(Integer.MAX_VALUE);
+        }
+
+        /**
+         * Seek to the given absolute position in the stream (i.e. the number of bytes from the
+         * beginning of the stream).
+         */
+        public void seek(long position) throws IOException {
+            if (mPosition > position) {
+                mPosition = 0;
+                mDataInputStream.reset();
+            } else {
+                position -= mPosition;
+            }
+            skipFully((int) position);
+        }
+    }
+
+    // An input stream class that can parse both little and big endian order data.
     private static class ByteOrderedDataInputStream extends InputStream implements DataInput {
         private static final ByteOrder LITTLE_ENDIAN = ByteOrder.LITTLE_ENDIAN;
         private static final ByteOrder BIG_ENDIAN = ByteOrder.BIG_ENDIAN;
 
-        private DataInputStream mDataInputStream;
+        final DataInputStream mDataInputStream;
         private ByteOrder mByteOrder = ByteOrder.BIG_ENDIAN;
         @SuppressWarnings("WeakerAccess") /* synthetic access */
-        final int mLength;
-        @SuppressWarnings("WeakerAccess") /* synthetic access */
         int mPosition;
+        private byte[] mSkipBuffer;
 
-        public ByteOrderedDataInputStream(InputStream in) throws IOException {
+        ByteOrderedDataInputStream(byte[] bytes) throws IOException {
+            this(new ByteArrayInputStream(bytes), ByteOrder.BIG_ENDIAN);
+        }
+
+        ByteOrderedDataInputStream(InputStream in) throws IOException {
             this(in, ByteOrder.BIG_ENDIAN);
         }
 
         ByteOrderedDataInputStream(InputStream in, ByteOrder byteOrder) throws IOException {
             mDataInputStream = new DataInputStream(in);
-            mLength = mDataInputStream.available();
+            mDataInputStream.mark(0);
             mPosition = 0;
-            // TODO (b/142218289): Need to handle case where input stream does not support mark
-            mDataInputStream.mark(mLength);
             mByteOrder = byteOrder;
         }
 
-        public ByteOrderedDataInputStream(byte[] bytes) throws IOException {
-            this(new ByteArrayInputStream(bytes));
-        }
-
         public void setByteOrder(ByteOrder byteOrder) {
             mByteOrder = byteOrder;
         }
 
-        public void seek(long byteCount) throws IOException {
-            if (mPosition > byteCount) {
-                mPosition = 0;
-                mDataInputStream.reset();
-                // TODO (b/142218289): Need to handle case where input stream does not support mark
-                mDataInputStream.mark(mLength);
-            } else {
-                byteCount -= mPosition;
-            }
-
-            if (skipBytes((int) byteCount) != (int) byteCount) {
-                throw new IOException("Couldn't seek up to the byteCount");
-            }
-        }
-
-        public int peek() {
+        public int position() {
             return mPosition;
         }
 
@@ -7799,31 +7761,18 @@
         @Override
         public void readFully(byte[] buffer, int offset, int length) throws IOException {
             mPosition += length;
-            if (mPosition > mLength) {
-                throw new EOFException();
-            }
-            if (mDataInputStream.read(buffer, offset, length) != length) {
-                throw new IOException("Couldn't read up to the length of buffer");
-            }
+            mDataInputStream.readFully(buffer, offset, length);
         }
 
         @Override
         public void readFully(byte[] buffer) throws IOException {
             mPosition += buffer.length;
-            if (mPosition > mLength) {
-                throw new EOFException();
-            }
-            if (mDataInputStream.read(buffer, 0, buffer.length) != buffer.length) {
-                throw new IOException("Couldn't read up to the length of buffer");
-            }
+            mDataInputStream.readFully(buffer);
         }
 
         @Override
         public byte readByte() throws IOException {
             ++mPosition;
-            if (mPosition > mLength) {
-                throw new EOFException();
-            }
             int ch = mDataInputStream.read();
             if (ch < 0) {
                 throw new EOFException();
@@ -7834,9 +7783,6 @@
         @Override
         public short readShort() throws IOException {
             mPosition += 2;
-            if (mPosition > mLength) {
-                throw new EOFException();
-            }
             int ch1 = mDataInputStream.read();
             int ch2 = mDataInputStream.read();
             if ((ch1 | ch2) < 0) {
@@ -7853,9 +7799,6 @@
         @Override
         public int readInt() throws IOException {
             mPosition += 4;
-            if (mPosition > mLength) {
-                throw new EOFException();
-            }
             int ch1 = mDataInputStream.read();
             int ch2 = mDataInputStream.read();
             int ch3 = mDataInputStream.read();
@@ -7872,27 +7815,36 @@
         }
 
         @Override
-        public int skipBytes(int byteCount) throws IOException {
-            int totalBytesToSkip = Math.min(byteCount, mLength - mPosition);
+        public int skipBytes(int n) throws IOException {
+            throw new UnsupportedOperationException("skipBytes is currently unsupported");
+        }
+
+        /**
+         * Discards n bytes of data from the input stream. This method will block until either
+         * the full amount has been skipped or the end of the stream is reached, whichever happens
+         * first.
+         */
+        public void skipFully(int n) throws IOException {
             int totalSkipped = 0;
-            while (totalSkipped < totalBytesToSkip) {
-                int skipped = mDataInputStream.skipBytes(totalBytesToSkip - totalSkipped);
-                if (skipped > 0) {
-                    totalSkipped += skipped;
-                } else {
-                    break;
+            while (totalSkipped < n) {
+                int skipped = (int) mDataInputStream.skip(n - totalSkipped);
+                if (skipped <= 0) {
+                    if (mSkipBuffer == null) {
+                        mSkipBuffer = new byte[SKIP_BUFFER_SIZE];
+                    }
+                    int bytesToSkip = Math.min(SKIP_BUFFER_SIZE, n - totalSkipped);
+                    if ((skipped = mDataInputStream.read(mSkipBuffer, 0, bytesToSkip)) == -1) {
+                        throw new EOFException("Reached EOF while skipping " + n + " bytes.");
+                    }
                 }
+                totalSkipped += skipped;
             }
             mPosition += totalSkipped;
-            return totalSkipped;
         }
 
         @Override
         public int readUnsignedShort() throws IOException {
             mPosition += 2;
-            if (mPosition > mLength) {
-                throw new EOFException();
-            }
             int ch1 = mDataInputStream.read();
             int ch2 = mDataInputStream.read();
             if ((ch1 | ch2) < 0) {
@@ -7913,9 +7865,6 @@
         @Override
         public long readLong() throws IOException {
             mPosition += 8;
-            if (mPosition > mLength) {
-                throw new EOFException();
-            }
             int ch1 = mDataInputStream.read();
             int ch2 = mDataInputStream.read();
             int ch3 = mDataInputStream.read();
@@ -7950,12 +7899,13 @@
         }
 
         @Override
-        public synchronized void mark(int readlimit) {
-            mDataInputStream.mark(readlimit);
+        public void mark(int readlimit) {
+            throw new UnsupportedOperationException("Mark is currently unsupported");
         }
 
-        public int getLength() {
-            return mLength;
+        @Override
+        public void reset() {
+            throw new UnsupportedOperationException("Reset is currently unsupported");
         }
     }
 
@@ -8065,34 +8015,24 @@
     }
 
     /**
-     * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null.
+     * Parsing EXIF data requires seek (moving to any position in the stream), so all MIME
+     * types should support seek via mark/reset, unless the MIME type specifies the position and
+     * length of the EXIF data and the EXIF data can be read from the file and wrapped with a
+     * ByteArrayInputStream.
      */
-    private static void closeQuietly(Closeable closeable) {
-        if (closeable != null) {
-            try {
-                closeable.close();
-            } catch (RuntimeException rethrown) {
-                throw rethrown;
-            } catch (Exception ignored) {
-            }
+    private static boolean shouldSupportSeek(int mimeType) {
+        if (mimeType == IMAGE_TYPE_JPEG || mimeType == IMAGE_TYPE_RAF || mimeType == IMAGE_TYPE_PNG
+                || mimeType == IMAGE_TYPE_WEBP) {
+            return false;
         }
+        return true;
     }
 
-    /**
-     * Closes a file descriptor that has been duplicated.
-     */
-    private static void closeFileDescriptor(FileDescriptor fd) {
-        // Os.dup and Os.close was introduced in API 21 so this method shouldn't be called
-        // in API < 21.
-        if (Build.VERSION.SDK_INT >= 21) {
-            try {
-                Os.close(fd);
-                // Catching ErrnoException will raise error in API < 21
-            } catch (Exception ex) {
-                Log.e(TAG, "Error closing fd.");
-            }
-        } else {
-            Log.e(TAG, "closeFileDescriptor is called in API < 21, which must be wrong.");
+    private static boolean isSupportedFormatForSavingAttributes(int mimeType) {
+        if (mimeType == IMAGE_TYPE_JPEG || mimeType == IMAGE_TYPE_PNG
+                || mimeType == IMAGE_TYPE_WEBP) {
+            return true;
         }
+        return false;
     }
 }
diff --git a/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterfaceUtils.java b/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterfaceUtils.java
index 8c3390d..d5cc058 100644
--- a/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterfaceUtils.java
+++ b/exifinterface/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterfaceUtils.java
@@ -16,10 +16,12 @@
 
 package androidx.exifinterface.media;
 
-import static androidx.exifinterface.media.ExifInterface.IMAGE_TYPE_JPEG;
-import static androidx.exifinterface.media.ExifInterface.IMAGE_TYPE_PNG;
-import static androidx.exifinterface.media.ExifInterface.IMAGE_TYPE_WEBP;
+import android.os.Build;
+import android.system.Os;
+import android.util.Log;
 
+import java.io.Closeable;
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -97,14 +99,6 @@
         return true;
     }
 
-    static boolean isSupportedFormatForSavingAttributes(int mimeType) {
-        if (mimeType == IMAGE_TYPE_JPEG || mimeType == IMAGE_TYPE_PNG
-                || mimeType == IMAGE_TYPE_WEBP) {
-            return true;
-        }
-        return false;
-    }
-
     static String byteArrayToHexString(byte[] bytes) {
         StringBuilder sb = new StringBuilder(bytes.length * 2);
         for (int i = 0; i < bytes.length; i++) {
@@ -126,4 +120,37 @@
         }
         return 0L;
     }
+
+
+    /**
+     * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null.
+     */
+    static void closeQuietly(Closeable closeable) {
+        if (closeable != null) {
+            try {
+                closeable.close();
+            } catch (RuntimeException rethrown) {
+                throw rethrown;
+            } catch (Exception ignored) {
+            }
+        }
+    }
+
+    /**
+     * Closes a file descriptor that has been duplicated.
+     */
+    static void closeFileDescriptor(FileDescriptor fd) {
+        // Os.dup and Os.close was introduced in API 21 so this method shouldn't be called
+        // in API < 21.
+        if (Build.VERSION.SDK_INT >= 21) {
+            try {
+                Os.close(fd);
+                // Catching ErrnoException will raise error in API < 21
+            } catch (Exception ex) {
+                Log.e(TAG, "Error closing fd.");
+            }
+        } else {
+            Log.e(TAG, "closeFileDescriptor is called in API < 21, which must be wrong.");
+        }
+    }
 }
diff --git a/fragment/fragment-ktx/src/main/java/androidx/fragment/app/Fragment.kt b/fragment/fragment-ktx/src/main/java/androidx/fragment/app/Fragment.kt
index f7a834d..f6514f4 100644
--- a/fragment/fragment-ktx/src/main/java/androidx/fragment/app/Fragment.kt
+++ b/fragment/fragment-ktx/src/main/java/androidx/fragment/app/Fragment.kt
@@ -27,8 +27,7 @@
  * requestKey.
  *
  * @param requestKey key used to identify the result
- * @param result the result to be passed to another fragment or `null` if you want to
- *               clear out any pending result.
+ * @param result the result to be passed to another fragment.
  */
 public fun Fragment.setFragmentResult(requestKey: String, result: Bundle) {
     parentFragmentManager.setFragmentResult(requestKey, result)
@@ -54,11 +53,10 @@
  * [setFragmentResult] using the same [requestKey] will be delivered to the
  * [FragmentResultListener.onFragmentResult] callback. The callback will remain active until this
  * Fragment reaches the [androidx.lifecycle.Lifecycle.State.DESTROYED] state or
- * [clearFragmentResultListener] is called with the same requestKey..
+ * [clearFragmentResultListener] is called with the same requestKey.
  *
  * @param requestKey requestKey used to store the result
- * @param listener listener for result changes or `null` to remove any previously
- *                 registered listener.
+ * @param listener listener for result changes.
  */
 public fun Fragment.setFragmentResultListener(
     requestKey: String,
diff --git a/fragment/fragment/api/current.txt b/fragment/fragment/api/current.txt
index a700d16..b850c56 100644
--- a/fragment/fragment/api/current.txt
+++ b/fragment/fragment/api/current.txt
@@ -427,6 +427,8 @@
     field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
     field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
     field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+    field public static final int TRANSIT_FRAGMENT_MATCH_ACTIVITY_CLOSE = 8197; // 0x2005
+    field public static final int TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN = 4100; // 0x1004
     field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
     field public static final int TRANSIT_NONE = 0; // 0x0
     field public static final int TRANSIT_UNSET = -1; // 0xffffffff
diff --git a/fragment/fragment/api/public_plus_experimental_current.txt b/fragment/fragment/api/public_plus_experimental_current.txt
index a2f6d9f..97a49c7 100644
--- a/fragment/fragment/api/public_plus_experimental_current.txt
+++ b/fragment/fragment/api/public_plus_experimental_current.txt
@@ -433,6 +433,8 @@
     field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
     field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
     field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+    field public static final int TRANSIT_FRAGMENT_MATCH_ACTIVITY_CLOSE = 8197; // 0x2005
+    field public static final int TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN = 4100; // 0x1004
     field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
     field public static final int TRANSIT_NONE = 0; // 0x0
     field public static final int TRANSIT_UNSET = -1; // 0xffffffff
diff --git a/fragment/fragment/api/restricted_current.txt b/fragment/fragment/api/restricted_current.txt
index 060b006..ab90399 100644
--- a/fragment/fragment/api/restricted_current.txt
+++ b/fragment/fragment/api/restricted_current.txt
@@ -435,6 +435,8 @@
     field public static final int TRANSIT_EXIT_MASK = 8192; // 0x2000
     field public static final int TRANSIT_FRAGMENT_CLOSE = 8194; // 0x2002
     field public static final int TRANSIT_FRAGMENT_FADE = 4099; // 0x1003
+    field public static final int TRANSIT_FRAGMENT_MATCH_ACTIVITY_CLOSE = 8197; // 0x2005
+    field public static final int TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN = 4100; // 0x1004
     field public static final int TRANSIT_FRAGMENT_OPEN = 4097; // 0x1001
     field public static final int TRANSIT_NONE = 0; // 0x0
     field public static final int TRANSIT_UNSET = -1; // 0xffffffff
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentSharedElementTransitionTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentSharedElementTransitionTest.kt
new file mode 100644
index 0000000..820b9762
--- /dev/null
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentSharedElementTransitionTest.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2021 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
+
+import android.os.Build
+import androidx.core.view.ViewCompat
+import androidx.fragment.app.test.FragmentTestActivity
+import androidx.fragment.test.R
+import androidx.test.core.app.ActivityScenario
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SdkSuppress
+import androidx.testutils.withActivity
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
+class FragmentSharedElementTransitionTest {
+
+    @Test
+    fun testNestedSharedElementView() {
+        with(ActivityScenario.launch(FragmentTestActivity::class.java)) {
+            val fragment = TransitionFragment(R.layout.nested_transition_groups)
+            withActivity {
+                supportFragmentManager
+                    .beginTransaction()
+                    .replace(R.id.content, fragment)
+                    .commit()
+            }
+
+            val squareContainer = withActivity { findViewById(R.id.squareContainer) }
+            var blueSquare = withActivity { findViewById(R.id.blueSquare) }
+
+            withActivity {
+                supportFragmentManager
+                    .beginTransaction()
+                    .addSharedElement(squareContainer, "squareContainer")
+                    .addSharedElement(blueSquare, "blueSquare")
+                    .replace(R.id.content, TransitionFragment(R.layout.nested_transition_groups))
+                    .commit()
+            }
+
+            blueSquare = withActivity { findViewById(R.id.blueSquare) }
+
+            assertThat(ViewCompat.getTransitionName(blueSquare)).isEqualTo("blueSquare")
+        }
+    }
+}
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitTest.kt
index 1ded023..0f9a36a 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentTransitTest.kt
@@ -18,6 +18,9 @@
 
 import android.animation.Animator
 import android.view.animation.Animation
+import androidx.annotation.LayoutRes
+import androidx.fragment.app.FragmentTransaction.TRANSIT_FRAGMENT_MATCH_ACTIVITY_CLOSE
+import androidx.fragment.app.FragmentTransaction.TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN
 import androidx.fragment.app.test.FragmentTestActivity
 import androidx.fragment.test.R
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -35,7 +38,6 @@
 @LargeTest
 @RunWith(AndroidJUnit4::class)
 class FragmentTransitTest {
-
     @Suppress("DEPRECATION")
     @get:Rule
     var activityRule = androidx.test.rule.ActivityTestRule(FragmentTestActivity::class.java)
@@ -62,11 +64,57 @@
             .containsExactly(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
     }
 
-    class TransitFragment : StrictViewFragment() {
+    @Test
+    fun testFragmentAnimationWithActivityTransition() {
+        val fragmentA = FragmentA()
+        val fragmentB = FragmentB()
+        val fm = activityRule.activity.supportFragmentManager
+
+        // set TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN to navigate forward when fragmentA entering.
+        fm.beginTransaction()
+            .add(R.id.fragmentContainer, fragmentA)
+            .setTransition(TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN)
+            .commit()
+        activityRule.executePendingTransactions(fm)
+
+        assertThat(fragmentA.transitValues).containsExactly(TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN)
+        assertThat(fragmentA.isEnterTransit).isTrue()
+
+        // set TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN to navigate forward when fragmentB entering
+        // and fragmentA exiting.
+        fm.beginTransaction()
+            .replace(R.id.fragmentContainer, fragmentB)
+            .setTransition(TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN)
+            .addToBackStack(null)
+            .commit()
+        activityRule.executePendingTransactions(fm)
+
+        assertThat(fragmentA.transitValues).containsExactly(TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN)
+        assertThat(fragmentA.isEnterTransit).isFalse()
+        assertThat(fragmentB.transitValues).containsExactly(TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN)
+        assertThat(fragmentB.isEnterTransit).isTrue()
+
+        // Simulating back key with popBackStack, system will set
+        // TRANSIT_FRAGMENT_MATCH_ACTIVITY_CLOSE to navigate backward when fragmentB exiting
+        // and fragmentA entering.
+        fm.popBackStack()
+        activityRule.executePendingTransactions(fm)
+
+        assertThat(fragmentB.transitValues).contains(TRANSIT_FRAGMENT_MATCH_ACTIVITY_CLOSE)
+        assertThat(fragmentB.isEnterTransit).isFalse()
+        assertThat(fragmentA.transitValues).contains(TRANSIT_FRAGMENT_MATCH_ACTIVITY_CLOSE)
+        assertThat(fragmentA.isEnterTransit).isTrue()
+    }
+
+    public open class TransitFragment(
+        @LayoutRes contentLayoutId: Int = R.layout.strict_view_fragment
+    ) : StrictFragment(contentLayoutId) {
         val transitValues = mutableSetOf<Int>()
+        var isEnterTransit: Boolean = false
 
         override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
             transitValues += transit
+            isEnterTransit = enter
             return super.onCreateAnimation(transit, enter, nextAnim)
         }
 
@@ -75,4 +123,8 @@
             return super.onCreateAnimator(transit, enter, nextAnim)
         }
     }
+
+    class FragmentA : TransitFragment(R.layout.fragment_a)
+
+    class FragmentB : TransitFragment(R.layout.fragment_b)
 }
diff --git a/fragment/fragment/src/androidTest/res/layout/nested_transition_groups.xml b/fragment/fragment/src/androidTest/res/layout/nested_transition_groups.xml
new file mode 100644
index 0000000..f6b90e9
--- /dev/null
+++ b/fragment/fragment/src/androidTest/res/layout/nested_transition_groups.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  Copyright 2021 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.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/squareContainer"
+    android:transitionName="squareContainer"
+    android:transitionGroup="false"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+        <View android:id="@+id/blueSquare"
+            android:transitionName="blueSquare"
+            android:layout_width="100dp"
+            android:layout_height="100dp"
+            android:background="#008"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java b/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java
index aa72c76..247065a 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/DefaultSpecialEffectsController.java
@@ -708,7 +708,9 @@
                 }
             }
         } else {
-            transitioningViews.add(view);
+            if (!transitioningViews.contains(view)) {
+                transitioningViews.add(view);
+            }
         }
     }
 
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentAnim.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentAnim.java
index 76f34ef..df536f1 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentAnim.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentAnim.java
@@ -21,6 +21,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.Animation;
@@ -60,6 +61,7 @@
         if (fragment.mContainer != null && fragment.mContainer.getLayoutTransition() != null) {
             return null;
         }
+
         Animation animation = fragment.onCreateAnimation(transit, enter, nextAnim);
         if (animation != null) {
             return new AnimationOrAnimator(animation);
@@ -71,10 +73,9 @@
         }
 
         if (nextAnim == 0 && transit != 0) {
-            nextAnim = transitToAnimResourceId(transit, enter);
+            nextAnim = transitToAnimResourceId(context, transit, enter);
         }
 
-
         if (nextAnim != 0) {
             String dir = context.getResources().getResourceTypeName(nextAnim);
             boolean isAnim = "anim".equals(dir);
@@ -195,7 +196,8 @@
     }
 
     @AnimRes
-    private static int transitToAnimResourceId(int transit, boolean enter) {
+    private static int transitToAnimResourceId(@NonNull Context context, int transit,
+            boolean enter) {
         int animAttr = -1;
         switch (transit) {
             case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
@@ -207,10 +209,32 @@
             case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
                 animAttr = enter ? R.animator.fragment_fade_enter : R.animator.fragment_fade_exit;
                 break;
+            case FragmentTransaction.TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN:
+                animAttr = enter
+                        ? toActivityTransitResId(context, android.R.attr.activityOpenEnterAnimation)
+                        : toActivityTransitResId(context, android.R.attr.activityOpenExitAnimation);
+                break;
+            case FragmentTransaction.TRANSIT_FRAGMENT_MATCH_ACTIVITY_CLOSE:
+                animAttr = enter
+                        ? toActivityTransitResId(context,
+                        android.R.attr.activityCloseEnterAnimation)
+                        : toActivityTransitResId(context,
+                                android.R.attr.activityCloseExitAnimation);
+                break;
         }
         return animAttr;
     }
 
+    @AnimRes
+    private static int toActivityTransitResId(@NonNull Context context, int attrInt) {
+        int resId;
+        TypedArray typedArray = context.obtainStyledAttributes(
+                android.R.style.Animation_Activity, new int[]{attrInt});
+        resId = typedArray.getResourceId(0, View.NO_ID);
+        typedArray.recycle();
+        return resId;
+    }
+
     /**
      * Contains either an animator or animation. One of these should be null.
      */
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
index 811156c..6abf46e 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -3618,6 +3618,12 @@
             case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
                 rev = FragmentTransaction.TRANSIT_FRAGMENT_FADE;
                 break;
+            case FragmentTransaction.TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN:
+                rev = FragmentTransaction.TRANSIT_FRAGMENT_MATCH_ACTIVITY_CLOSE;
+                break;
+            case FragmentTransaction.TRANSIT_FRAGMENT_MATCH_ACTIVITY_CLOSE:
+                rev = FragmentTransaction.TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN;
+                break;
         }
         return rev;
 
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java
index 0140639..b94e94c 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java
@@ -504,7 +504,8 @@
 
     /** @hide */
     @RestrictTo(LIBRARY_GROUP_PREFIX)
-    @IntDef({TRANSIT_NONE, TRANSIT_FRAGMENT_OPEN, TRANSIT_FRAGMENT_CLOSE, TRANSIT_FRAGMENT_FADE})
+    @IntDef({TRANSIT_NONE, TRANSIT_FRAGMENT_OPEN, TRANSIT_FRAGMENT_CLOSE, TRANSIT_FRAGMENT_FADE,
+            TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN, TRANSIT_FRAGMENT_MATCH_ACTIVITY_CLOSE})
     @Retention(RetentionPolicy.SOURCE)
     private @interface Transit {}
 
@@ -521,6 +522,22 @@
     public static final int TRANSIT_FRAGMENT_FADE = 3 | TRANSIT_ENTER_MASK;
 
     /**
+     * Fragment is being added onto the stack with Activity open transition.
+     *
+     * @see android.R.attr#activityOpenEnterAnimation
+     * @see android.R.attr#activityOpenExitAnimation
+     */
+    public static final int TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN = 4 | TRANSIT_ENTER_MASK;
+
+    /**
+     * Fragment is being removed from the stack with Activity close transition.
+     *
+     * @see android.R.attr#activityCloseEnterAnimation
+     * @see android.R.attr#activityCloseExitAnimation
+     */
+    public static final int TRANSIT_FRAGMENT_MATCH_ACTIVITY_CLOSE = 5 | TRANSIT_EXIT_MASK;
+
+    /**
      * Set specific animation resources to run for the fragments that are
      * entering and exiting in this transaction. These animations will not be
      * played when popping the back stack.
diff --git a/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/GenerateInspectionPlatformVersionTask.kt b/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/GenerateInspectionPlatformVersionTask.kt
new file mode 100644
index 0000000..3b0c043
--- /dev/null
+++ b/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/GenerateInspectionPlatformVersionTask.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2021 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.inspection.gradle
+
+import com.android.build.gradle.api.BaseVariant
+import org.gradle.api.DefaultTask
+import org.gradle.api.GradleException
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+import org.gradle.api.artifacts.component.ModuleComponentIdentifier
+import org.gradle.api.artifacts.component.ProjectComponentIdentifier
+import org.gradle.api.attributes.Attribute
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.tasks.Classpath
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.OutputDirectory
+import org.gradle.api.tasks.TaskAction
+import org.gradle.api.tasks.TaskProvider
+import java.io.File
+
+/**
+ * Generates a file into META-INF/ folder that has version of androidx.inspection used
+ * during complication. Android Studio checks compatibility of its version with version required
+ * by inspector.
+ */
+abstract class GenerateInspectionPlatformVersionTask : DefaultTask() {
+    @get:Classpath
+    abstract var compileConfiguration: Configuration
+
+    @get:OutputDirectory
+    abstract val outputDir: DirectoryProperty
+
+    @Input
+    fun getVersion(): String {
+        val artifacts = compileConfiguration.incoming.artifacts.artifacts
+        val projectDep = artifacts.any {
+            (it.id.componentIdentifier as? ProjectComponentIdentifier)?.projectPath ==
+                ":inspection:inspection"
+        }
+
+        val prebuiltVersion = artifacts.mapNotNull {
+            it.id.componentIdentifier as? ModuleComponentIdentifier
+        }.firstOrNull { id ->
+            id.group == "androidx.inspection" && id.module == "inspection"
+        }?.version
+
+        return if (projectDep) {
+            "${project.project(":inspection:inspection").version}"
+        } else prebuiltVersion ?: throw GradleException(
+            "Inspector must have a dependency on androidx.inspection"
+        )
+    }
+
+    @TaskAction
+    fun exec() {
+        val file = File(outputDir.asFile.get(), "META-INF/androidx_inspection.min_version")
+        file.parentFile.mkdirs()
+        file.writeText(getVersion())
+    }
+}
+
+@ExperimentalStdlibApi
+fun Project.registerGenerateInspectionPlatformVersionTask(
+    variant: BaseVariant
+): TaskProvider<GenerateInspectionPlatformVersionTask> {
+    val name = variant.taskName("generateInspectionPlatformVersion")
+    return tasks.register(name, GenerateInspectionPlatformVersionTask::class.java) {
+        it.compileConfiguration = variant.compileConfiguration.attributes {
+            it.attribute(Attribute.of("artifactType", String::class.java), "android-classes")
+        }
+        it.outputDir.set(taskWorkingDir(variant, "inspectionVersion"))
+    }
+}
diff --git a/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/ShadowDependenciesTask.kt b/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/ShadowDependenciesTask.kt
index 897ec1e..11ad65f 100644
--- a/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/ShadowDependenciesTask.kt
+++ b/inspection/inspection-gradle-plugin/src/main/kotlin/androidx/inspection/gradle/ShadowDependenciesTask.kt
@@ -40,14 +40,17 @@
     zipTask: TaskProvider<Copy>
 ): TaskProvider<ShadowJar> {
     val uberJar = registerUberJarTask(variant)
+    val versionTask = project.registerGenerateInspectionPlatformVersionTask(variant)
     return tasks.register(
         variant.taskName("shadowDependencies"),
         ShadowJar::class.java
     ) {
         it.dependsOn(uberJar)
+        it.dependsOn(versionTask)
         val fileTree = project.fileTree(zipTask.get().destinationDir)
         fileTree.include("**/*.jar", "**/*.so")
         it.from(fileTree)
+        it.from(versionTask.get().outputDir)
         it.includeEmptyDirs = false
         it.filesMatching("**/*.so") {
             if (it.path.startsWith("jni")) {
@@ -55,6 +58,7 @@
             }
         }
         it.transform(RenameServicesTransformer::class.java)
+        it.from(versionTask.get().outputDir)
         it.destinationDirectory.set(taskWorkingDir(variant, "shadowedJar"))
         it.archiveBaseName.set("${project.name}-shadowed")
         it.dependsOn(zipTask)
@@ -138,4 +142,4 @@
     val relocateContext = RelocateClassContext(className, stats)
     val relocator = relocators.find { it.canRelocateClass(relocateContext) }
     return relocator?.relocateClass(relocateContext) ?: className
-}
\ No newline at end of file
+}
diff --git a/inspection/inspection-gradle-plugin/src/test/kotlin/androidx/inspection/gradle/InspectionPluginTest.kt b/inspection/inspection-gradle-plugin/src/test/kotlin/androidx/inspection/gradle/InspectionPluginTest.kt
index b84c90b7..4a0ebfe 100644
--- a/inspection/inspection-gradle-plugin/src/test/kotlin/androidx/inspection/gradle/InspectionPluginTest.kt
+++ b/inspection/inspection-gradle-plugin/src/test/kotlin/androidx/inspection/gradle/InspectionPluginTest.kt
@@ -66,7 +66,11 @@
                     id("androidx.inspection")
                 }
             """.trimIndent(),
-            suffix = ""
+            suffix = """
+                dependencies {
+                    implementation("androidx.inspection:inspection:1.0.0")
+                }
+            """
         )
 
         val output = gradleRunner.withArguments("dexInspectorRelease").build()
@@ -95,4 +99,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/lint-checks/build.gradle b/lint-checks/build.gradle
index 470f379..5733dc1 100644
--- a/lint-checks/build.gradle
+++ b/lint-checks/build.gradle
@@ -23,6 +23,14 @@
     id("kotlin")
 }
 
+sourceSets {
+    // Pull integration test source code in for use by lint testing framework.
+    test.resources.srcDirs(
+            project(":lint-checks:integration-tests")
+                    .projectDir.absolutePath + "/src/main"
+    )
+}
+
 dependencies {
     compileOnly(LINT_API_LATEST)
     compileOnly(LINT_CHECKS_LATEST)
diff --git a/lint-checks/integration-tests/build.gradle b/lint-checks/integration-tests/build.gradle
index 825602b..3790ebf 100644
--- a/lint-checks/integration-tests/build.gradle
+++ b/lint-checks/integration-tests/build.gradle
@@ -17,22 +17,31 @@
 import androidx.build.BuildOnServerKt
 import androidx.build.dependencyTracker.AffectedModuleDetector
 import androidx.build.uptodatedness.EnableCachingKt
-import org.apache.tools.ant.filters.ReplaceTokens
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 import static androidx.build.dependencies.DependenciesKt.KOTLIN_STDLIB
 
 plugins {
     id("AndroidXPlugin")
     id("com.android.library")
-    id("AndroidXUiPlugin")
-    id("org.jetbrains.kotlin.android")
+    id("kotlin-android")
 }
 
 dependencies {
-    implementation("androidx.annotation:annotation:1.0.0")
+    implementation(project(":annotation:annotation"))
     implementation(KOTLIN_STDLIB)
 }
 
+// Allow usage of Kotlin's @Experimental and @RequiresOptIn annotations.
+tasks.withType(KotlinCompile).configureEach {
+    kotlinOptions {
+        freeCompilerArgs += [
+                "-Xuse-experimental=kotlin.Experimental",
+                "-Xopt-in=kotlin.RequiresOptIn",
+        ]
+    }
+}
+
 androidx {
     name = "Lint Checks Integration Tests"
     description = "This is a sample library for confirming that lint checks execute correctly, b/177437928"
diff --git a/lint-checks/integration-tests/expected-lint-results.xml b/lint-checks/integration-tests/expected-lint-results.xml
index 7dd7360..e8f2901 100644
--- a/lint-checks/integration-tests/expected-lint-results.xml
+++ b/lint-checks/integration-tests/expected-lint-results.xml
@@ -2,54 +2,6 @@
 <issues format="5" by="lint 4.2.0-beta04">
 
     <issue
-        id="UnknownIssueId"
-        severity="Ignore"
-        message="Unknown issue id &quot;ComposableLambdaParameterNaming&quot;"
-        category="Lint"
-        priority="1"
-        summary="Unknown Lint Issue Id"
-        explanation="Lint will report this issue if it is configured with an issue id it does not recognize in for example Gradle files or `lint.xml` configuration files.">
-        <location
-            file="$SUPPORT/lint-checks/integration-tests/build.gradle"/>
-    </issue>
-
-    <issue
-        id="UnknownIssueId"
-        severity="Ignore"
-        message="Unknown issue id &quot;ComposableLambdaParameterPosition&quot;"
-        category="Lint"
-        priority="1"
-        summary="Unknown Lint Issue Id"
-        explanation="Lint will report this issue if it is configured with an issue id it does not recognize in for example Gradle files or `lint.xml` configuration files.">
-        <location
-            file="$SUPPORT/lint-checks/integration-tests/build.gradle"/>
-    </issue>
-
-    <issue
-        id="UnknownIssueId"
-        severity="Ignore"
-        message="Unknown issue id &quot;ComposableNaming&quot;"
-        category="Lint"
-        priority="1"
-        summary="Unknown Lint Issue Id"
-        explanation="Lint will report this issue if it is configured with an issue id it does not recognize in for example Gradle files or `lint.xml` configuration files.">
-        <location
-            file="$SUPPORT/lint-checks/integration-tests/build.gradle"/>
-    </issue>
-
-    <issue
-        id="UnknownIssueId"
-        severity="Ignore"
-        message="Unknown issue id &quot;CompositionLocalNaming&quot;"
-        category="Lint"
-        priority="1"
-        summary="Unknown Lint Issue Id"
-        explanation="Lint will report this issue if it is configured with an issue id it does not recognize in for example Gradle files or `lint.xml` configuration files.">
-        <location
-            file="$SUPPORT/lint-checks/integration-tests/build.gradle"/>
-    </issue>
-
-    <issue
         id="BanConcurrentHashMap"
         severity="Error"
         message="Detected ConcurrentHashMap usage."
@@ -60,28 +12,12 @@
         errorLine1="import java.util.concurrent.ConcurrentHashMap;"
         errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="$SUPPORT/lint-checks/integration-tests/src/main/java/Sample.java"
+            file="$SUPPORT/lint-checks/integration-tests/src/main/java/androidx/Sample.java"
             line="19"
             column="1"/>
     </issue>
 
     <issue
-        id="UnnecessaryLambdaCreation"
-        severity="Error"
-        message="Creating an unnecessary lambda to emit a captured lambda"
-        category="Performance"
-        priority="5"
-        summary="Creating an unnecessary lambda to emit a captured lambda"
-        explanation="Creating this extra lambda instead of just passing the already captured lambda means that during code generation the Compose compiler will insert code around this lambda to track invalidations. This adds some extra runtime cost so you should instead just directly pass the lambda as a parameter to the function."
-        errorLine1="        lambda()"
-        errorLine2="        ~~~~~~">
-        <location
-            file="$SUPPORT/lint-checks/integration-tests/src/main/java/ComposeSample.kt"
-            line="29"
-            column="9"/>
-    </issue>
-
-    <issue
         id="UnknownNullness"
         severity="Fatal"
         message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://android.github.io/kotlin-guides/interop.html#nullability-annotations"
@@ -94,8 +30,8 @@
         errorLine1="    public static Sample confirmIntrinisicLintChecksRun() {"
         errorLine2="                  ~~~~~~">
         <location
-            file="$SUPPORT/lint-checks/integration-tests/src/main/java/Sample.java"
-            line="28"
+            file="$SUPPORT/lint-checks/integration-tests/src/main/java/androidx/Sample.java"
+            line="32"
             column="19"/>
     </issue>
 
@@ -112,8 +48,8 @@
         errorLine1="    public static void confirmCustomAndroidXChecksRun(ConcurrentHashMap m) {"
         errorLine2="                                                      ~~~~~~~~~~~~~~~~~">
         <location
-            file="$SUPPORT/lint-checks/integration-tests/src/main/java/Sample.java"
-            line="37"
+            file="$SUPPORT/lint-checks/integration-tests/src/main/java/androidx/Sample.java"
+            line="41"
             column="55"/>
     </issue>
 
diff --git a/lint-checks/integration-tests/src/main/java/ComposeSample.kt b/lint-checks/integration-tests/src/main/java/androidx/ComposeSample.kt
similarity index 96%
rename from lint-checks/integration-tests/src/main/java/ComposeSample.kt
rename to lint-checks/integration-tests/src/main/java/androidx/ComposeSample.kt
index c3e2c63..ca74815 100644
--- a/lint-checks/integration-tests/src/main/java/ComposeSample.kt
+++ b/lint-checks/integration-tests/src/main/java/androidx/ComposeSample.kt
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+@file:Suppress("unused")
+
 package androidx
 
 fun lambdaFunction(lambda: () -> Unit) {
diff --git a/lint-checks/integration-tests/src/main/java/Sample.java b/lint-checks/integration-tests/src/main/java/androidx/Sample.java
similarity index 88%
rename from lint-checks/integration-tests/src/main/java/Sample.java
rename to lint-checks/integration-tests/src/main/java/androidx/Sample.java
index 5d2ba27..7c396ca 100644
--- a/lint-checks/integration-tests/src/main/java/Sample.java
+++ b/lint-checks/integration-tests/src/main/java/androidx/Sample.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright 2021 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.
@@ -18,6 +18,10 @@
 
 import java.util.concurrent.ConcurrentHashMap;
 
+/**
+ * Sample class used to verify that ConcurrentHashMap lint check is running.
+ */
+@SuppressWarnings("unused")
 public class Sample {
 
     /**
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt b/lint-checks/integration-tests/src/main/java/androidx/sample/consumer/OutsideGroupExperimentalAnnotatedClass.kt
similarity index 61%
copy from compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
copy to lint-checks/integration-tests/src/main/java/androidx/sample/consumer/OutsideGroupExperimentalAnnotatedClass.kt
index 7e01354..ded25ef 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
+++ b/lint-checks/integration-tests/src/main/java/androidx/sample/consumer/OutsideGroupExperimentalAnnotatedClass.kt
@@ -1,5 +1,3 @@
-// ktlint-disable filename
-
 /*
  * Copyright 2021 The Android Open Source Project
  *
@@ -16,6 +14,17 @@
  * limitations under the License.
  */
 
-package androidx.compose.foundation
+@file:Suppress("unused")
 
-internal actual typealias AtomicReference<V> = java.util.concurrent.atomic.AtomicReference<V>
\ No newline at end of file
+package androidx.sample.consumer
+
+import sample.annotation.provider.ExperimentalSampleAnnotation
+import sample.annotation.provider.ExperimentalSampleAnnotationJava
+
+class OutsideGroupExperimentalAnnotatedClass {
+    @ExperimentalSampleAnnotationJava
+    @ExperimentalSampleAnnotation
+    fun invalidAnnotatedMethod() {
+        // Nothing to see here.
+    }
+}
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt b/lint-checks/integration-tests/src/main/java/sample/annotation/provider/ExperimentalSampleAnnotation.kt
similarity index 75%
copy from compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
copy to lint-checks/integration-tests/src/main/java/sample/annotation/provider/ExperimentalSampleAnnotation.kt
index 7e01354..265455c 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
+++ b/lint-checks/integration-tests/src/main/java/sample/annotation/provider/ExperimentalSampleAnnotation.kt
@@ -1,5 +1,3 @@
-// ktlint-disable filename
-
 /*
  * Copyright 2021 The Android Open Source Project
  *
@@ -16,6 +14,9 @@
  * limitations under the License.
  */
 
-package androidx.compose.foundation
+package sample.annotation.provider
 
-internal actual typealias AtomicReference<V> = java.util.concurrent.atomic.AtomicReference<V>
\ No newline at end of file
+@RequiresOptIn
+@Retention(AnnotationRetention.BINARY)
+@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
+annotation class ExperimentalSampleAnnotation
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt b/lint-checks/integration-tests/src/main/java/sample/annotation/provider/ExperimentalSampleAnnotationJava.java
similarity index 61%
copy from compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
copy to lint-checks/integration-tests/src/main/java/sample/annotation/provider/ExperimentalSampleAnnotationJava.java
index 7e01354..cf47d87 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
+++ b/lint-checks/integration-tests/src/main/java/sample/annotation/provider/ExperimentalSampleAnnotationJava.java
@@ -1,5 +1,3 @@
-// ktlint-disable filename
-
 /*
  * Copyright 2021 The Android Open Source Project
  *
@@ -16,6 +14,17 @@
  * limitations under the License.
  */
 
-package androidx.compose.foundation
+package sample.annotation.provider;
 
-internal actual typealias AtomicReference<V> = java.util.concurrent.atomic.AtomicReference<V>
\ No newline at end of file
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import kotlin.RequiresOptIn;
+
+@RequiresOptIn
+@Retention(CLASS)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface ExperimentalSampleAnnotationJava {}
diff --git a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt b/lint-checks/integration-tests/src/main/java/sample/annotation/provider/WithinGroupExperimentalAnnotatedClass.kt
similarity index 73%
copy from compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
copy to lint-checks/integration-tests/src/main/java/sample/annotation/provider/WithinGroupExperimentalAnnotatedClass.kt
index 7e01354..f36c34fd 100644
--- a/compose/foundation/foundation/src/desktopMain/kotlin/androidx/compose/foundation/ActualDesktop.kt
+++ b/lint-checks/integration-tests/src/main/java/sample/annotation/provider/WithinGroupExperimentalAnnotatedClass.kt
@@ -1,5 +1,3 @@
-// ktlint-disable filename
-
 /*
  * Copyright 2021 The Android Open Source Project
  *
@@ -16,6 +14,13 @@
  * limitations under the License.
  */
 
-package androidx.compose.foundation
+@file:Suppress("unused")
 
-internal actual typealias AtomicReference<V> = java.util.concurrent.atomic.AtomicReference<V>
\ No newline at end of file
+package sample.annotation.provider
+
+class WithinGroupExperimentalAnnotatedClass {
+    @ExperimentalSampleAnnotation
+    fun validAnnotatedMethod() {
+        // Nothing to see here.
+    }
+}
diff --git a/lint-checks/src/main/java/androidx/build/lint/BanInappropriateExperimentalUsage.kt b/lint-checks/src/main/java/androidx/build/lint/BanInappropriateExperimentalUsage.kt
index e596f53..5bc2e75 100644
--- a/lint-checks/src/main/java/androidx/build/lint/BanInappropriateExperimentalUsage.kt
+++ b/lint-checks/src/main/java/androidx/build/lint/BanInappropriateExperimentalUsage.kt
@@ -14,9 +14,11 @@
  * limitations under the License.
  */
 
+@file:Suppress("UnstableApiUsage")
+
 package androidx.build.lint
 
-import com.android.tools.lint.detector.api.AnnotationUsageType
+import com.android.tools.lint.client.api.UElementHandler
 import com.android.tools.lint.detector.api.Category
 import com.android.tools.lint.detector.api.Detector
 import com.android.tools.lint.detector.api.Implementation
@@ -24,107 +26,93 @@
 import com.android.tools.lint.detector.api.JavaContext
 import com.android.tools.lint.detector.api.Scope
 import com.android.tools.lint.detector.api.Severity
-import com.android.tools.lint.detector.api.SourceCodeScanner
-import com.intellij.psi.PsiElement
-import com.intellij.psi.PsiMethod
+import com.intellij.psi.PsiCompiledElement
+import org.jetbrains.uast.UAnnotated
 import org.jetbrains.uast.UAnnotation
 import org.jetbrains.uast.UElement
-import org.jetbrains.uast.getContainingUClass
+import org.jetbrains.uast.resolveToUElement
 
-class BanInappropriateExperimentalUsage : Detector(), SourceCodeScanner {
-    override fun applicableAnnotations(): List<String>? = listOf(
-        JAVA_EXPERIMENTAL_ANNOTATION,
-        KOTLIN_OPT_IN_ANNOTATION,
-        KOTLIN_EXPERIMENTAL_ANNOTATION
-    )
+/**
+ * Prevents usage of experimental annotations outside the groups in which they were defined.
+ */
+class BanInappropriateExperimentalUsage : Detector(), Detector.UastScanner {
 
-    override fun visitAnnotationUsage(
-        context: JavaContext,
-        usage: UElement,
-        type: AnnotationUsageType,
-        annotation: UAnnotation,
-        qualifiedName: String,
-        method: PsiMethod?,
-        referenced: PsiElement?,
-        annotations: List<UAnnotation>,
-        allMemberAnnotations: List<UAnnotation>,
-        allClassAnnotations: List<UAnnotation>,
-        allPackageAnnotations: List<UAnnotation>
-    ) {
-        when (qualifiedName) {
-            JAVA_EXPERIMENTAL_ANNOTATION,
-            JAVA_OPT_IN_ANNOTATION,
-            KOTLIN_EXPERIMENTAL_ANNOTATION,
-            KOTLIN_OPT_IN_ANNOTATION -> {
-                verifyExperimentalOrOptInUsageIsWithinSameGroup(
-                    context, usage, annotation
-                )
+    override fun getApplicableUastTypes() = listOf(UAnnotation::class.java)
+
+    override fun createUastHandler(context: JavaContext): UElementHandler {
+        return AnnotationChecker(context)
+    }
+
+    private inner class AnnotationChecker(val context: JavaContext) : UElementHandler() {
+        override fun visitAnnotation(node: UAnnotation) {
+            val annotation = node.resolveToUElement()
+            if (annotation is UAnnotated) {
+                val annotations = context.evaluator.getAllAnnotations(annotation, false)
+                val isOptIn = annotations.any { APPLICABLE_ANNOTATIONS.contains(it.qualifiedName) }
+                if (isOptIn) {
+                    verifyUsageOfElementIsWithinSameGroup(context, node, annotation, ISSUE)
+                }
             }
         }
     }
 
-    fun verifyExperimentalOrOptInUsageIsWithinSameGroup(
+    fun verifyUsageOfElementIsWithinSameGroup(
         context: JavaContext,
         usage: UElement,
-        annotation: UAnnotation
+        annotation: UElement,
+        issue: Issue,
     ) {
-        val declaringGroup = getApproximateAnnotationMavenGroup(annotation)
-        val usingGroup = getApproximateUsageSiteMavenGroup(usage)
-        // Don't flag if group is null for some reason (for now at least)
-        // Also exclude sample for now, since it doesn't work well with our workaround (includes
-        // class)
-        if (declaringGroup != null && usingGroup != null && declaringGroup != usingGroup &&
-            usingGroup != "sample"
-        ) {
+        val evaluator = context.evaluator
+        val usageCoordinates = evaluator.getLibrary(usage) ?: context.project.mavenCoordinate
+        val annotationCoordinates = evaluator.getLibrary(annotation) ?: run {
+            // Is the annotation defined in source code?
+            if (usageCoordinates != null && annotation !is PsiCompiledElement) {
+                annotation.sourcePsi?.let { sourcePsi ->
+                    evaluator.getProject(sourcePsi)?.mavenCoordinate
+                }
+            } else {
+                null
+            }
+        }
+        val usageGroupId = usageCoordinates?.groupId
+        val annotationGroupId = annotationCoordinates?.groupId
+        if (annotationGroupId != usageGroupId && annotationGroupId != null) {
             context.report(
-                BanInappropriateExperimentalUsage.ISSUE, usage, context.getNameLocation(usage),
-                "`Experimental`/`OptIn` APIs should only be used from within the same library " +
-                    "or libraries within the same requireSameVersion group"
+                issue, usage, context.getNameLocation(usage),
+                "`Experimental` and `RequiresOptIn` APIs may only be used within the same-version" +
+                    " group where they were defined."
             )
         }
     }
 
-    fun getApproximateAnnotationMavenGroup(annotation: UAnnotation): String? {
-        if (annotation.getContainingUClass() == null || annotation.getContainingUClass()!!
-            .qualifiedName == null
-        ) {
-            return null
-        }
-        return annotation.getContainingUClass()!!.qualifiedName!!.split(".").subList(0, 2)
-            .joinToString(".")
-    }
-
-    fun getApproximateUsageSiteMavenGroup(usage: UElement): String? {
-        if (usage.getContainingUClass() == null || usage.getContainingUClass()!!
-            .qualifiedName == null
-        ) {
-            return null
-        }
-        return usage.getContainingUClass()!!.qualifiedName!!.split(".").subList(0, 2)
-            .joinToString(".")
-    }
-
     companion object {
-
         private const val KOTLIN_EXPERIMENTAL_ANNOTATION = "kotlin.Experimental"
-
+        private const val KOTLIN_REQUIRES_OPT_IN_ANNOTATION = "kotlin.RequiresOptIn"
         private const val JAVA_EXPERIMENTAL_ANNOTATION =
             "androidx.annotation.experimental.Experimental"
+        private const val JAVA_REQUIRES_OPT_IN_ANNOTATION =
+            "androidx.annotation.RequiresOptIn"
 
-        private const val KOTLIN_OPT_IN_ANNOTATION =
-            "kotlin.OptIn"
-
-        private const val JAVA_OPT_IN_ANNOTATION =
-            "androidx.annotation.OptIn"
+        private val APPLICABLE_ANNOTATIONS = listOf(
+            JAVA_EXPERIMENTAL_ANNOTATION,
+            KOTLIN_EXPERIMENTAL_ANNOTATION,
+            JAVA_REQUIRES_OPT_IN_ANNOTATION,
+            KOTLIN_REQUIRES_OPT_IN_ANNOTATION,
+        )
 
         val ISSUE = Issue.create(
-            "IllegalExperimentalApiUsage",
-            "Using experimental api from separately versioned library",
-            "APIs annotated with `@RequiresOptIn` or `@Experimental` are considered alpha." +
-                "A caller from another library may not use them unless that the two libraries " +
-                "are part of the same maven group and that group specifies requireSameVersion",
-            Category.CORRECTNESS, 5, Severity.ERROR,
-            Implementation(BanInappropriateExperimentalUsage::class.java, Scope.JAVA_FILE_SCOPE)
+            id = "IllegalExperimentalApiUsage",
+            briefDescription = "Using experimental API from separately versioned library",
+            explanation = "Annotations meta-annotated with `@RequiresOptIn` or `@Experimental` " +
+                "may only be referenced from within the same-version group in which they were " +
+                "defined.",
+            category = Category.CORRECTNESS,
+            priority = 5,
+            severity = Severity.ERROR,
+            implementation = Implementation(
+                BanInappropriateExperimentalUsage::class.java,
+                Scope.JAVA_FILE_SCOPE,
+            ),
         )
     }
-}
+}
\ No newline at end of file
diff --git a/lint-checks/src/test/java/androidx/build/lint/BanInappropriateExperimentalUsageTest.kt b/lint-checks/src/test/java/androidx/build/lint/BanInappropriateExperimentalUsageTest.kt
new file mode 100644
index 0000000..cd7a7b3
--- /dev/null
+++ b/lint-checks/src/test/java/androidx/build/lint/BanInappropriateExperimentalUsageTest.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2021 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.build.lint
+
+import com.android.tools.lint.checks.infrastructure.ProjectDescription
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestFiles
+import com.android.tools.lint.checks.infrastructure.TestFiles.gradle
+import com.android.tools.lint.checks.infrastructure.TestLintTask.lint
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@Suppress("UnstableApiUsage")
+@RunWith(JUnit4::class)
+class BanInappropriateExperimentalUsageTest {
+
+    @Test
+    fun `Test within-module Experimental usage via Gradle model`() {
+        val provider = project()
+            .name("provider")
+            .files(
+                ktSample("sample.annotation.provider.WithinGroupExperimentalAnnotatedClass"),
+                ktSample("sample.annotation.provider.ExperimentalSampleAnnotation"),
+                gradle(
+                    """
+                    apply plugin: 'com.android.library'
+                    group=sample.annotation.provider
+                    """
+                ).indented(),
+                OPT_IN_KT,
+            )
+
+        lint()
+            .projects(provider)
+            .issues(BanInappropriateExperimentalUsage.ISSUE)
+            .run()
+            .expect(
+                """
+                No warnings.
+                """.trimIndent()
+            )
+    }
+
+    @Test
+    fun `Test cross-module Experimental usage via Gradle model`() {
+        val provider = project()
+            .name("provider")
+            .report(false)
+            .files(
+                ktSample("sample.annotation.provider.ExperimentalSampleAnnotation"),
+                javaSample("sample.annotation.provider.ExperimentalSampleAnnotationJava"),
+                gradle(
+                    """
+                    apply plugin: 'com.android.library'
+                    group=sample.annotation.provider
+                    """
+                ).indented(),
+                OPT_IN_KT,
+            )
+
+        val consumer = project()
+            .name("consumer")
+            .dependsOn(provider)
+            .files(
+                ktSample("androidx.sample.consumer.OutsideGroupExperimentalAnnotatedClass"),
+                gradle(
+                    """
+                    apply plugin: 'com.android.library'
+                    group=androidx.sample.consumer
+                    """
+                ).indented()
+            )
+
+        lint()
+            .projects(provider, consumer)
+            .issues(BanInappropriateExperimentalUsage.ISSUE)
+            .run()
+            .expect(
+                """
+                consumer/src/main/kotlin/androidx/sample/consumer/OutsideGroupExperimentalAnnotatedClass.kt:25: Error: Experimental and RequiresOptIn APIs may only be used within the same-version group where they were defined. [IllegalExperimentalApiUsage]
+                    @ExperimentalSampleAnnotationJava
+                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                1 errors, 0 warnings
+                """.trimIndent()
+            )
+    }
+
+    private fun project(): ProjectDescription = ProjectDescription()
+
+    /**
+     * Loads a [TestFile] from Java source code included in the JAR resources.
+     */
+    private fun javaSample(className: String): TestFile = TestFiles.java(
+        javaClass.getResource("/java/${className.replace('.', '/')}.java").readText()
+    )
+
+    /**
+     * Loads a [TestFile] from Kotlin source code included in the JAR resources.
+     */
+    private fun ktSample(className: String): TestFile = TestFiles.kotlin(
+        javaClass.getResource("/java/${className.replace('.', '/')}.kt").readText()
+    )
+}
+
+/* ktlint-disable max-line-length */
+
+/**
+ * [TestFile] containing OptIn.kt from the Kotlin standard library.
+ *
+ * This is a workaround for the Kotlin standard library used by the Lint test harness not
+ * including the Experimental annotation by default.
+ */
+private val OPT_IN_KT: TestFile = TestFiles.kotlin(
+    """
+    package kotlin
+
+    import kotlin.annotation.AnnotationRetention.BINARY
+    import kotlin.annotation.AnnotationRetention.SOURCE
+    import kotlin.annotation.AnnotationTarget.*
+    import kotlin.internal.RequireKotlin
+    import kotlin.internal.RequireKotlinVersionKind
+    import kotlin.reflect.KClass
+
+    @Target(ANNOTATION_CLASS)
+    @Retention(BINARY)
+    @SinceKotlin("1.3")
+    @RequireKotlin("1.3.70", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)
+    public annotation class RequiresOptIn(
+        val message: String = "",
+        val level: Level = Level.ERROR
+    ) {
+        public enum class Level {
+            WARNING,
+            ERROR,
+        }
+    }
+
+    @Target(
+        CLASS, PROPERTY, LOCAL_VARIABLE, VALUE_PARAMETER, CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, EXPRESSION, FILE, TYPEALIAS
+    )
+    @Retention(SOURCE)
+    @SinceKotlin("1.3")
+    @RequireKotlin("1.3.70", versionKind = RequireKotlinVersionKind.COMPILER_VERSION)
+    public annotation class OptIn(
+        vararg val markerClass: KClass<out Annotation>
+    )
+    """.trimIndent()
+)
+
+/* ktlint-enable max-line-length */
diff --git a/media/media/api/current.txt b/media/media/api/current.txt
index ff8752c..f2736b3 100644
--- a/media/media/api/current.txt
+++ b/media/media/api/current.txt
@@ -634,9 +634,9 @@
 
   public static class MediaBrowserServiceCompat.Result<T> {
     method public void detach();
-    method public void sendError(android.os.Bundle!);
-    method public void sendProgressUpdate(android.os.Bundle!);
-    method public void sendResult(T!);
+    method public void sendError(android.os.Bundle?);
+    method public void sendProgressUpdate(android.os.Bundle?);
+    method public void sendResult(T?);
   }
 
   public final class MediaSessionManager {
diff --git a/media/media/api/public_plus_experimental_current.txt b/media/media/api/public_plus_experimental_current.txt
index a6eaa11..21272eb 100644
--- a/media/media/api/public_plus_experimental_current.txt
+++ b/media/media/api/public_plus_experimental_current.txt
@@ -634,9 +634,9 @@
 
   public static class MediaBrowserServiceCompat.Result<T> {
     method public void detach();
-    method public void sendError(android.os.Bundle!);
-    method public void sendProgressUpdate(android.os.Bundle!);
-    method public void sendResult(T!);
+    method public void sendError(android.os.Bundle?);
+    method public void sendProgressUpdate(android.os.Bundle?);
+    method public void sendResult(T?);
   }
 
   public final class MediaSessionManager {
diff --git a/media/media/api/restricted_current.txt b/media/media/api/restricted_current.txt
index 052b25c..bdc3176 100644
--- a/media/media/api/restricted_current.txt
+++ b/media/media/api/restricted_current.txt
@@ -659,9 +659,9 @@
 
   public static class MediaBrowserServiceCompat.Result<T> {
     method public void detach();
-    method public void sendError(android.os.Bundle!);
-    method public void sendProgressUpdate(android.os.Bundle!);
-    method public void sendResult(T!);
+    method public void sendError(android.os.Bundle?);
+    method public void sendProgressUpdate(android.os.Bundle?);
+    method public void sendResult(T?);
   }
 
   public final class MediaSessionManager {
diff --git a/media/media/src/main/java/androidx/media/MediaBrowserServiceCompat.java b/media/media/src/main/java/androidx/media/MediaBrowserServiceCompat.java
index fcf780f..05bbf1f 100644
--- a/media/media/src/main/java/androidx/media/MediaBrowserServiceCompat.java
+++ b/media/media/src/main/java/androidx/media/MediaBrowserServiceCompat.java
@@ -401,7 +401,7 @@
             final Result<List<MediaBrowserCompat.MediaItem>> result =
                     new Result<List<MediaBrowserCompat.MediaItem>>(parentId) {
                         @Override
-                        void onResultSent(List<MediaBrowserCompat.MediaItem> list) {
+                        void onResultSent(@Nullable List<MediaBrowserCompat.MediaItem> list) {
                             List<Parcel> parcelList = null;
                             if (list != null) {
                                 parcelList = new ArrayList<>();
@@ -528,7 +528,7 @@
             final Result<MediaBrowserCompat.MediaItem> result =
                     new Result<MediaBrowserCompat.MediaItem>(itemId) {
                         @Override
-                        void onResultSent(MediaBrowserCompat.MediaItem item) {
+                        void onResultSent(@Nullable MediaBrowserCompat.MediaItem item) {
                             if (item == null) {
                                 resultWrapper.sendResult(null);
                             } else {
@@ -575,7 +575,7 @@
             final Result<List<MediaBrowserCompat.MediaItem>> result =
                     new Result<List<MediaBrowserCompat.MediaItem>>(parentId) {
                         @Override
-                        void onResultSent(List<MediaBrowserCompat.MediaItem> list) {
+                        void onResultSent(@Nullable List<MediaBrowserCompat.MediaItem> list) {
                             if (list == null) {
                                 resultWrapper.sendResult(null);
                                 return;
@@ -845,7 +845,7 @@
         /**
          * Send the result back to the caller.
          */
-        public void sendResult(T result) {
+        public void sendResult(@Nullable T result) {
             if (mSendResultCalled || mSendErrorCalled) {
                 throw new IllegalStateException("sendResult() called when either sendResult() or "
                         + "sendError() had already been called for: " + mDebug);
@@ -860,7 +860,7 @@
          *
          * @param extras A bundle that contains extra data.
          */
-        public void sendProgressUpdate(Bundle extras) {
+        public void sendProgressUpdate(@Nullable Bundle extras) {
             if (mSendResultCalled || mSendErrorCalled) {
                 throw new IllegalStateException("sendProgressUpdate() called when either "
                         + "sendResult() or sendError() had already been called for: " + mDebug);
@@ -875,7 +875,7 @@
          *
          * @param extras A bundle that contains extra data.
          */
-        public void sendError(Bundle extras) {
+        public void sendError(@Nullable Bundle extras) {
             if (mSendResultCalled || mSendErrorCalled) {
                 throw new IllegalStateException("sendError() called when either sendResult() or "
                         + "sendError() had already been called for: " + mDebug);
@@ -920,13 +920,13 @@
          * Called when the result is sent, after assertions about not being called twice have
          * happened.
          */
-        void onResultSent(T result) {
+        void onResultSent(@Nullable T result) {
         }
 
         /**
          * Called when an interim update is sent.
          */
-        void onProgressUpdateSent(Bundle extras) {
+        void onProgressUpdateSent(@Nullable Bundle extras) {
             throw new UnsupportedOperationException("It is not supported to send an interim update "
                     + "for " + mDebug);
         }
@@ -935,12 +935,12 @@
          * Called when an error is sent, after assertions about not being called twice have
          * happened.
          */
-        void onErrorSent(Bundle extras) {
+        void onErrorSent(@Nullable Bundle extras) {
             throw new UnsupportedOperationException("It is not supported to send an error for "
                     + mDebug);
         }
 
-        private void checkExtraFields(Bundle extras) {
+        private void checkExtraFields(@Nullable Bundle extras) {
             if (extras == null) {
                 return;
             }
@@ -1716,7 +1716,7 @@
         final Result<List<MediaBrowserCompat.MediaItem>> result
                 = new Result<List<MediaBrowserCompat.MediaItem>>(parentId) {
             @Override
-            void onResultSent(List<MediaBrowserCompat.MediaItem> list) {
+            void onResultSent(@Nullable List<MediaBrowserCompat.MediaItem> list) {
                 if (mConnections.get(connection.callbacks.asBinder()) != connection) {
                     if (DEBUG) {
                         Log.d(TAG, "Not sending onLoadChildren result for connection that has"
@@ -1779,7 +1779,7 @@
         final Result<MediaBrowserCompat.MediaItem> result =
                 new Result<MediaBrowserCompat.MediaItem>(itemId) {
                     @Override
-                    void onResultSent(MediaBrowserCompat.MediaItem item) {
+                    void onResultSent(@Nullable MediaBrowserCompat.MediaItem item) {
                         if ((getFlags() & RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED) != 0) {
                             receiver.send(RESULT_ERROR, null);
                             return;
@@ -1805,7 +1805,7 @@
         final Result<List<MediaBrowserCompat.MediaItem>> result =
                 new Result<List<MediaBrowserCompat.MediaItem>>(query) {
             @Override
-            void onResultSent(List<MediaBrowserCompat.MediaItem> items) {
+            void onResultSent(@Nullable List<MediaBrowserCompat.MediaItem> items) {
                 if ((getFlags() & RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED) != 0
                         || items == null) {
                     receiver.send(RESULT_ERROR, null);
@@ -1832,17 +1832,17 @@
             final ResultReceiver receiver) {
         final Result<Bundle> result = new Result<Bundle>(action) {
                 @Override
-                void onResultSent(Bundle result) {
+                void onResultSent(@Nullable Bundle result) {
                     receiver.send(RESULT_OK, result);
                 }
 
                 @Override
-                void onProgressUpdateSent(Bundle data) {
+                void onProgressUpdateSent(@Nullable Bundle data) {
                     receiver.send(RESULT_PROGRESS_UPDATE, data);
                 }
 
                 @Override
-                void onErrorSent(Bundle data) {
+                void onErrorSent(@Nullable Bundle data) {
                     receiver.send(RESULT_ERROR, data);
                 }
             };
diff --git a/media2/media2-session/src/androidTest/java/androidx/media2/session/MediaBrowserTest.java b/media2/media2-session/src/androidTest/java/androidx/media2/session/MediaBrowserTest.java
deleted file mode 100644
index 95d3a9f..0000000
--- a/media2/media2-session/src/androidTest/java/androidx/media2/session/MediaBrowserTest.java
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * Copyright 2019 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.media2.session;
-
-import static androidx.media2.session.LibraryResult.RESULT_ERROR_PERMISSION_DENIED;
-import static androidx.media2.session.LibraryResult.RESULT_SUCCESS;
-import static androidx.media2.session.TestUtils.assertLibraryParamsEquals;
-import static androidx.media2.session.TestUtils.assertMediaItemEquals;
-import static androidx.media2.session.TestUtils.assertMediaItemWithId;
-import static androidx.media2.session.TestUtils.createLibraryParams;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-
-import android.os.Bundle;
-import android.os.Process;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.media2.session.MediaBrowser.BrowserCallback;
-import androidx.media2.session.MediaController.ControllerCallback;
-import androidx.media2.session.MediaLibraryService.LibraryParams;
-import androidx.media2.session.MediaLibraryService.MediaLibrarySession;
-import androidx.media2.session.MediaLibraryService.MediaLibrarySession.MediaLibrarySessionCallback;
-import androidx.media2.session.MediaSession.ControllerInfo;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.LargeTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.lang.reflect.Method;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Tests {@link MediaBrowser}.
- * <p>
- * This test inherits {@link MediaControllerTest} to ensure that inherited APIs from
- * {@link MediaController} works cleanly.
- */
-// TODO(jaewan): Implement host-side test so browser and service can run in different processes.
-@RunWith(AndroidJUnit4.class)
-@LargeTest
-public class MediaBrowserTest extends MediaControllerTest {
-    private static final String TAG = "MediaBrowserTest";
-
-    @Override
-    MediaController onCreateController(@NonNull final SessionToken token,
-            @Nullable final Bundle connectionHints, @Nullable final TestBrowserCallback callback)
-            throws InterruptedException {
-        final AtomicReference<MediaController> controller = new AtomicReference<>();
-        sHandler.postAndSync(new Runnable() {
-            @Override
-            public void run() {
-                // Create controller on the test handler, for changing MediaBrowserCompat's Handler
-                // Looper. Otherwise, MediaBrowserCompat will post all the commands to the handler
-                // and commands wouldn't be run if tests codes waits on the test handler.
-                MediaBrowser.Builder builder = new MediaBrowser.Builder(mContext)
-                        .setSessionToken(token)
-                        .setControllerCallback(sHandlerExecutor, callback);
-                if (connectionHints != null) {
-                    builder.setConnectionHints(connectionHints);
-                }
-                controller.set(builder.build());
-            }
-        });
-        return controller.get();
-    }
-
-    final MediaBrowser createBrowser() throws InterruptedException {
-        return createBrowser(null);
-    }
-
-    final MediaBrowser createBrowser(@Nullable BrowserCallback callback)
-            throws InterruptedException {
-        return (MediaBrowser) createController(MockMediaLibraryService.getToken(mContext),
-                true, null, callback);
-    }
-
-    /**
-     * Test if the {@link TestBrowserCallback} wraps the callback proxy without missing any method.
-     */
-    @Test
-    public void testBrowserCallback() {
-        Method[] methods = TestBrowserCallback.class.getMethods();
-        assertNotNull(methods);
-        for (int i = 0; i < methods.length; i++) {
-            // For any methods in the controller callback, TestBrowserCallback should have
-            // overridden the method and call matching API in the callback proxy.
-            assertNotEquals("TestBrowserCallback should override " + methods[i]
-                            + " and call callback proxy",
-                    BrowserCallback.class, methods[i].getDeclaringClass());
-            assertNotEquals("TestBrowserCallback should override " + methods[i]
-                            + " and call callback proxy",
-                    ControllerCallback.class, methods[i].getDeclaringClass());
-        }
-    }
-
-    @Test
-    public void getLibraryRoot() throws Exception {
-        final LibraryParams params = createLibraryParams();
-
-        MockMediaLibraryService.setAssertLibraryParams(params);
-        LibraryResult result = createBrowser().getLibraryRoot(params)
-                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        assertEquals(RESULT_SUCCESS, result.getResultCode());
-        assertMediaItemEquals(MockMediaLibraryService.ROOT_ITEM, result.getMediaItem());
-        assertLibraryParamsEquals(MockMediaLibraryService.ROOT_PARAMS, result.getLibraryParams());
-    }
-
-    @Test
-    public void getItem() throws Exception {
-        final String mediaId = MockMediaLibraryService.MEDIA_ID_GET_ITEM;
-
-        LibraryResult result = createBrowser().getItem(mediaId)
-                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        assertEquals(RESULT_SUCCESS, result.getResultCode());
-        assertMediaItemWithId(mediaId, result.getMediaItem());
-    }
-
-    @Test
-    public void getItemNullResult() throws Exception {
-        final String mediaId = "random_media_id";
-
-        LibraryResult result = createBrowser().getItem(mediaId)
-                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        assertNotEquals(RESULT_SUCCESS, result.getResultCode());
-        assertNull(result.getMediaItem());
-    }
-
-    @Test
-    public void getChildren() throws Exception {
-        final String parentId = MockMediaLibraryService.PARENT_ID;
-        final int page = 4;
-        final int pageSize = 10;
-        final LibraryParams params = createLibraryParams();
-
-        MockMediaLibraryService.setAssertLibraryParams(params);
-        LibraryResult result = createBrowser().getChildren(parentId, page, pageSize, params)
-                        .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        assertEquals(RESULT_SUCCESS, result.getResultCode());
-
-        TestUtils.assertPaginatedListEquals(MockMediaLibraryService.GET_CHILDREN_RESULT,
-                page, pageSize, result.getMediaItems());
-    }
-
-    @Test
-    public void getChildrenEmptyResult() throws Exception {
-        final String parentId = MockMediaLibraryService.PARENT_ID_NO_CHILDREN;
-
-        LibraryResult result = createBrowser().getChildren(parentId, 1, 1, null)
-                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        assertEquals(RESULT_SUCCESS, result.getResultCode());
-        assertEquals(0, result.getMediaItems().size());
-    }
-
-    @Test
-    public void getChildrenNullResult() throws Exception {
-        final String parentId = MockMediaLibraryService.PARENT_ID_ERROR;
-
-        LibraryResult result = createBrowser().getChildren(parentId, 1, 1, null)
-                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        assertNotEquals(RESULT_SUCCESS, result.getResultCode());
-        assertNull(result.getMediaItems());
-    }
-
-    @Test
-    public void search() throws Exception {
-        final String query = MockMediaLibraryService.SEARCH_QUERY;
-        final int page = 4;
-        final int pageSize = 10;
-        final LibraryParams params = createLibraryParams();
-
-        final CountDownLatch latchForSearch = new CountDownLatch(1);
-        final BrowserCallback callback = new BrowserCallback() {
-            @Override
-            public void onSearchResultChanged(MediaBrowser browser,
-                    String queryOut, int itemCount, LibraryParams paramsOut) {
-                assertEquals(query, queryOut);
-                assertLibraryParamsEquals(params, paramsOut);
-                assertEquals(MockMediaLibraryService.SEARCH_RESULT_COUNT, itemCount);
-                latchForSearch.countDown();
-            }
-        };
-
-        // Request the search.
-        MockMediaLibraryService.setAssertLibraryParams(params);
-        MediaBrowser browser = createBrowser(callback);
-        LibraryResult result = browser.search(query, params)
-                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        assertEquals(RESULT_SUCCESS, result.getResultCode());
-        assertTrue(latchForSearch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
-        // Get the search result.
-        result = browser.getSearchResult(query, page, pageSize, params)
-                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        assertEquals(RESULT_SUCCESS, result.getResultCode());
-
-        TestUtils.assertPaginatedListEquals(MockMediaLibraryService.SEARCH_RESULT,
-                page, pageSize, result.getMediaItems());
-    }
-
-    @Test
-    @LargeTest
-    public void searchTakesTime() throws Exception {
-        final String query = MockMediaLibraryService.SEARCH_QUERY_TAKES_TIME;
-        final LibraryParams params = createLibraryParams();
-
-        final CountDownLatch latch = new CountDownLatch(1);
-        final BrowserCallback callback = new BrowserCallback() {
-            @Override
-            public void onSearchResultChanged(
-                    MediaBrowser browser, String queryOut, int itemCount,
-                    LibraryParams paramsOut) {
-                assertEquals(query, queryOut);
-                assertLibraryParamsEquals(params, paramsOut);
-                assertEquals(MockMediaLibraryService.SEARCH_RESULT_COUNT, itemCount);
-                latch.countDown();
-            }
-        };
-
-        MockMediaLibraryService.setAssertLibraryParams(params);
-        LibraryResult result = createBrowser(callback).search(query, params)
-                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        assertEquals(RESULT_SUCCESS, result.getResultCode());
-        assertTrue(latch.await(
-                MockMediaLibraryService.SEARCH_TIME_IN_MS + TIMEOUT_MS, TimeUnit.MILLISECONDS));
-    }
-
-    @Test
-    public void searchEmptyResult() throws Exception {
-        final String query = MockMediaLibraryService.SEARCH_QUERY_EMPTY_RESULT;
-        final LibraryParams params = createLibraryParams();
-
-        final CountDownLatch latch = new CountDownLatch(1);
-        final BrowserCallback callback = new BrowserCallback() {
-            @Override
-            public void onSearchResultChanged(MediaBrowser browser, String queryOut, int itemCount,
-                    LibraryParams paramsOut) {
-                assertEquals(query, queryOut);
-                assertLibraryParamsEquals(params, paramsOut);
-                assertEquals(0, itemCount);
-                latch.countDown();
-            }
-        };
-
-        MockMediaLibraryService.setAssertLibraryParams(params);
-        LibraryResult result = createBrowser(callback).search(query, params)
-                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        assertEquals(RESULT_SUCCESS, result.getResultCode());
-        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-    }
-
-    @Test
-    public void subscribe() throws Exception {
-        final String testParentId = "testSubscribeId";
-        final LibraryParams params = createLibraryParams();
-
-        final MediaLibrarySessionCallback callback = new MediaLibrarySessionCallback() {
-            @Override
-            public int onSubscribe(@NonNull MediaLibraryService.MediaLibrarySession session,
-                    @NonNull MediaSession.ControllerInfo info, @NonNull String parentId,
-                    @Nullable LibraryParams paramsOut) {
-                if (Process.myUid() == info.getUid()) {
-                    assertEquals(testParentId, parentId);
-                    assertLibraryParamsEquals(params, paramsOut);
-                    return RESULT_SUCCESS;
-                }
-                return RESULT_ERROR_PERMISSION_DENIED;
-            }
-        };
-        TestServiceRegistry.getInstance().setSessionCallback(callback);
-        MockMediaLibraryService.setAssertLibraryParams(params);
-        LibraryResult result = createBrowser().subscribe(testParentId, params)
-                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        assertEquals(RESULT_SUCCESS, result.getResultCode());
-        assertNull(result.getMediaItems());
-    }
-
-    @Test
-    public void unsubscribe() throws Exception {
-        final String testParentId = "testUnsubscribeId";
-        final MediaLibrarySessionCallback callback = new MediaLibrarySessionCallback() {
-            @Override
-            public int onUnsubscribe(@NonNull MediaLibrarySession session,
-                    @NonNull ControllerInfo info, @NonNull String parentId) {
-                if (Process.myUid() == info.getUid()) {
-                    assertEquals(testParentId, parentId);
-                    return RESULT_SUCCESS;
-                }
-                return RESULT_ERROR_PERMISSION_DENIED;
-            }
-        };
-        TestServiceRegistry.getInstance().setSessionCallback(callback);
-        LibraryResult result = createBrowser().unsubscribe(testParentId)
-                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        assertEquals(RESULT_SUCCESS, result.getResultCode());
-        assertNull(result.getMediaItems());
-    }
-
-    @Test
-    public void browserCallback_onChildrenChangedIsNotCalledWhenNotSubscribed()
-            throws Exception {
-        // This test uses MediaLibrarySession.notifyChildrenChanged().
-        final String subscribedMediaId = "subscribedMediaId";
-        final String anotherMediaId = "anotherMediaId";
-        final int testChildrenCount = 101;
-
-        final MediaLibrarySessionCallback sessionCallback = new MediaLibrarySessionCallback() {
-            @Override
-            public int onSubscribe(@NonNull MediaLibrarySession session,
-                    @NonNull ControllerInfo controller, @NonNull String parentId,
-                    @Nullable LibraryParams params) {
-                if (Process.myUid() == controller.getUid()) {
-                    // Shouldn't trigger onChildrenChanged() for the browser,
-                    // because the browser didn't subscribe this media id.
-                    session.notifyChildrenChanged(anotherMediaId, testChildrenCount, null);
-                }
-                return RESULT_SUCCESS;
-            }
-
-            @NonNull
-            @Override
-            public LibraryResult onGetChildren(@NonNull MediaLibrarySession session,
-                    @NonNull ControllerInfo controller, @NonNull String parentId, int page,
-                    int pageSize, LibraryParams params) {
-                // This wouldn't be called at all.
-                return new LibraryResult(RESULT_SUCCESS,
-                        TestUtils.createMediaItems(testChildrenCount), null);
-            }
-        };
-        final CountDownLatch latch = new CountDownLatch(1);
-        final BrowserCallback controllerCallbackProxy = new BrowserCallback() {
-            @Override
-            public void onChildrenChanged(@NonNull MediaBrowser browser, @NonNull String parentId,
-                    int itemCount, LibraryParams params) {
-                // Unexpected call.
-                fail();
-                latch.countDown();
-            }
-        };
-
-        TestServiceRegistry.getInstance().setSessionCallback(sessionCallback);
-        LibraryResult result = createBrowser(controllerCallbackProxy)
-                .subscribe(subscribedMediaId, null)
-                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        // Subscribe itself is success because onSubscribe() returned SUCCESS.
-        assertEquals(RESULT_SUCCESS, result.getResultCode());
-
-        // notifyChildrenChanged() in onSubscribe() should fail onChildrenChanged() should not be
-        // called, because the ID hasn't been subscribed.
-        assertFalse(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-    }
-
-    @Test
-    public void browserCallback_onChildrenChangedIsCalledWhenSubscribed() throws Exception {
-        // This test uses MediaLibrarySession.notifyChildrenChanged().
-        final String expectedParentId = "expectedParentId";
-        final int testChildrenCount = 101;
-        final LibraryParams testParams = createLibraryParams();
-
-        final CountDownLatch latch = new CountDownLatch(1);
-        final MediaLibrarySessionCallback sessionCallback = new MediaLibrarySessionCallback() {
-            @Override
-            public int onSubscribe(@NonNull MediaLibrarySession session,
-                    @NonNull ControllerInfo controller, @NonNull String parentId,
-                    @Nullable LibraryParams params) {
-                if (Process.myUid() == controller.getUid()) {
-                    // Should trigger onChildrenChanged() for the browser.
-                    session.notifyChildrenChanged(expectedParentId, testChildrenCount, params);
-                }
-                return RESULT_SUCCESS;
-            }
-
-            @NonNull
-            @Override
-            public LibraryResult onGetChildren(@NonNull MediaLibrarySession session,
-                    @NonNull ControllerInfo controller, @NonNull String parentId, int page,
-                    int pageSize, LibraryParams params) {
-                return new LibraryResult(RESULT_SUCCESS,
-                        TestUtils.createMediaItems(testChildrenCount), null);
-            }
-        };
-        final BrowserCallback controllerCallbackProxy = new BrowserCallback() {
-            @Override
-            public void onChildrenChanged(@NonNull MediaBrowser browser, @NonNull String parentId,
-                    int itemCount, LibraryParams params) {
-                assertEquals(expectedParentId, parentId);
-                assertEquals(testChildrenCount, itemCount);
-                assertLibraryParamsEquals(testParams, params);
-                latch.countDown();
-            }
-        };
-
-        TestServiceRegistry.getInstance().setSessionCallback(sessionCallback);
-        MockMediaLibraryService.setAssertLibraryParams(testParams);
-        LibraryResult result = createBrowser(controllerCallbackProxy)
-                .subscribe(expectedParentId, testParams)
-                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        assertEquals(RESULT_SUCCESS, result.getResultCode());
-
-        // onChildrenChanged() should be called.
-        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-    }
-
-    @Test
-    public void browserCallback_onChildrenChangedIsNotCalledWhenNotSubscribed2()
-            throws Exception {
-        // This test uses MediaLibrarySession.notifyChildrenChanged(ControllerInfo).
-        final String subscribedMediaId = "subscribedMediaId";
-        final String anotherMediaId = "anotherMediaId";
-        final int testChildrenCount = 101;
-
-        final MediaLibrarySessionCallback sessionCallback = new MediaLibrarySessionCallback() {
-            @Override
-            public int onSubscribe(@NonNull MediaLibrarySession session,
-                    @NonNull ControllerInfo controller, @NonNull String parentId,
-                    @Nullable LibraryParams params) {
-                if (Process.myUid() == controller.getUid()) {
-                    // Shouldn't trigger onChildrenChanged() for the browser,
-                    // because the browser didn't subscribe this media id.
-                    session.notifyChildrenChanged(
-                            controller, anotherMediaId, testChildrenCount, null);
-                }
-                return RESULT_SUCCESS;
-            }
-
-            @NonNull
-            @Override
-            public LibraryResult onGetChildren(@NonNull MediaLibrarySession session,
-                    @NonNull ControllerInfo controller, @NonNull String parentId, int page,
-                    int pageSize, LibraryParams params) {
-                return new LibraryResult(RESULT_SUCCESS,
-                        TestUtils.createMediaItems(testChildrenCount), null);
-            }
-        };
-        final CountDownLatch latch = new CountDownLatch(1);
-        final BrowserCallback controllerCallbackProxy = new BrowserCallback() {
-            @Override
-            public void onChildrenChanged(@NonNull MediaBrowser browser, @NonNull String parentId,
-                    int itemCount, LibraryParams params) {
-                // Unexpected call.
-                fail();
-                latch.countDown();
-            }
-        };
-
-        TestServiceRegistry.getInstance().setSessionCallback(sessionCallback);
-
-        LibraryResult result = createBrowser(controllerCallbackProxy)
-                .subscribe(subscribedMediaId, null)
-                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-
-        // onSubscribe() always returns SUCCESS, so success is expected.
-        assertEquals(RESULT_SUCCESS, result.getResultCode());
-
-        // But onChildrenChanged() wouldn't be called because notifyChildrenChanged() fails.
-        assertFalse(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-    }
-
-    @Test
-    public void browserCallback_onChildrenChangedIsCalledWhenSubscribed2() throws Exception {
-        // This test uses MediaLibrarySession.notifyChildrenChanged(ControllerInfo).
-        final String expectedParentId = "expectedParentId";
-        final int testChildrenCount = 101;
-        final LibraryParams testParams = createLibraryParams();
-
-        final CountDownLatch latch = new CountDownLatch(1);
-        final MediaLibrarySessionCallback sessionCallback = new MediaLibrarySessionCallback() {
-            @Override
-            public int onSubscribe(@NonNull MediaLibrarySession session,
-                    @NonNull ControllerInfo controller, @NonNull String parentId,
-                    @Nullable LibraryParams params) {
-                if (Process.myUid() == controller.getUid()) {
-                    // Should trigger onChildrenChanged() for the browser.
-                    session.notifyChildrenChanged(
-                            controller, expectedParentId, testChildrenCount, testParams);
-                }
-                return RESULT_SUCCESS;
-            }
-
-            @NonNull
-            @Override
-            public LibraryResult onGetChildren(@NonNull MediaLibrarySession session,
-                    @NonNull ControllerInfo controller, @NonNull String parentId, int page,
-                    int pageSize, LibraryParams params) {
-                return new LibraryResult(RESULT_SUCCESS,
-                        TestUtils.createMediaItems(testChildrenCount), null);
-            }
-        };
-        final BrowserCallback controllerCallbackProxy = new BrowserCallback() {
-            @Override
-            public void onChildrenChanged(@NonNull MediaBrowser browser, @NonNull String parentId,
-                    int itemCount, LibraryParams params) {
-                assertEquals(expectedParentId, parentId);
-                assertEquals(testChildrenCount, itemCount);
-                assertLibraryParamsEquals(testParams, params);
-                latch.countDown();
-            }
-        };
-
-        TestServiceRegistry.getInstance().setSessionCallback(sessionCallback);
-        LibraryResult result = createBrowser(controllerCallbackProxy)
-                .subscribe(expectedParentId, null)
-                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
-        assertEquals(RESULT_SUCCESS, result.getResultCode());
-
-        // onChildrenChanged() should be called.
-        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-    }
-}
diff --git a/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionServiceTest.java b/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionServiceTest.java
index 6b8a632..50f0dcc 100644
--- a/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionServiceTest.java
+++ b/media2/media2-session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionServiceTest.java
@@ -61,6 +61,7 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
+        TestServiceRegistry.getInstance().cleanUp();
         TestServiceRegistry.getInstance().setHandler(sHandler);
         mToken = new SessionToken(mContext,
                 new ComponentName(mContext, MockMediaSessionService.class));
diff --git a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionServiceTest.java b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionServiceTest.java
index a251a80..0ec1ad4 100644
--- a/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionServiceTest.java
+++ b/media2/media2-session/version-compat-tests/previous/service/src/androidTest/java/androidx/media2/test/service/tests/MediaSessionServiceTest.java
@@ -60,6 +60,7 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
+        TestServiceRegistry.getInstance().cleanUp();
         TestServiceRegistry.getInstance().setHandler(sHandler);
         mToken = new SessionToken(mContext,
                 new ComponentName(mContext, MockMediaSessionService.class));
diff --git a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java
index 4a8d273..76cf79c 100644
--- a/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java
+++ b/mediarouter/mediarouter/src/androidTest/java/androidx/mediarouter/media/MediaRouter2Test.java
@@ -104,7 +104,7 @@
                     mServiceImpl = (MediaRouteProviderService.MediaRouteProviderServiceImplApi30)
                             mService.mImpl;
                     mMr2ProviderServiceAdapter = mServiceImpl.mMR2ProviderServiceAdapter;
-                    return true;
+                    return mMr2ProviderServiceAdapter != null;
                 }
                 return false;
             }
@@ -224,6 +224,7 @@
         }
     }
 
+    @FlakyTest // b/182205261
     @SmallTest
     @Test
     public void setRouterParams_onRouteParamsChangedCalled() throws Exception {
@@ -233,8 +234,8 @@
         addCallback(new MediaRouter.Callback() {
             @Override
             public void onRouterParamsChanged(MediaRouter router, MediaRouterParams params) {
-                onRouterParmasChangedLatch.countDown();
                 routerParams[0] = params;
+                onRouterParmasChangedLatch.countDown();
             }
         });
 
diff --git a/navigation/navigation-compose/build.gradle b/navigation/navigation-compose/build.gradle
index ad1a40c..d384453 100644
--- a/navigation/navigation-compose/build.gradle
+++ b/navigation/navigation-compose/build.gradle
@@ -37,7 +37,7 @@
     api(projectOrArtifact(":compose:runtime:runtime-saveable"))
     api(projectOrArtifact(":compose:ui:ui"))
     api(projectOrArtifact(":lifecycle:lifecycle-viewmodel-compose"))
-    api("androidx.navigation:navigation-runtime-ktx:2.3.4")
+    api(prebuiltOrSnapshot("androidx.navigation:navigation-runtime-ktx:2.3.4"))
 
     androidTestImplementation(projectOrArtifact(":compose:material:material"))
     androidTestImplementation("androidx.navigation:navigation-testing:2.3.1")
diff --git a/paging/rxjava2/api/3.0.0-beta02.txt b/paging/rxjava2/api/3.0.0-beta02.txt
index afe197e..edfcce1 100644
--- a/paging/rxjava2/api/3.0.0-beta02.txt
+++ b/paging/rxjava2/api/3.0.0-beta02.txt
@@ -32,8 +32,6 @@
   public final class PagingRx {
     method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
-    method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
-    method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
     method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
   }
@@ -41,8 +39,6 @@
   public final class PagingRx {
     method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
-    method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
-    method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
     method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
   }
diff --git a/paging/rxjava2/api/current.ignore b/paging/rxjava2/api/current.ignore
new file mode 100644
index 0000000..08752c6
--- /dev/null
+++ b/paging/rxjava2/api/current.ignore
@@ -0,0 +1,5 @@
+// Baseline format: 1.0
+RemovedMethod: androidx.paging.rxjava2.PagingRx#getFlowable(androidx.paging.Pager<Key,Value>):
+    Removed method androidx.paging.rxjava2.PagingRx.getFlowable(androidx.paging.Pager<Key,Value>)
+RemovedMethod: androidx.paging.rxjava2.PagingRx#getObservable(androidx.paging.Pager<Key,Value>):
+    Removed method androidx.paging.rxjava2.PagingRx.getObservable(androidx.paging.Pager<Key,Value>)
diff --git a/paging/rxjava2/api/current.txt b/paging/rxjava2/api/current.txt
index afe197e..edfcce1 100644
--- a/paging/rxjava2/api/current.txt
+++ b/paging/rxjava2/api/current.txt
@@ -32,8 +32,6 @@
   public final class PagingRx {
     method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
-    method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
-    method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
     method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
   }
@@ -41,8 +39,6 @@
   public final class PagingRx {
     method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
-    method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
-    method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
     method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
   }
diff --git a/paging/rxjava2/api/public_plus_experimental_3.0.0-beta02.txt b/paging/rxjava2/api/public_plus_experimental_3.0.0-beta02.txt
index 19d0b45..c7ed5fc 100644
--- a/paging/rxjava2/api/public_plus_experimental_3.0.0-beta02.txt
+++ b/paging/rxjava2/api/public_plus_experimental_3.0.0-beta02.txt
@@ -34,8 +34,8 @@
     method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.Observable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.Observable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
     method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
-    method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
-    method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
+    method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+    method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
     method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
   }
@@ -45,8 +45,8 @@
     method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.Observable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.Observable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
     method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
-    method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
-    method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
+    method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+    method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
     method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
   }
diff --git a/paging/rxjava2/api/public_plus_experimental_current.txt b/paging/rxjava2/api/public_plus_experimental_current.txt
index 19d0b45..c7ed5fc 100644
--- a/paging/rxjava2/api/public_plus_experimental_current.txt
+++ b/paging/rxjava2/api/public_plus_experimental_current.txt
@@ -34,8 +34,8 @@
     method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.Observable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.Observable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
     method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
-    method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
-    method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
+    method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+    method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
     method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
   }
@@ -45,8 +45,8 @@
     method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <T> io.reactivex.Observable<androidx.paging.PagingData<T>> cachedIn(io.reactivex.Observable<androidx.paging.PagingData<T>>, kotlinx.coroutines.CoroutineScope scope);
     method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
-    method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
-    method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
+    method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
+    method @kotlinx.coroutines.ExperimentalCoroutinesApi public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
     method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
   }
diff --git a/paging/rxjava2/api/restricted_3.0.0-beta02.txt b/paging/rxjava2/api/restricted_3.0.0-beta02.txt
index afe197e..edfcce1 100644
--- a/paging/rxjava2/api/restricted_3.0.0-beta02.txt
+++ b/paging/rxjava2/api/restricted_3.0.0-beta02.txt
@@ -32,8 +32,6 @@
   public final class PagingRx {
     method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
-    method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
-    method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
     method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
   }
@@ -41,8 +39,6 @@
   public final class PagingRx {
     method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
-    method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
-    method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
     method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
   }
diff --git a/paging/rxjava2/api/restricted_current.ignore b/paging/rxjava2/api/restricted_current.ignore
new file mode 100644
index 0000000..08752c6
--- /dev/null
+++ b/paging/rxjava2/api/restricted_current.ignore
@@ -0,0 +1,5 @@
+// Baseline format: 1.0
+RemovedMethod: androidx.paging.rxjava2.PagingRx#getFlowable(androidx.paging.Pager<Key,Value>):
+    Removed method androidx.paging.rxjava2.PagingRx.getFlowable(androidx.paging.Pager<Key,Value>)
+RemovedMethod: androidx.paging.rxjava2.PagingRx#getObservable(androidx.paging.Pager<Key,Value>):
+    Removed method androidx.paging.rxjava2.PagingRx.getObservable(androidx.paging.Pager<Key,Value>)
diff --git a/paging/rxjava2/api/restricted_current.txt b/paging/rxjava2/api/restricted_current.txt
index afe197e..edfcce1 100644
--- a/paging/rxjava2/api/restricted_current.txt
+++ b/paging/rxjava2/api/restricted_current.txt
@@ -32,8 +32,6 @@
   public final class PagingRx {
     method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
-    method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
-    method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
     method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
   }
@@ -41,8 +39,6 @@
   public final class PagingRx {
     method @CheckResult public static <T> androidx.paging.PagingData<T> filter(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Boolean>> predicate);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> flatMap(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<java.lang.Iterable<R>>> transform);
-    method public static <Key, Value> io.reactivex.Flowable<androidx.paging.PagingData<Value>> getFlowable(androidx.paging.Pager<Key,Value>);
-    method public static <Key, Value> io.reactivex.Observable<androidx.paging.PagingData<Value>> getObservable(androidx.paging.Pager<Key,Value>);
     method @CheckResult public static <T extends R, R> androidx.paging.PagingData<R> insertSeparators(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function2<? super T,? super T,? extends io.reactivex.Maybe<R>> generator);
     method @CheckResult public static <T, R> androidx.paging.PagingData<R> map(androidx.paging.PagingData<T>, kotlin.jvm.functions.Function1<? super T,? extends io.reactivex.Single<R>> transform);
   }
diff --git a/paging/rxjava2/src/main/java/androidx/paging/rxjava2/PagingRx.kt b/paging/rxjava2/src/main/java/androidx/paging/rxjava2/PagingRx.kt
index 02189d8..d6ba2d9 100644
--- a/paging/rxjava2/src/main/java/androidx/paging/rxjava2/PagingRx.kt
+++ b/paging/rxjava2/src/main/java/androidx/paging/rxjava2/PagingRx.kt
@@ -36,7 +36,9 @@
  * An [Observable] of [PagingData], which mirrors the stream provided by [Pager.flow], but exposes
  * it as an [Observable].
  */
+// Both annotations are needed here see: https://youtrack.jetbrains.com/issue/KT-45227
 @ExperimentalCoroutinesApi
+@get:ExperimentalCoroutinesApi
 val <Key : Any, Value : Any> Pager<Key, Value>.observable: Observable<PagingData<Value>>
     get() = flow
         .conflate()
@@ -46,7 +48,9 @@
  * A [Flowable] of [PagingData], which mirrors the stream provided by [Pager.flow], but exposes
  * it as a [Flowable].
  */
+// Both annotations are needed here see: https://youtrack.jetbrains.com/issue/KT-45227
 @ExperimentalCoroutinesApi
+@get:ExperimentalCoroutinesApi
 val <Key : Any, Value : Any> Pager<Key, Value>.flowable: Flowable<PagingData<Value>>
     get() = flow
         .conflate()
diff --git a/paging/rxjava3/src/main/java/androidx/paging/rxjava3/PagingRx.kt b/paging/rxjava3/src/main/java/androidx/paging/rxjava3/PagingRx.kt
index 2a5d86b..2d76681 100644
--- a/paging/rxjava3/src/main/java/androidx/paging/rxjava3/PagingRx.kt
+++ b/paging/rxjava3/src/main/java/androidx/paging/rxjava3/PagingRx.kt
@@ -36,6 +36,8 @@
  * An [Observable] of [PagingData], which mirrors the stream provided by [Pager.flow], but exposes
  * it as an [Observable].
  */
+// Both annotations are needed here see: https://youtrack.jetbrains.com/issue/KT-45227
+@ExperimentalCoroutinesApi
 @get:ExperimentalCoroutinesApi
 val <Key : Any, Value : Any> Pager<Key, Value>.observable: Observable<PagingData<Value>>
     get() = flow
@@ -46,6 +48,8 @@
  * A [Flowable] of [PagingData], which mirrors the stream provided by [Pager.flow], but exposes
  * it as a [Flowable].
  */
+// Both annotations are needed here see: https://youtrack.jetbrains.com/issue/KT-45227
+@ExperimentalCoroutinesApi
 @get:ExperimentalCoroutinesApi
 val <Key : Any, Value : Any> Pager<Key, Value>.flowable: Flowable<PagingData<Value>>
     get() = flow
diff --git a/preference/preference/build.gradle b/preference/preference/build.gradle
index 21edee3..5cc86e5 100644
--- a/preference/preference/build.gradle
+++ b/preference/preference/build.gradle
@@ -26,7 +26,7 @@
 }
 
 dependencies {
-    api(project(":annotation:annotation"))
+    api("androidx.annotation:annotation:1.2.0-rc01")
     api("androidx.appcompat:appcompat:1.1.0")
     // Use the latest version of core library for verifying insets visibility
     api(project(":core:core"))
diff --git a/preference/preference/res/values-cs/strings.xml b/preference/preference/res/values-cs/strings.xml
index 050678d..a07bdd1 100644
--- a/preference/preference/res/values-cs/strings.xml
+++ b/preference/preference/res/values-cs/strings.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="v7_preference_on" msgid="89551595707643515">"ZAP"</string>
-    <string name="v7_preference_off" msgid="3140233346420563315">"Vypnutí"</string>
+    <string name="v7_preference_on" msgid="89551595707643515">"Zapnuto"</string>
+    <string name="v7_preference_off" msgid="3140233346420563315">"Vypnuto"</string>
     <string name="expand_button_title" msgid="2427401033573778270">"RozšíÅ™ená nastavení"</string>
     <string name="summary_collapsed_preference_list" msgid="9167775378838880170">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
     <string name="copy" msgid="6083905920877235314">"Kopírovat"</string>
diff --git a/preference/preference/res/values-es-rUS/strings.xml b/preference/preference/res/values-es-rUS/strings.xml
index 7f45355..06dfaf0 100644
--- a/preference/preference/res/values-es-rUS/strings.xml
+++ b/preference/preference/res/values-es-rUS/strings.xml
@@ -2,7 +2,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="v7_preference_on" msgid="89551595707643515">"ACTIVADO"</string>
-    <string name="v7_preference_off" msgid="3140233346420563315">"DESACTIVADA"</string>
+    <string name="v7_preference_off" msgid="3140233346420563315">"DESACTIVADO"</string>
     <string name="expand_button_title" msgid="2427401033573778270">"Opciones avanzadas"</string>
     <string name="summary_collapsed_preference_list" msgid="9167775378838880170">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
     <string name="copy" msgid="6083905920877235314">"Copiar"</string>
diff --git a/preference/preference/res/values-sk/strings.xml b/preference/preference/res/values-sk/strings.xml
index 5006dab..5b535d01 100644
--- a/preference/preference/res/values-sk/strings.xml
+++ b/preference/preference/res/values-sk/strings.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="v7_preference_on" msgid="89551595707643515">"ZAP."</string>
-    <string name="v7_preference_off" msgid="3140233346420563315">"VYP."</string>
+    <string name="v7_preference_on" msgid="89551595707643515">"Zapnuté"</string>
+    <string name="v7_preference_off" msgid="3140233346420563315">"Vypnuté"</string>
     <string name="expand_button_title" msgid="2427401033573778270">"Rozšírené"</string>
     <string name="summary_collapsed_preference_list" msgid="9167775378838880170">"<xliff:g id="CURRENT_ITEMS">%1$s</xliff:g>, <xliff:g id="ADDED_ITEMS">%2$s</xliff:g>"</string>
     <string name="copy" msgid="6083905920877235314">"KopírovaÅ¥"</string>
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/AutoMigrationProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/AutoMigrationProcessor.kt
index adeeeb5..b9d992c 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/AutoMigrationProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/AutoMigrationProcessor.kt
@@ -104,7 +104,8 @@
             element = element,
             from = fromSchemaBundle.version,
             to = toSchemaBundle.version,
-            addedColumns = schemaDiff.added
+            addedColumns = schemaDiff.addedColumn,
+            addedTables = schemaDiff.addedTable
         )
     }
 
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt b/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
index 7773547..05a3b6a 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
@@ -850,6 +850,11 @@
             "renamed. This change is not currently supported by AutoMigration."
     }
 
+    fun removedOrRenamedTableFound(tableName: String): String {
+        return "Table '$tableName' has been either removed or " +
+            "renamed. This change is not currently supported by AutoMigration."
+    }
+
     val AUTO_MIGRATION_FOUND_BUT_EXPORT_SCHEMA_OFF = "Cannot create auto-migrations when export " +
         "schema is OFF."
 }
\ No newline at end of file
diff --git a/room/compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt b/room/compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt
index 80435f6..a0a327d 100644
--- a/room/compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/util/SchemaDiffer.kt
@@ -17,7 +17,6 @@
 package androidx.room.util
 
 import androidx.room.migration.bundle.DatabaseBundle
-import androidx.room.migration.bundle.EntityBundle
 import androidx.room.processor.ProcessorErrors
 import androidx.room.vo.AutoMigrationResult
 
@@ -30,9 +29,11 @@
  * Contains the added, changed and removed columns detected.
  */
 data class SchemaDiffResult(
-    val added: List<AutoMigrationResult.AddedColumn>,
-    val changed: List<AutoMigrationResult.ChangedColumn>,
-    val removed: List<AutoMigrationResult.RemovedColumn>
+    val addedColumn: MutableList<AutoMigrationResult.AddedColumn>,
+    val changedColumn: List<AutoMigrationResult.ChangedColumn>,
+    val removedColumn: List<AutoMigrationResult.RemovedColumn>,
+    val addedTable: List<AutoMigrationResult.AddedTable>,
+    val removedTable: List<AutoMigrationResult.RemovedTable>
 )
 
 /**
@@ -53,8 +54,8 @@
      * @return the AutoMigrationResult containing the schema changes detected
      */
     fun diffSchemas(): SchemaDiffResult {
-        val addedTables = mutableListOf<EntityBundle>()
-        val removedTables = mutableListOf<EntityBundle>()
+        val addedTables = mutableListOf<AutoMigrationResult.AddedTable>()
+        val removedTables = mutableListOf<AutoMigrationResult.RemovedTable>()
 
         val addedColumns = mutableListOf<AutoMigrationResult.AddedColumn>()
         val changedColumns = mutableListOf<AutoMigrationResult.ChangedColumn>()
@@ -65,7 +66,7 @@
         fromSchemaBundle.entitiesByTableName.forEach { v1Table ->
             val v2Table = toSchemaBundle.entitiesByTableName[v1Table.key]
             if (v2Table == null) {
-                removedTables.add(v1Table.value)
+                removedTables.add(AutoMigrationResult.RemovedTable(v1Table.value))
             } else {
                 val v1Columns = v1Table.value.fieldsByColumnName
                 val v2Columns = v2Table.fieldsByColumnName
@@ -96,7 +97,7 @@
         toSchemaBundle.entitiesByTableName.forEach { v2Table ->
             val v1Table = fromSchemaBundle.entitiesByTableName[v2Table.key]
             if (v1Table == null) {
-                addedTables.add(v2Table.value)
+                addedTables.add(AutoMigrationResult.AddedTable(v2Table.value))
             } else {
                 val v2Columns = v2Table.value.fieldsByColumnName
                 val v1Columns = v1Table.fieldsByColumnName
@@ -104,7 +105,7 @@
                     val match = v1Columns[v2Column.key]
                     if (match == null) {
                         if (v2Column.value.isNonNull && v2Column.value.defaultValue == null) {
-                            throw DiffException(
+                            diffError(
                                 ProcessorErrors.newNotNullColumnMustHaveDefaultValue(v2Column.key)
                             )
                         }
@@ -121,15 +122,17 @@
 
         if (changedColumns.isNotEmpty()) {
             changedColumns.forEach { changedColumn ->
-                throw DiffException(
+                diffError(
                     ProcessorErrors.columnWithChangedSchemaFound(
                         changedColumn.originalFieldBundle.columnName
                     )
                 )
             }
-        } else if (removedColumns.isNotEmpty()) {
+        }
+
+        if (removedColumns.isNotEmpty()) {
             removedColumns.forEach { removedColumn ->
-                throw DiffException(
+                diffError(
                     ProcessorErrors.removedOrRenamedColumnFound(
                         removedColumn.fieldBundle.columnName
                     )
@@ -137,10 +140,26 @@
             }
         }
 
+        if (removedTables.isNotEmpty()) {
+            removedTables.forEach { removedTable ->
+                diffError(
+                    ProcessorErrors.removedOrRenamedTableFound(
+                        removedTable.entityBundle.tableName
+                    )
+                )
+            }
+        }
+
         return SchemaDiffResult(
-            added = addedColumns,
-            changed = changedColumns,
-            removed = removedColumns
+            addedColumn = addedColumns,
+            changedColumn = changedColumns,
+            removedColumn = removedColumns,
+            addedTable = addedTables,
+            removedTable = removedTables
         )
     }
+
+    private fun diffError(errorMsg: String) {
+        throw DiffException(errorMsg)
+    }
 }
\ No newline at end of file
diff --git a/room/compiler/src/main/kotlin/androidx/room/vo/AutoMigrationResult.kt b/room/compiler/src/main/kotlin/androidx/room/vo/AutoMigrationResult.kt
index 6931854..91d4bd6 100644
--- a/room/compiler/src/main/kotlin/androidx/room/vo/AutoMigrationResult.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/vo/AutoMigrationResult.kt
@@ -17,6 +17,7 @@
 package androidx.room.vo
 
 import androidx.room.compiler.processing.XTypeElement
+import androidx.room.migration.bundle.EntityBundle
 import androidx.room.migration.bundle.FieldBundle
 import com.squareup.javapoet.ClassName
 
@@ -24,7 +25,8 @@
     val element: XTypeElement,
     val from: Int?,
     val to: Int?,
-    val addedColumns: List<AddedColumn>
+    val addedColumns: List<AddedColumn>,
+    val addedTables: List<AddedTable>
 ) {
 
     val implTypeName: ClassName by lazy {
@@ -60,4 +62,18 @@
      * renamed.
      */
     data class RemovedColumn(val tableName: String, val fieldBundle: FieldBundle)
+
+    /**
+     * Stores the table that was added to a database in a newer version.
+     */
+    data class AddedTable(val entityBundle: EntityBundle)
+
+    /**
+     * Stores the table that was present in the old version of a database but is not present in a
+     * new version of the same database, either because it was removed or renamed.
+     *
+     * In the current implementation, we cannot differ between whether the table was removed or
+     * renamed.
+     */
+    data class RemovedTable(val entityBundle: EntityBundle)
 }
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
index 3324771..c6a7b9c 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/AutoMigrationWriter.kt
@@ -76,6 +76,9 @@
      * @param migrateFunctionBuilder Builder for the migrate() function to be generated
      */
     private fun addAutoMigrationResultToMigrate(migrateFunctionBuilder: MethodSpec.Builder) {
+        if (autoMigrationResult.addedTables.isNotEmpty()) {
+            addNewTableStatements(migrateFunctionBuilder)
+        }
         if (autoMigrationResult.addedColumns.isNotEmpty()) {
             addNewColumnStatements(migrateFunctionBuilder)
         }
@@ -91,11 +94,11 @@
         autoMigrationResult.addedColumns.forEach {
             val addNewColumnSql = buildString {
                 append(
-                    "ALTER TABLE '${it.tableName}' ADD COLUMN `${it.fieldBundle.columnName}` " +
+                    "ALTER TABLE `${it.tableName}` ADD COLUMN `${it.fieldBundle.columnName}` " +
                         "${it.fieldBundle.affinity} "
                 )
                 if (it.fieldBundle.isNonNull) {
-                    append("NOT NULL DEFAULT '${it.fieldBundle.defaultValue}'")
+                    append("NOT NULL DEFAULT `${it.fieldBundle.defaultValue}`")
                 } else {
                     append("DEFAULT NULL")
                 }
@@ -105,6 +108,20 @@
     }
 
     /**
+     * Adds the appropriate SQL statements for adding new tables to a database, into the
+     * generated migrate() function.
+     *
+     * @param migrateFunctionBuilder Builder for the migrate() function to be generated
+     */
+    private fun addNewTableStatements(migrateFunctionBuilder: MethodSpec.Builder) {
+        autoMigrationResult.addedTables.forEach { addedTable ->
+            migrateFunctionBuilder.addStatement(
+                "database.execSQL($S)", addedTable.entityBundle.createTable()
+            )
+        }
+    }
+
+    /**
      * Builds the constructor of the generated AutoMigration.
      *
      * @return The constructor of the generated AutoMigration
diff --git a/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithDefault.java b/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithDefault.java
index 8a5dd5b1..b0882e0 100644
--- a/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithDefault.java
+++ b/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithDefault.java
@@ -17,7 +17,7 @@
 
     @Override
     public void migrate(@NonNull SupportSQLiteDatabase database) {
-        database.execSQL("ALTER TABLE 'Song' ADD COLUMN `artistId` INTEGER NOT NULL DEFAULT '0'");
+        database.execSQL("ALTER TABLE `Song` ADD COLUMN `artistId` INTEGER NOT NULL DEFAULT `0`");
         onPostMigrate(database);
     }
 }
diff --git a/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithNewTableAdded.java b/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithNewTableAdded.java
new file mode 100644
index 0000000..3589a08
--- /dev/null
+++ b/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithNewTableAdded.java
@@ -0,0 +1,25 @@
+package foo.bar;
+
+import androidx.annotation.NonNull;
+import androidx.room.migration.AutoMigrationCallback;
+import androidx.room.migration.Migration;
+import androidx.sqlite.db.SupportSQLiteDatabase;
+import java.lang.Override;
+import java.lang.SuppressWarnings;
+import javax.annotation.processing.Generated;
+
+@Generated("androidx.room.RoomProcessor")
+@SuppressWarnings({"unchecked", "deprecation"})
+class ValidAutoMigrationWithNewTableAdded_Impl extends Migration implements AutoMigrationCallback {
+    public ValidAutoMigrationWithNewTableAdded_Impl() {
+        super(1, 2);
+    }
+
+    @Override
+    public void migrate(@NonNull SupportSQLiteDatabase database) {
+        database.execSQL("CREATE TABLE IF NOT EXISTS `Artist` (`artistId` INTEGER NOT NULL, `name` TEXT NOT NULL, PRIMARY KEY(`artistId`))");
+        database.execSQL("CREATE TABLE IF NOT EXISTS `Album` (`albumId` INTEGER NOT NULL, PRIMARY KEY(`albumId`))");
+        database.execSQL("ALTER TABLE `Song` ADD COLUMN `songId` INTEGER DEFAULT NULL");
+        onPostMigrate(database);
+    }
+}
diff --git a/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithoutDefault.java b/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithoutDefault.java
index 5747c04..93eb47d 100644
--- a/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithoutDefault.java
+++ b/room/compiler/src/test/data/autoMigrationWriter/output/ValidAutoMigrationWithoutDefault.java
@@ -17,7 +17,7 @@
 
     @Override
     public void migrate(@NonNull SupportSQLiteDatabase database) {
-        database.execSQL("ALTER TABLE 'Song' ADD COLUMN `artistId` INTEGER DEFAULT NULL");
+        database.execSQL("ALTER TABLE `Song` ADD COLUMN `artistId` INTEGER DEFAULT NULL");
         onPostMigrate(database);
     }
 }
diff --git a/room/compiler/src/test/kotlin/androidx/room/util/SchemaDifferTest.kt b/room/compiler/src/test/kotlin/androidx/room/util/SchemaDifferTest.kt
index 6be4eea..0dd90dc 100644
--- a/room/compiler/src/test/kotlin/androidx/room/util/SchemaDifferTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/util/SchemaDifferTest.kt
@@ -34,7 +34,7 @@
             fromSchemaBundle = from.database,
             toSchemaBundle = toColumnAddedWithColumnInfoDefaultValue.database
         ).diffSchemas()
-        assertThat(schemaDiffResult.added[0].fieldBundle.columnName).isEqualTo("artistId")
+        assertThat(schemaDiffResult.addedColumn[0].fieldBundle.columnName).isEqualTo("artistId")
     }
 
     @Test
@@ -53,6 +53,16 @@
     }
 
     @Test
+    fun testTableAddedWithColumnInfoDefaultValue() {
+        val schemaDiffResult = SchemaDiffer(
+            fromSchemaBundle = from.database,
+            toSchemaBundle = toTableAddedWithColumnInfoDefaultValue.database
+        ).diffSchemas()
+        assertThat(schemaDiffResult.addedTable[0].entityBundle.tableName).isEqualTo("Artist")
+        assertThat(schemaDiffResult.addedTable[1].entityBundle.tableName).isEqualTo("Album")
+    }
+
+    @Test
     fun testColumnRenamed() {
         try {
             SchemaDiffer(
@@ -204,7 +214,7 @@
      * The length column is removed from the first version. No other changes made.
      *
      */
-    val toColumnRemoved = SchemaBundle(
+    private val toColumnRemoved = SchemaBundle(
         2,
         DatabaseBundle(
             2,
@@ -248,7 +258,7 @@
      * Room will put null for that default value in the exported schema. In this case we
      * can't migrate.
      */
-    val toColumnAddedWithNoDefaultValue = SchemaBundle(
+    private val toColumnAddedWithNoDefaultValue = SchemaBundle(
         2,
         DatabaseBundle(
             2,
@@ -307,7 +317,7 @@
      */
     // TODO: We currently do not support column renames as we can't detect rename or deletion
     //  yet.
-    val toColumnRenamed = SchemaBundle(
+    private val toColumnRenamed = SchemaBundle(
         2,
         DatabaseBundle(
             2,
@@ -405,4 +415,147 @@
             mutableListOf()
         )
     )
+
+    private val toTableAddedWithColumnInfoDefaultValue = SchemaBundle(
+        1,
+        DatabaseBundle(
+            1,
+            "",
+            mutableListOf(
+                EntityBundle(
+                    "Song",
+                    "CREATE TABLE IF NOT EXISTS `Song` (`id` INTEGER NOT NULL, " +
+                        "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+                    listOf(
+                        FieldBundle(
+                            "id",
+                            "id",
+                            "INTEGER",
+                            true,
+                            "1"
+                        ),
+                        FieldBundle(
+                            "title",
+                            "title",
+                            "TEXT",
+                            true,
+                            ""
+                        ),
+                        FieldBundle(
+                            "length",
+                            "length",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(
+                        false,
+                        mutableListOf("id")
+                    ),
+                    mutableListOf(),
+                    mutableListOf()
+                ),
+                EntityBundle(
+                    "Artist",
+                    "CREATE TABLE IF NOT EXISTS `Artist` (`artistId` INTEGER NOT NULL, `name` " +
+                        "TEXT NOT NULL, PRIMARY KEY(`artistId`))",
+                    listOf(
+                        FieldBundle(
+                            "artistId",
+                            "artistId",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(true, listOf("artistId")),
+                    listOf(),
+                    listOf()
+                ),
+                EntityBundle(
+                    "Album",
+                    "CREATE TABLE IF NOT EXISTS `Album` (`albumId` INTEGER NOT NULL, `name` TEXT " +
+                        "NOT NULL, PRIMARY KEY(`albumId`))",
+                    listOf(
+                        FieldBundle(
+                            "albumId",
+                            "albumId",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(true, listOf("albumId")),
+                    listOf(),
+                    listOf()
+                )
+            ),
+            mutableListOf(),
+            mutableListOf()
+        )
+    )
+
+    val toTableAddedWithNoDefaultValue = SchemaBundle(
+        1,
+        DatabaseBundle(
+            1,
+            "",
+            mutableListOf(
+                EntityBundle(
+                    "Song",
+                    "CREATE TABLE IF NOT EXISTS `Song` (`id` INTEGER NOT NULL, " +
+                        "`title` TEXT NOT NULL, `length` INTEGER NOT NULL, PRIMARY KEY(`id`))",
+                    listOf(
+                        FieldBundle(
+                            "id",
+                            "id",
+                            "INTEGER",
+                            true,
+                            "1"
+                        ),
+                        FieldBundle(
+                            "title",
+                            "title",
+                            "TEXT",
+                            true,
+                            ""
+                        ),
+                        FieldBundle(
+                            "length",
+                            "length",
+                            "INTEGER",
+                            true,
+                            "1"
+                        )
+                    ),
+                    PrimaryKeyBundle(
+                        false,
+                        mutableListOf("id")
+                    ),
+                    mutableListOf(),
+                    mutableListOf()
+                ),
+                EntityBundle(
+                    "Album",
+                    "CREATE TABLE IF NOT EXISTS `Album` (`id` INTEGER NOT NULL, `name` TEXT NOT " +
+                        "NULL, PRIMARY KEY(`id`))",
+                    listOf(
+                        FieldBundle(
+                            "albumId",
+                            "albumId",
+                            "INTEGER",
+                            true,
+                            null
+                        )
+                    ),
+                    PrimaryKeyBundle(true, listOf("id")),
+                    listOf(),
+                    listOf()
+                )
+            ),
+            mutableListOf(),
+            mutableListOf()
+        )
+    )
 }
\ No newline at end of file
diff --git a/room/compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt b/room/compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt
index 4176a0b..5379314 100644
--- a/room/compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/writer/AutoMigrationWriterTest.kt
@@ -19,7 +19,9 @@
 import androidx.room.compiler.processing.XElement
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.runProcessorTest
+import androidx.room.migration.bundle.EntityBundle
 import androidx.room.migration.bundle.FieldBundle
+import androidx.room.migration.bundle.PrimaryKeyBundle
 import androidx.room.vo.AutoMigrationResult
 import loadTestSource
 import org.junit.Test
@@ -61,7 +63,8 @@
                             "0"
                         )
                     )
-                )
+                ),
+                addedTables = listOf()
             )
             AutoMigrationWriter(mock(XElement::class.java), autoMigrationResultWithNewAddedColumn)
                 .write(invocation.processingEnv)
@@ -110,7 +113,8 @@
                             ""
                         )
                     )
-                )
+                ),
+                addedTables = listOf()
             )
             AutoMigrationWriter(mock(XElement::class.java), autoMigrationResultWithNewAddedColumn)
                 .write(invocation.processingEnv)
@@ -125,4 +129,95 @@
             }
         }
     }
+
+    @Test
+    fun validAutoMigrationWithNewTableAdded() {
+        val source = Source.java(
+            "foo.bar.ValidAutoMigrationWithoutDefault",
+            """
+            package foo.bar;
+            import androidx.room.migration.AutoMigrationCallback;
+            import androidx.room.AutoMigration;
+            import androidx.sqlite.db.SupportSQLiteDatabase;
+            @AutoMigration(from=1, to=2)
+            interface ValidAutoMigrationWithNewTableAdded extends AutoMigrationCallback {
+                @Override
+                void onPostMigrate(SupportSQLiteDatabase db);
+            }
+            """.trimIndent()
+        )
+
+        runProcessorTest(listOf(source)) { invocation ->
+            val autoMigrationResultWithNewTableAdded = AutoMigrationResult(
+                element = invocation.processingEnv.requireTypeElement(
+                    "foo.bar.ValidAutoMigrationWithNewTableAdded"
+                ),
+                from = 1,
+                to = 2,
+                addedColumns = listOf(
+                    AutoMigrationResult.AddedColumn(
+                        "Song",
+                        FieldBundle(
+                            "songId",
+                            "songId",
+                            "INTEGER",
+                            false,
+                            ""
+                        )
+                    )
+                ),
+                addedTables = listOf(
+                    AutoMigrationResult.AddedTable(
+                        EntityBundle(
+                            "Artist",
+                            "CREATE TABLE IF NOT EXISTS `Artist` (`artistId` INTEGER NOT NULL, " +
+                                "`name` TEXT NOT NULL, PRIMARY KEY(`artistId`))",
+                            listOf(
+                                FieldBundle(
+                                    "artistId",
+                                    "artistId",
+                                    "INTEGER",
+                                    true,
+                                    "1"
+                                )
+                            ),
+                            PrimaryKeyBundle(true, listOf("artistId")),
+                            listOf(),
+                            listOf()
+                        ),
+                    ),
+                    AutoMigrationResult.AddedTable(
+                        EntityBundle(
+                            "Album",
+                            "CREATE TABLE IF NOT EXISTS `Album` (`albumId` INTEGER NOT NULL, " +
+                                "PRIMARY KEY(`albumId`))",
+                            listOf(
+                                FieldBundle(
+                                    "albumId",
+                                    "albumId",
+                                    "INTEGER",
+                                    true,
+                                    "1"
+                                )
+                            ),
+                            PrimaryKeyBundle(true, listOf("albumId")),
+                            listOf(),
+                            listOf()
+                        )
+                    )
+                )
+            )
+            AutoMigrationWriter(mock(XElement::class.java), autoMigrationResultWithNewTableAdded)
+                .write(invocation.processingEnv)
+
+            invocation.assertCompilationResult {
+                generatedSource(
+                    loadTestSource(
+                        "autoMigrationWriter/output/ValidAutoMigrationWithNewTableAdded.java",
+                        "foo.bar.ValidAutoMigrationWithNewTableAdded_Impl"
+                    )
+                )
+            }
+        }
+    }
 }
diff --git a/settings.gradle b/settings.gradle
index dfba23f..77a3e7d 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -232,9 +232,12 @@
 includeProject(":compose:animation", "compose/animation", [BuildType.COMPOSE])
 includeProject(":compose:animation:animation", "compose/animation/animation", [BuildType.COMPOSE])
 includeProject(":compose:animation:animation-core", "compose/animation/animation-core", [BuildType.COMPOSE])
+includeProject(":compose:animation:animation-core:animation-core-benchmark", "compose/animation/animation-core/benchmark", [BuildType.COMPOSE])
 includeProject(":compose:animation:animation-core:animation-core-samples", "compose/animation/animation-core/samples", [BuildType.COMPOSE])
 includeProject(":compose:animation:animation:integration-tests:animation-demos", "compose/animation/animation/integration-tests/animation-demos", [BuildType.COMPOSE])
 includeProject(":compose:animation:animation:animation-samples", "compose/animation/animation/samples", [BuildType.COMPOSE])
+includeProject(":compose:benchmark-utils", "compose/benchmark-utils", [BuildType.COMPOSE])
+includeProject(":compose:benchmark-utils:benchmark-utils-benchmark", "compose/benchmark-utils/benchmark", [BuildType.COMPOSE])
 includeProject(":compose:compiler:compiler", "compose/compiler/compiler", [BuildType.COMPOSE])
 includeProject(":compose:compiler:compiler-hosted", "compose/compiler/compiler-hosted", [BuildType.COMPOSE])
 includeProject(":compose:compiler:compiler-hosted:integration-tests", "compose/compiler/compiler-hosted/integration-tests", [BuildType.COMPOSE])
@@ -290,9 +293,12 @@
 includeProject(":compose:test-utils", "compose/test-utils", [BuildType.COMPOSE])
 includeProject(":compose:ui", "compose/ui", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui", "compose/ui/ui", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-benchmark", "compose/ui/ui/benchmark", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui-android-stubs", "compose/ui/ui-android-stubs", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui-geometry", "compose/ui/ui-geometry", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui-graphics", "compose/ui/ui-graphics", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-graphics:ui-graphics-benchmark", "compose/ui/ui-graphics/benchmark", [BuildType.COMPOSE])
+includeProject(":compose:ui:ui-graphics:ui-graphics-benchmark:test", "compose/ui/ui-graphics/benchmark/test", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui-graphics:ui-graphics-samples", "compose/ui/ui-graphics/samples", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui-inspection", "compose/ui/ui-inspection", [BuildType.COMPOSE])
 includeProject(":compose:ui:ui-lint", "compose/ui/ui-lint", [BuildType.COMPOSE])
@@ -350,6 +356,8 @@
 includeProject(":emoji-bundled", "emoji/bundled", [BuildType.MAIN])
 includeProject(":emoji2:emoji2", "emoji2/emoji2", [BuildType.MAIN])
 includeProject(":emoji2:emoji2-bundled", "emoji2/emoji2-bundled", [BuildType.MAIN])
+includeProject(":emoji2:emoji2-views", "emoji2/emoji2-views", [BuildType.MAIN])
+includeProject(":emoji2:emoji2-views-core", "emoji2/emoji2-views-core", [BuildType.MAIN])
 includeProject(":enterprise-feedback", "enterprise/feedback", [BuildType.MAIN])
 includeProject(":enterprise-feedback-testing", "enterprise/feedback/testing", [BuildType.MAIN])
 includeProject(":exifinterface:exifinterface", "exifinterface/exifinterface", [BuildType.MAIN])
@@ -414,8 +422,8 @@
 includeProject(":lifecycle:lifecycle-viewmodel-ktx", "lifecycle/lifecycle-viewmodel-ktx", [BuildType.MAIN, BuildType.FLAN])
 includeProject(":lifecycle:lifecycle-viewmodel-savedstate", "lifecycle/lifecycle-viewmodel-savedstate", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR])
 includeProject(":lint-checks", "lint-checks")
-includeProject(":lint-checks:integration-tests", "lint-checks/integration-tests", [BuildType.COMPOSE])
-includeProject(":lint-checks:tests", "lint-checks/tests", [BuildType.MAIN])
+includeProject(":lint-checks:integration-tests", "lint-checks/integration-tests")
+includeProject(":lint-checks:tests", "lint-checks/tests")
 includeProject(":lint-demos:lint-demo-appcompat", "lint-demos/lint-demo-appcompat", [BuildType.MAIN])
 includeProject(":loader:loader", "loader/loader", [BuildType.MAIN])
 includeProject(":loader:loader-ktx", "loader/loader-ktx", [BuildType.MAIN])
@@ -573,6 +581,7 @@
 includeProject(":wear:wear-watchface-editor-samples", "wear/wear-watchface-editor/samples", [BuildType.MAIN, BuildType.WEAR])
 includeProject(":wear:wear-watchface-guava", "wear/wear-watchface/guava", [BuildType.MAIN, BuildType.WEAR])
 includeProject(":wear:wear-watchface-samples", "wear/wear-watchface/samples", [BuildType.MAIN, BuildType.WEAR])
+includeProject(":wear:wear-watchface-samples-minimal", "wear/wear-watchface/samples/minimal", [BuildType.MAIN, BuildType.WEAR])
 includeProject(":wear:wear-watchface-style", "wear/wear-watchface-style", [BuildType.MAIN, BuildType.WEAR])
 includeProject(":webkit:integration-tests:testapp", "webkit/integration-tests/testapp", [BuildType.MAIN])
 includeProject(":webkit:webkit", "webkit/webkit", [BuildType.MAIN])
diff --git a/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/InvalidationTest.kt b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/InvalidationTest.kt
index 7918eea..ea6425a 100644
--- a/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/InvalidationTest.kt
+++ b/sqlite/sqlite-inspection/src/androidTest/java/androidx/sqlite/inspection/test/InvalidationTest.kt
@@ -48,6 +48,7 @@
     val temporaryFolder = TemporaryFolder(getInstrumentation().context.cacheDir)
 
     @Test
+    @FlakyTest(bugId = 159202455)
     fun test_exec_hook_methods() = test_simple_hook_methods(
         listOf(
             "execute()V",
diff --git a/tracing/tracing/src/androidTest/java/androidx/tracing/TraceTest.java b/tracing/tracing/src/androidTest/java/androidx/tracing/TraceTest.java
index 1e24c25..b9f58ca 100644
--- a/tracing/tracing/src/androidTest/java/androidx/tracing/TraceTest.java
+++ b/tracing/tracing/src/androidTest/java/androidx/tracing/TraceTest.java
@@ -77,6 +77,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 29) // SELinux
     public void beginAndEndSectionAsync() throws IOException {
         startTrace();
         Trace.beginAsyncSection("beginAndEndSectionAsync", /*cookie=*/5099);
@@ -88,6 +89,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 29) // SELinux
     public void setCounter() throws IOException {
         startTrace();
         Trace.setCounter("counterName", 42);
diff --git a/wear/wear-complications-data/api/current.txt b/wear/wear-complications-data/api/current.txt
index f9f2248..d1e2d37 100644
--- a/wear/wear-complications-data/api/current.txt
+++ b/wear/wear-complications-data/api/current.txt
@@ -231,6 +231,18 @@
     enum_constant public static final androidx.wear.complications.data.ComplicationType SMALL_IMAGE;
   }
 
+  public final class CountDownTimeReference {
+    ctor public CountDownTimeReference(long dateTimeMillis);
+    method public long getDateTimeMillis();
+    property public final long dateTimeMillis;
+  }
+
+  public final class CountUpTimeReference {
+    ctor public CountUpTimeReference(long dateTimeMillis);
+    method public long getDateTimeMillis();
+    property public final long dateTimeMillis;
+  }
+
   public final class DataKt {
   }
 
@@ -470,7 +482,8 @@
   }
 
   public static final class TimeDifferenceComplicationText.Builder {
-    ctor public TimeDifferenceComplicationText.Builder(androidx.wear.complications.data.TimeDifferenceStyle style, androidx.wear.complications.data.TimeReference reference);
+    ctor public TimeDifferenceComplicationText.Builder(androidx.wear.complications.data.TimeDifferenceStyle style, androidx.wear.complications.data.CountUpTimeReference countUpTimeReference);
+    ctor public TimeDifferenceComplicationText.Builder(androidx.wear.complications.data.TimeDifferenceStyle style, androidx.wear.complications.data.CountDownTimeReference countDownTimeReference);
     method public androidx.wear.complications.data.TimeDifferenceComplicationText build();
     method public androidx.wear.complications.data.TimeDifferenceComplicationText.Builder setDisplayAsNow(boolean displayAsNow);
     method public androidx.wear.complications.data.TimeDifferenceComplicationText.Builder setMinimumUnit(java.util.concurrent.TimeUnit? minimumUnit);
@@ -521,25 +534,6 @@
     method public androidx.wear.complications.data.TimeRange between(long startDateTimeMillis, long endDateTimeMillis);
   }
 
-  public final class TimeReference {
-    method public static androidx.wear.complications.data.TimeReference between(long startDateTimeMillis, long endDateTimeMillis);
-    method public static androidx.wear.complications.data.TimeReference ending(long dateTimeMillis);
-    method public long getEndDateTimeMillis();
-    method public long getStartDateTimeMillis();
-    method public boolean hasEndDateTimeMillis();
-    method public boolean hasStartDateTimeMillis();
-    method public static androidx.wear.complications.data.TimeReference starting(long dateTimeMillis);
-    property public final long endDateTimeMillis;
-    property public final long startDateTimeMillis;
-    field public static final androidx.wear.complications.data.TimeReference.Companion Companion;
-  }
-
-  public static final class TimeReference.Companion {
-    method public androidx.wear.complications.data.TimeReference between(long startDateTimeMillis, long endDateTimeMillis);
-    method public androidx.wear.complications.data.TimeReference ending(long dateTimeMillis);
-    method public androidx.wear.complications.data.TimeReference starting(long dateTimeMillis);
-  }
-
   public final class TypeKt {
   }
 
diff --git a/wear/wear-complications-data/api/public_plus_experimental_current.txt b/wear/wear-complications-data/api/public_plus_experimental_current.txt
index 7d78c5c..9d6e270 100644
--- a/wear/wear-complications-data/api/public_plus_experimental_current.txt
+++ b/wear/wear-complications-data/api/public_plus_experimental_current.txt
@@ -231,6 +231,18 @@
     enum_constant public static final androidx.wear.complications.data.ComplicationType SMALL_IMAGE;
   }
 
+  public final class CountDownTimeReference {
+    ctor public CountDownTimeReference(long dateTimeMillis);
+    method public long getDateTimeMillis();
+    property public final long dateTimeMillis;
+  }
+
+  public final class CountUpTimeReference {
+    ctor public CountUpTimeReference(long dateTimeMillis);
+    method public long getDateTimeMillis();
+    property public final long dateTimeMillis;
+  }
+
   public final class DataKt {
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.wear.complications.data.ComplicationData asApiComplicationData(android.support.wearable.complications.ComplicationData);
   }
@@ -481,7 +493,8 @@
   }
 
   public static final class TimeDifferenceComplicationText.Builder {
-    ctor public TimeDifferenceComplicationText.Builder(androidx.wear.complications.data.TimeDifferenceStyle style, androidx.wear.complications.data.TimeReference reference);
+    ctor public TimeDifferenceComplicationText.Builder(androidx.wear.complications.data.TimeDifferenceStyle style, androidx.wear.complications.data.CountUpTimeReference countUpTimeReference);
+    ctor public TimeDifferenceComplicationText.Builder(androidx.wear.complications.data.TimeDifferenceStyle style, androidx.wear.complications.data.CountDownTimeReference countDownTimeReference);
     method public androidx.wear.complications.data.TimeDifferenceComplicationText build();
     method public androidx.wear.complications.data.TimeDifferenceComplicationText.Builder setDisplayAsNow(boolean displayAsNow);
     method public androidx.wear.complications.data.TimeDifferenceComplicationText.Builder setMinimumUnit(java.util.concurrent.TimeUnit? minimumUnit);
@@ -532,25 +545,6 @@
     method public androidx.wear.complications.data.TimeRange between(long startDateTimeMillis, long endDateTimeMillis);
   }
 
-  public final class TimeReference {
-    method public static androidx.wear.complications.data.TimeReference between(long startDateTimeMillis, long endDateTimeMillis);
-    method public static androidx.wear.complications.data.TimeReference ending(long dateTimeMillis);
-    method public long getEndDateTimeMillis();
-    method public long getStartDateTimeMillis();
-    method public boolean hasEndDateTimeMillis();
-    method public boolean hasStartDateTimeMillis();
-    method public static androidx.wear.complications.data.TimeReference starting(long dateTimeMillis);
-    property public final long endDateTimeMillis;
-    property public final long startDateTimeMillis;
-    field public static final androidx.wear.complications.data.TimeReference.Companion Companion;
-  }
-
-  public static final class TimeReference.Companion {
-    method public androidx.wear.complications.data.TimeReference between(long startDateTimeMillis, long endDateTimeMillis);
-    method public androidx.wear.complications.data.TimeReference ending(long dateTimeMillis);
-    method public androidx.wear.complications.data.TimeReference starting(long dateTimeMillis);
-  }
-
   public final class TypeKt {
   }
 
diff --git a/wear/wear-complications-data/api/restricted_current.txt b/wear/wear-complications-data/api/restricted_current.txt
index 77ff478..580e18d 100644
--- a/wear/wear-complications-data/api/restricted_current.txt
+++ b/wear/wear-complications-data/api/restricted_current.txt
@@ -289,6 +289,18 @@
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public int[] toWireTypes(java.util.Collection<? extends androidx.wear.complications.data.ComplicationType> types);
   }
 
+  public final class CountDownTimeReference {
+    ctor public CountDownTimeReference(long dateTimeMillis);
+    method public long getDateTimeMillis();
+    property public final long dateTimeMillis;
+  }
+
+  public final class CountUpTimeReference {
+    ctor public CountUpTimeReference(long dateTimeMillis);
+    method public long getDateTimeMillis();
+    property public final long dateTimeMillis;
+  }
+
   public final class DataKt {
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.wear.complications.data.ComplicationData asApiComplicationData(android.support.wearable.complications.ComplicationData);
   }
@@ -539,7 +551,8 @@
   }
 
   public static final class TimeDifferenceComplicationText.Builder {
-    ctor public TimeDifferenceComplicationText.Builder(androidx.wear.complications.data.TimeDifferenceStyle style, androidx.wear.complications.data.TimeReference reference);
+    ctor public TimeDifferenceComplicationText.Builder(androidx.wear.complications.data.TimeDifferenceStyle style, androidx.wear.complications.data.CountUpTimeReference countUpTimeReference);
+    ctor public TimeDifferenceComplicationText.Builder(androidx.wear.complications.data.TimeDifferenceStyle style, androidx.wear.complications.data.CountDownTimeReference countDownTimeReference);
     method public androidx.wear.complications.data.TimeDifferenceComplicationText build();
     method public androidx.wear.complications.data.TimeDifferenceComplicationText.Builder setDisplayAsNow(boolean displayAsNow);
     method public androidx.wear.complications.data.TimeDifferenceComplicationText.Builder setMinimumUnit(java.util.concurrent.TimeUnit? minimumUnit);
@@ -590,25 +603,6 @@
     method public androidx.wear.complications.data.TimeRange between(long startDateTimeMillis, long endDateTimeMillis);
   }
 
-  public final class TimeReference {
-    method public static androidx.wear.complications.data.TimeReference between(long startDateTimeMillis, long endDateTimeMillis);
-    method public static androidx.wear.complications.data.TimeReference ending(long dateTimeMillis);
-    method public long getEndDateTimeMillis();
-    method public long getStartDateTimeMillis();
-    method public boolean hasEndDateTimeMillis();
-    method public boolean hasStartDateTimeMillis();
-    method public static androidx.wear.complications.data.TimeReference starting(long dateTimeMillis);
-    property public final long endDateTimeMillis;
-    property public final long startDateTimeMillis;
-    field public static final androidx.wear.complications.data.TimeReference.Companion Companion;
-  }
-
-  public static final class TimeReference.Companion {
-    method public androidx.wear.complications.data.TimeReference between(long startDateTimeMillis, long endDateTimeMillis);
-    method public androidx.wear.complications.data.TimeReference ending(long dateTimeMillis);
-    method public androidx.wear.complications.data.TimeReference starting(long dateTimeMillis);
-  }
-
   public final class TypeKt {
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.wear.complications.data.ComplicationType![] asApiComplicationTypes(int[]);
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static int[] asWireTypes(java.util.Collection<? extends androidx.wear.complications.data.ComplicationType>);
diff --git a/wear/wear-complications-data/src/main/java/androidx/wear/complications/data/Data.kt b/wear/wear-complications-data/src/main/java/androidx/wear/complications/data/Data.kt
index 06b1f05..0d3548c 100644
--- a/wear/wear-complications-data/src/main/java/androidx/wear/complications/data/Data.kt
+++ b/wear/wear-complications-data/src/main/java/androidx/wear/complications/data/Data.kt
@@ -30,7 +30,8 @@
 /** Base type for all different types of [ComplicationData] types. */
 public sealed class ComplicationData constructor(
     public val type: ComplicationType,
-    public val tapAction: PendingIntent?
+    public val tapAction: PendingIntent?,
+    internal var cachedWireComplicationData: WireComplicationData?
 ) {
     /**
      * Converts this value to [WireComplicationData] object used for serialization.
@@ -49,6 +50,11 @@
      * This must be checked for any time for which the complication will be displayed.
      */
     public abstract fun isActiveAt(dateTimeMillis: Long): Boolean
+
+    internal fun createWireComplicationDataBuilder(): WireComplicationDataBuilder =
+        cachedWireComplicationData?.let {
+            WireComplicationDataBuilder(it)
+        } ?: WireComplicationDataBuilder(type.asWireComplicationType())
 }
 
 /** A pair of id and [ComplicationData]. */
@@ -71,7 +77,7 @@
  * has no data to be displayed. Watch faces may choose whether to render this in some way or
  * leave the slot empty.
  */
-public class NoDataComplicationData : ComplicationData(TYPE, null) {
+public class NoDataComplicationData : ComplicationData(TYPE, null, null) {
     override fun isActiveAt(dateTimeMillis: Long): Boolean = true
 
     /** @hide */
@@ -91,7 +97,7 @@
  * i.e. when the user has chosen "Empty" in the provider chooser. Providers cannot send data of
  * this type.
  */
-public class EmptyComplicationData : ComplicationData(TYPE, null) {
+public class EmptyComplicationData : ComplicationData(TYPE, null, null) {
     override fun isActiveAt(dateTimeMillis: Long): Boolean = true
 
     /** @hide */
@@ -112,7 +118,7 @@
  * complication, and the watch face has not set a default provider. Providers cannot send data
  * of this type.
  */
-public class NotConfiguredComplicationData : ComplicationData(TYPE, null) {
+public class NotConfiguredComplicationData : ComplicationData(TYPE, null, null) {
     override fun isActiveAt(dateTimeMillis: Long): Boolean = true
 
     /** @hide */
@@ -141,8 +147,9 @@
     public val monochromaticImage: MonochromaticImage?,
     public val contentDescription: ComplicationText?,
     tapAction: PendingIntent?,
-    public val validTimeRange: TimeRange?
-) : ComplicationData(TYPE, tapAction) {
+    public val validTimeRange: TimeRange?,
+    cachedWireComplicationData: WireComplicationData?
+) : ComplicationData(TYPE, tapAction, cachedWireComplicationData) {
 
     public override fun isActiveAt(dateTimeMillis: Long): Boolean =
         validTimeRange?.contains(dateTimeMillis) ?: true
@@ -158,6 +165,7 @@
         private var title: ComplicationText? = null
         private var monochromaticImage: MonochromaticImage? = null
         private var contentDescription: ComplicationText? = null
+        private var cachedWireComplicationData: WireComplicationData? = null
 
         /** Sets optional pending intent to be invoked when the complication is tapped. */
         public fun setTapAction(tapAction: PendingIntent?): Builder = apply {
@@ -184,6 +192,12 @@
             this.contentDescription = contentDescription
         }
 
+        internal fun setCachedWireComplicationData(
+            cachedWireComplicationData: WireComplicationData?
+        ): Builder = apply {
+            this.cachedWireComplicationData = cachedWireComplicationData
+        }
+
         /** Builds the [ShortTextComplicationData]. */
         public fun build(): ShortTextComplicationData =
             ShortTextComplicationData(
@@ -192,21 +206,22 @@
                 monochromaticImage,
                 contentDescription,
                 tapAction,
-                validTimeRange
+                validTimeRange,
+                cachedWireComplicationData
             )
     }
 
     /** @hide */
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     override fun asWireComplicationData(): WireComplicationData =
-        WireComplicationDataBuilder(TYPE.asWireComplicationType()).apply {
+        createWireComplicationDataBuilder().apply {
             setShortText(text.asWireComplicationText())
             setShortTitle(title?.asWireComplicationText())
             setContentDescription(contentDescription?.asWireComplicationText())
             monochromaticImage?.addToWireComplicationData(this)
             setTapAction(tapAction)
             setValidTimeRange(validTimeRange, this)
-        }.build()
+        }.build().also { cachedWireComplicationData = it }
 
     /** @hide */
     public companion object {
@@ -233,8 +248,9 @@
     public val smallImage: SmallImage?,
     public val contentDescription: ComplicationText?,
     tapAction: PendingIntent?,
-    public val validTimeRange: TimeRange?
-) : ComplicationData(TYPE, tapAction) {
+    public val validTimeRange: TimeRange?,
+    cachedWireComplicationData: WireComplicationData?
+) : ComplicationData(TYPE, tapAction, cachedWireComplicationData) {
 
     public override fun isActiveAt(dateTimeMillis: Long): Boolean =
         validTimeRange?.contains(dateTimeMillis) ?: true
@@ -251,6 +267,7 @@
         private var monochromaticImage: MonochromaticImage? = null
         private var smallImage: SmallImage? = null
         private var contentDescription: ComplicationText? = null
+        private var cachedWireComplicationData: WireComplicationData? = null
 
         /** Sets optional pending intent to be invoked when the complication is tapped. */
         public fun setTapAction(tapAction: PendingIntent?): Builder = apply {
@@ -282,6 +299,12 @@
             this.contentDescription = contentDescription
         }
 
+        internal fun setCachedWireComplicationData(
+            cachedWireComplicationData: WireComplicationData?
+        ): Builder = apply {
+            this.cachedWireComplicationData = cachedWireComplicationData
+        }
+
         /** Builds the [LongTextComplicationData]. */
         public fun build(): LongTextComplicationData =
             LongTextComplicationData(
@@ -291,14 +314,15 @@
                 smallImage,
                 contentDescription,
                 tapAction,
-                validTimeRange
+                validTimeRange,
+                cachedWireComplicationData
             )
     }
 
     /** @hide */
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     override fun asWireComplicationData(): WireComplicationData =
-        WireComplicationDataBuilder(TYPE.asWireComplicationType()).apply {
+        createWireComplicationDataBuilder().apply {
             setLongText(text.asWireComplicationText())
             setLongTitle(title?.asWireComplicationText())
             monochromaticImage?.addToWireComplicationData(this)
@@ -306,7 +330,7 @@
             setTapAction(tapAction)
             setContentDescription(contentDescription?.asWireComplicationText())
             setValidTimeRange(validTimeRange, this)
-        }.build()
+        }.build().also { cachedWireComplicationData = it }
 
     /** @hide */
     public companion object {
@@ -335,8 +359,9 @@
     public val text: ComplicationText?,
     public val contentDescription: ComplicationText?,
     tapAction: PendingIntent?,
-    public val validTimeRange: TimeRange?
-) : ComplicationData(TYPE, tapAction) {
+    public val validTimeRange: TimeRange?,
+    cachedWireComplicationData: WireComplicationData?
+) : ComplicationData(TYPE, tapAction, cachedWireComplicationData) {
 
     public override fun isActiveAt(dateTimeMillis: Long): Boolean =
         validTimeRange?.contains(dateTimeMillis) ?: true
@@ -357,6 +382,7 @@
         private var title: ComplicationText? = null
         private var text: ComplicationText? = null
         private var contentDescription: ComplicationText? = null
+        private var cachedWireComplicationData: WireComplicationData? = null
 
         /** Sets optional pending intent to be invoked when the complication is tapped. */
         public fun setTapAction(tapAction: PendingIntent?): Builder = apply {
@@ -388,6 +414,12 @@
             this.contentDescription = contentDescription
         }
 
+        internal fun setCachedWireComplicationData(
+            cachedWireComplicationData: WireComplicationData?
+        ): Builder = apply {
+            this.cachedWireComplicationData = cachedWireComplicationData
+        }
+
         /** Builds the [RangedValueComplicationData]. */
         public fun build(): RangedValueComplicationData =
             RangedValueComplicationData(
@@ -399,14 +431,15 @@
                 text,
                 contentDescription,
                 tapAction,
-                validTimeRange
+                validTimeRange,
+                cachedWireComplicationData
             )
     }
 
     /** @hide */
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     public override fun asWireComplicationData(): WireComplicationData =
-        WireComplicationDataBuilder(TYPE.asWireComplicationType()).apply {
+        createWireComplicationDataBuilder().apply {
             setRangedValue(value)
             setRangedMinValue(min)
             setRangedMaxValue(max)
@@ -416,7 +449,7 @@
             setTapAction(tapAction)
             setContentDescription(contentDescription?.asWireComplicationText())
             setValidTimeRange(validTimeRange, this)
-        }.build()
+        }.build().also { cachedWireComplicationData = it }
 
     /** @hide */
     public companion object {
@@ -440,8 +473,9 @@
     public val monochromaticImage: MonochromaticImage,
     public val contentDescription: ComplicationText?,
     tapAction: PendingIntent?,
-    public val validTimeRange: TimeRange?
-) : ComplicationData(TYPE, tapAction) {
+    public val validTimeRange: TimeRange?,
+    cachedWireComplicationData: WireComplicationData?
+) : ComplicationData(TYPE, tapAction, cachedWireComplicationData) {
 
     public override fun isActiveAt(dateTimeMillis: Long): Boolean =
         validTimeRange?.contains(dateTimeMillis) ?: true
@@ -455,6 +489,7 @@
         private var tapAction: PendingIntent? = null
         private var validTimeRange: TimeRange? = null
         private var contentDescription: ComplicationText? = null
+        private var cachedWireComplicationData: WireComplicationData? = null
 
         /** Sets optional pending intent to be invoked when the complication is tapped. */
         public fun setTapAction(tapAction: PendingIntent?): Builder = apply {
@@ -471,24 +506,31 @@
             this.contentDescription = contentDescription
         }
 
+        internal fun setCachedWireComplicationData(
+            cachedWireComplicationData: WireComplicationData?
+        ): Builder = apply {
+            this.cachedWireComplicationData = cachedWireComplicationData
+        }
+
         /** Builds the [MonochromaticImageComplicationData]. */
         public fun build(): MonochromaticImageComplicationData =
             MonochromaticImageComplicationData(
                 monochromaticImage,
                 contentDescription,
                 tapAction,
-                validTimeRange
+                validTimeRange,
+                cachedWireComplicationData
             )
     }
 
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     override fun asWireComplicationData(): WireComplicationData =
-        WireComplicationDataBuilder(TYPE.asWireComplicationType()).apply {
+        createWireComplicationDataBuilder().apply {
             monochromaticImage.addToWireComplicationData(this)
             setContentDescription(contentDescription?.asWireComplicationText())
             setTapAction(tapAction)
             setValidTimeRange(validTimeRange, this)
-        }.build()
+        }.build().also { cachedWireComplicationData = it }
 
     /** @hide */
     public companion object {
@@ -512,8 +554,9 @@
     public val smallImage: SmallImage,
     public val contentDescription: ComplicationText?,
     tapAction: PendingIntent?,
-    public val validTimeRange: TimeRange?
-) : ComplicationData(TYPE, tapAction) {
+    public val validTimeRange: TimeRange?,
+    cachedWireComplicationData: WireComplicationData?
+) : ComplicationData(TYPE, tapAction, cachedWireComplicationData) {
 
     public override fun isActiveAt(dateTimeMillis: Long): Boolean =
         validTimeRange?.contains(dateTimeMillis) ?: true
@@ -527,6 +570,7 @@
         private var tapAction: PendingIntent? = null
         private var validTimeRange: TimeRange? = null
         private var contentDescription: ComplicationText? = null
+        private var cachedWireComplicationData: WireComplicationData? = null
 
         /** Sets optional pending intent to be invoked when the complication is tapped. */
         public fun setTapAction(tapAction: PendingIntent?): Builder = apply {
@@ -543,19 +587,31 @@
             this.contentDescription = contentDescription
         }
 
+        internal fun setCachedWireComplicationData(
+            cachedWireComplicationData: WireComplicationData?
+        ): Builder = apply {
+            this.cachedWireComplicationData = cachedWireComplicationData
+        }
+
         /** Builds the [MonochromaticImageComplicationData]. */
         public fun build(): SmallImageComplicationData =
-            SmallImageComplicationData(smallImage, contentDescription, tapAction, validTimeRange)
+            SmallImageComplicationData(
+                smallImage,
+                contentDescription,
+                tapAction,
+                validTimeRange,
+                cachedWireComplicationData
+            )
     }
 
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     override fun asWireComplicationData(): WireComplicationData =
-        WireComplicationDataBuilder(TYPE.asWireComplicationType()).apply {
+        createWireComplicationDataBuilder().apply {
             smallImage.addToWireComplicationData(this)
             setContentDescription(contentDescription?.asWireComplicationText())
             setTapAction(tapAction)
             setValidTimeRange(validTimeRange, this)
-        }.build()
+        }.build().also { cachedWireComplicationData = it }
 
     /** @hide */
     public companion object {
@@ -583,8 +639,9 @@
     public val photoImage: Icon,
     public val contentDescription: ComplicationText?,
     tapAction: PendingIntent?,
-    public val validTimeRange: TimeRange?
-) : ComplicationData(TYPE, tapAction) {
+    public val validTimeRange: TimeRange?,
+    cachedWireComplicationData: WireComplicationData?
+) : ComplicationData(TYPE, tapAction, cachedWireComplicationData) {
 
     public override fun isActiveAt(dateTimeMillis: Long): Boolean =
         validTimeRange?.contains(dateTimeMillis) ?: true
@@ -598,6 +655,7 @@
         private var tapAction: PendingIntent? = null
         private var validTimeRange: TimeRange? = null
         private var contentDescription: ComplicationText? = null
+        private var cachedWireComplicationData: WireComplicationData? = null
 
         /** Sets optional pending intent to be invoked when the complication is tapped. */
         @SuppressWarnings("MissingGetterMatchingBuilder") // See http://b/174052810
@@ -616,18 +674,30 @@
             this.contentDescription = contentDescription
         }
 
+        internal fun setCachedWireComplicationData(
+            cachedWireComplicationData: WireComplicationData?
+        ): Builder = apply {
+            this.cachedWireComplicationData = cachedWireComplicationData
+        }
+
         /** Builds the [PhotoImageComplicationData]. */
         public fun build(): PhotoImageComplicationData =
-            PhotoImageComplicationData(photoImage, contentDescription, tapAction, validTimeRange)
+            PhotoImageComplicationData(
+                photoImage,
+                contentDescription,
+                tapAction,
+                validTimeRange,
+                cachedWireComplicationData
+            )
     }
 
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     override fun asWireComplicationData(): WireComplicationData =
-        WireComplicationDataBuilder(TYPE.asWireComplicationType()).apply {
+        createWireComplicationDataBuilder().apply {
             setLargeImage(photoImage)
             setContentDescription(contentDescription?.asWireComplicationText())
             setValidTimeRange(validTimeRange, this)
-        }.build()
+        }.build().also { cachedWireComplicationData = it }
 
     /** @hide */
     public companion object {
@@ -651,7 +721,8 @@
     public val text: ComplicationText?,
     public val title: ComplicationText?,
     public val monochromaticImage: MonochromaticImage?,
-) : ComplicationData(TYPE, null) {
+    cachedWireComplicationData: WireComplicationData?
+) : ComplicationData(TYPE, null, cachedWireComplicationData) {
 
     override fun isActiveAt(dateTimeMillis: Long): Boolean = true
 
@@ -664,6 +735,7 @@
         private var text: ComplicationText? = null
         private var title: ComplicationText? = null
         private var monochromaticImage: MonochromaticImage? = null
+        private var cachedWireComplicationData: WireComplicationData? = null
 
         /** Sets optional text associated with the complication data. */
         public fun setText(text: ComplicationText?): Builder = apply {
@@ -680,19 +752,30 @@
             this.monochromaticImage = monochromaticImage
         }
 
+        internal fun setCachedWireComplicationData(
+            cachedWireComplicationData: WireComplicationData?
+        ): Builder = apply {
+            this.cachedWireComplicationData = cachedWireComplicationData
+        }
+
         /** Builds the [NoPermissionComplicationData]. */
         public fun build(): NoPermissionComplicationData =
-            NoPermissionComplicationData(text, title, monochromaticImage)
+            NoPermissionComplicationData(
+                text,
+                title,
+                monochromaticImage,
+                cachedWireComplicationData
+            )
     }
 
     /** @hide */
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     override fun asWireComplicationData(): WireComplicationData =
-        WireComplicationDataBuilder(TYPE.asWireComplicationType()).apply {
+        createWireComplicationDataBuilder().apply {
             setShortText(text?.asWireComplicationText())
             setShortTitle(title?.asWireComplicationText())
             monochromaticImage?.addToWireComplicationData(this)
-        }.build()
+        }.build().also { cachedWireComplicationData = it }
 
     /** @hide */
     public companion object {
@@ -703,8 +786,9 @@
 }
 
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public fun WireComplicationData.asApiComplicationData(): ComplicationData =
-    when (type) {
+public fun WireComplicationData.asApiComplicationData(): ComplicationData {
+    val wireComplicationData = this
+    return when (type) {
         NoDataComplicationData.TYPE.asWireComplicationType() -> NoDataComplicationData()
 
         EmptyComplicationData.TYPE.asWireComplicationType() -> EmptyComplicationData()
@@ -719,6 +803,7 @@
                 setTitle(shortTitle?.asApiComplicationText())
                 setMonochromaticImage(parseIcon())
                 setContentDescription(contentDescription?.asApiComplicationText())
+                setCachedWireComplicationData(wireComplicationData)
             }.build()
 
         LongTextComplicationData.TYPE.asWireComplicationType() ->
@@ -729,6 +814,7 @@
                 setMonochromaticImage(parseIcon())
                 setSmallImage(parseSmallImage())
                 setContentDescription(contentDescription?.asApiComplicationText())
+                setCachedWireComplicationData(wireComplicationData)
             }.build()
 
         RangedValueComplicationData.TYPE.asWireComplicationType() ->
@@ -742,6 +828,7 @@
                 setTitle(shortTitle?.asApiComplicationText())
                 setText(shortText?.asApiComplicationText())
                 setContentDescription(contentDescription?.asApiComplicationText())
+                setCachedWireComplicationData(wireComplicationData)
             }.build()
 
         MonochromaticImageComplicationData.TYPE.asWireComplicationType() ->
@@ -749,6 +836,7 @@
                 setTapAction(tapAction)
                 setValidTimeRange(parseTimeRange())
                 setContentDescription(contentDescription?.asApiComplicationText())
+                setCachedWireComplicationData(wireComplicationData)
             }.build()
 
         SmallImageComplicationData.TYPE.asWireComplicationType() ->
@@ -756,12 +844,14 @@
                 setTapAction(tapAction)
                 setValidTimeRange(parseTimeRange())
                 setContentDescription(contentDescription?.asApiComplicationText())
+                setCachedWireComplicationData(wireComplicationData)
             }.build()
 
         PhotoImageComplicationData.TYPE.asWireComplicationType() ->
             PhotoImageComplicationData.Builder(largeImage!!).apply {
                 setValidTimeRange(parseTimeRange())
                 setContentDescription(contentDescription?.asApiComplicationText())
+                setCachedWireComplicationData(wireComplicationData)
             }.build()
 
         NoPermissionComplicationData.TYPE.asWireComplicationType() ->
@@ -769,10 +859,12 @@
                 setMonochromaticImage(parseIcon())
                 setTitle(shortTitle?.asApiComplicationText())
                 setText(shortText?.asApiComplicationText())
+                setCachedWireComplicationData(wireComplicationData)
             }.build()
 
         else -> NoDataComplicationData()
     }
+}
 
 private fun WireComplicationData.parseTimeRange() =
     if ((startDateTimeMillis == 0L) and (endDateTimeMillis == Long.MAX_VALUE)) {
@@ -813,4 +905,4 @@
             data.setEndDateTimeMillis(it.endDateTimeMillis)
         }
     }
-}
\ No newline at end of file
+}
diff --git a/wear/wear-complications-data/src/main/java/androidx/wear/complications/data/Text.kt b/wear/wear-complications-data/src/main/java/androidx/wear/complications/data/Text.kt
index ea85f74..2d5b55c 100644
--- a/wear/wear-complications-data/src/main/java/androidx/wear/complications/data/Text.kt
+++ b/wear/wear-complications-data/src/main/java/androidx/wear/complications/data/Text.kt
@@ -191,14 +191,25 @@
      *
      * Requires setting a [TimeDifferenceStyle].
      */
-    public class Builder(
+    public class Builder private constructor(
         private val style: TimeDifferenceStyle,
-        private val reference: TimeReference
+        private val startDateTimeMillis: Long?,
+        private val endDateTimeMillis: Long?
     ) {
         private var text: CharSequence? = null
         private var displayAsNow: Boolean? = null
         private var minimumUnit: TimeUnit? = null
 
+        public constructor(
+            style: TimeDifferenceStyle,
+            countUpTimeReference: CountUpTimeReference
+        ) : this(style, countUpTimeReference.dateTimeMillis, null)
+
+        public constructor(
+            style: TimeDifferenceStyle,
+            countDownTimeReference: CountDownTimeReference
+        ) : this(style, null, countDownTimeReference.dateTimeMillis)
+
         /**
          * Sets the text within which the time difference will be displayed.
          *
@@ -247,11 +258,11 @@
             WireComplicationTextTimeDifferenceBuilder().apply {
                 setStyle(style.wireStyle)
                 setSurroundingText(text)
-                if (reference.hasStartDateTimeMillis()) {
-                    setReferencePeriodStartMillis(reference.startDateTimeMillis)
+                startDateTimeMillis?.let {
+                    setReferencePeriodStartMillis(it)
                 }
-                if (reference.hasEndDateTimeMillis()) {
-                    setReferencePeriodEndMillis(reference.endDateTimeMillis)
+                endDateTimeMillis?.let {
+                    setReferencePeriodEndMillis(it)
                 }
                 displayAsNow?.let { setShowNowText(it) }
                 setMinimumUnit(minimumUnit)
diff --git a/wear/wear-complications-data/src/main/java/androidx/wear/complications/data/Time.kt b/wear/wear-complications-data/src/main/java/androidx/wear/complications/data/Time.kt
index f4f99e7..1205662 100644
--- a/wear/wear-complications-data/src/main/java/androidx/wear/complications/data/Time.kt
+++ b/wear/wear-complications-data/src/main/java/androidx/wear/complications/data/Time.kt
@@ -48,40 +48,8 @@
     }
 }
 
-/**
- * Expresses a reference point or range for a time difference.
- *
- * It defines [endDateTimeMillis] and/or [startDateTimeMillis] to express the corresponding
- * time differences relative to before, between or after the given point(s) in time.
- */
-public class TimeReference internal constructor(
-    public val endDateTimeMillis: Long,
-    public val startDateTimeMillis: Long
-) {
-    public fun hasStartDateTimeMillis(): Boolean = startDateTimeMillis != NONE
-    public fun hasEndDateTimeMillis(): Boolean = endDateTimeMillis != NONE
+/** Defines a point in time the complication is counting down until. */
+public class CountDownTimeReference(public val dateTimeMillis: Long)
 
-    public companion object {
-        private const val NONE = -1L
-
-        /**
-         * Creates a [TimeReference] for the time difference ending at the given [dateTimeMillis].
-         */
-        @JvmStatic
-        public fun ending(dateTimeMillis: Long): TimeReference = TimeReference(dateTimeMillis, NONE)
-
-        /**
-         * Creates a [TimeReference] for the time difference starting at the given [dateTimeMillis].
-         */
-        @JvmStatic
-        public fun starting(dateTimeMillis: Long): TimeReference =
-            TimeReference(NONE, dateTimeMillis)
-
-        /**
-         * Creates a [TimeReference] for the time difference between [startDateTimeMillis] and [endDateTimeMillis].
-         */
-        @JvmStatic
-        public fun between(startDateTimeMillis: Long, endDateTimeMillis: Long): TimeReference =
-            TimeReference(endDateTimeMillis, startDateTimeMillis)
-    }
-}
+/** Defines a point in time the complication is counting up from. */
+public class CountUpTimeReference(public val dateTimeMillis: Long)
diff --git a/wear/wear-complications-data/src/test/java/androidx/wear/complications/data/DataTest.kt b/wear/wear-complications-data/src/test/java/androidx/wear/complications/data/DataTest.kt
index 42c5ec4..9d93102 100644
--- a/wear/wear-complications-data/src/test/java/androidx/wear/complications/data/DataTest.kt
+++ b/wear/wear-complications-data/src/test/java/androidx/wear/complications/data/DataTest.kt
@@ -35,6 +35,7 @@
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_NO_DATA).build()
             )
+        testRoundTripConversions(data)
     }
 
     @Test
@@ -44,6 +45,7 @@
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_EMPTY).build()
             )
+        testRoundTripConversions(data)
     }
 
     @Test
@@ -53,6 +55,7 @@
             .hasSameSerializationAs(
                 WireComplicationDataBuilder(WireComplicationData.TYPE_NOT_CONFIGURED).build()
             )
+        testRoundTripConversions(data)
     }
 
     @Test
@@ -69,6 +72,7 @@
                     .setContentDescription(WireComplicationText.plainText("content description"))
                     .build()
             )
+        testRoundTripConversions(data)
     }
 
     @Test
@@ -85,6 +89,7 @@
                     .setContentDescription(WireComplicationText.plainText("content description"))
                     .build()
             )
+        testRoundTripConversions(data)
     }
 
     @Test
@@ -103,6 +108,7 @@
                     .setContentDescription(WireComplicationText.plainText("content description"))
                     .build()
             )
+        testRoundTripConversions(data)
     }
 
     @Test
@@ -118,6 +124,7 @@
                     .setContentDescription(WireComplicationText.plainText("content description"))
                     .build()
             )
+        testRoundTripConversions(data)
     }
 
     @Test
@@ -134,6 +141,7 @@
                     .setContentDescription(WireComplicationText.plainText("content description"))
                     .build()
             )
+        testRoundTripConversions(data)
     }
 
     @Test
@@ -149,6 +157,7 @@
                     .setContentDescription(WireComplicationText.plainText("content description"))
                     .build()
             )
+        testRoundTripConversions(data)
     }
 
     @Test
@@ -162,6 +171,14 @@
                     .setShortText(WireComplicationText.plainText("needs location"))
                     .build()
             )
+        testRoundTripConversions(data)
+    }
+
+    private fun testRoundTripConversions(data: ComplicationData) {
+        ParcelableSubject.assertThat(data.asWireComplicationData())
+            .hasSameSerializationAs(
+                data.asWireComplicationData().asApiComplicationData().asWireComplicationData()
+            )
     }
 }
 
diff --git a/wear/wear-complications-data/src/test/java/androidx/wear/complications/data/TextTest.kt b/wear/wear-complications-data/src/test/java/androidx/wear/complications/data/TextTest.kt
index 6798909..127676d 100644
--- a/wear/wear-complications-data/src/test/java/androidx/wear/complications/data/TextTest.kt
+++ b/wear/wear-complications-data/src/test/java/androidx/wear/complications/data/TextTest.kt
@@ -45,10 +45,40 @@
     }
 
     @Test
-    public fun timeDifferenceText() {
+    public fun timeDifferenceText_CountUpTimeReference() {
+        val referenceMillis = Instant.parse("2020-12-30T10:15:30.001Z").toEpochMilli()
         val text = TimeDifferenceComplicationText.Builder(
             TimeDifferenceStyle.STOPWATCH,
-            TimeReference.starting(10000L)
+            CountDownTimeReference(referenceMillis)
+        )
+            .setText("^1 after lunch")
+            .setDisplayAsNow(false)
+            .setMinimumUnit(TimeUnit.SECONDS)
+            .build()
+
+        ParcelableSubject.assertThat(text.asWireComplicationText())
+            .hasSameSerializationAs(
+                WireTimeDifferenceBuilder()
+                    .setStyle(WireComplicationText.DIFFERENCE_STYLE_STOPWATCH)
+                    .setSurroundingText("^1 after lunch")
+                    .setShowNowText(false)
+                    .setMinimumUnit(TimeUnit.SECONDS)
+                    .setReferencePeriodEndMillis(referenceMillis)
+                    .build()
+            )
+
+        val twoMinutesThreeSecondAfter = referenceMillis + 2.minutes + 3.seconds
+        assertThat(
+            text.getTextAt(getResource(), twoMinutesThreeSecondAfter).toString()
+        ).isEqualTo("02:03 after lunch")
+    }
+
+    @Test
+    public fun timeDifferenceText_CountDownTimeReference() {
+        val referenceMillis = Instant.parse("2020-12-30T10:15:30.001Z").toEpochMilli()
+        val text = TimeDifferenceComplicationText.Builder(
+            TimeDifferenceStyle.STOPWATCH,
+            CountUpTimeReference(referenceMillis)
         )
             .setText("^1 before lunch")
             .setDisplayAsNow(false)
@@ -62,9 +92,14 @@
                     .setSurroundingText("^1 before lunch")
                     .setShowNowText(false)
                     .setMinimumUnit(TimeUnit.SECONDS)
-                    .setReferencePeriodStartMillis(10000L)
+                    .setReferencePeriodStartMillis(referenceMillis)
                     .build()
             )
+
+        val twoMinutesThreeSecondBefore = referenceMillis - 2.minutes - 3.seconds
+        assertThat(
+            text.getTextAt(getResource(), twoMinutesThreeSecondBefore).toString()
+        ).isEqualTo("02:03 before lunch")
     }
 
     @Test
@@ -85,6 +120,8 @@
                     .build()
             )
     }
+
+    private fun getResource() = ApplicationProvider.getApplicationContext<Context>().resources
 }
 
 @RunWith(SharedRobolectricTestRunner::class)
diff --git a/wear/wear-complications-data/src/test/java/androidx/wear/complications/data/TimeTest.kt b/wear/wear-complications-data/src/test/java/androidx/wear/complications/data/TimeRangeTest.kt
similarity index 79%
rename from wear/wear-complications-data/src/test/java/androidx/wear/complications/data/TimeTest.kt
rename to wear/wear-complications-data/src/test/java/androidx/wear/complications/data/TimeRangeTest.kt
index a81ba14..4c002ef 100644
--- a/wear/wear-complications-data/src/test/java/androidx/wear/complications/data/TimeTest.kt
+++ b/wear/wear-complications-data/src/test/java/androidx/wear/complications/data/TimeRangeTest.kt
@@ -70,23 +70,4 @@
         assertThat(range.contains(10000)).isTrue()
         assertThat(range.contains(Long.MAX_VALUE)).isTrue()
     }
-}
-
-@RunWith(SharedRobolectricTestRunner::class)
-public class TimeReferenceTest {
-    @Test
-    public fun startingAtTime() {
-        val reference = TimeReference.starting(1000L)
-        assertThat(reference.hasStartDateTimeMillis()).isTrue()
-        assertThat(reference.startDateTimeMillis).isEqualTo(1000L)
-        assertThat(reference.hasEndDateTimeMillis()).isFalse()
-    }
-
-    @Test
-    public fun endingAtTime() {
-        val reference = TimeReference.ending(1000L)
-        assertThat(reference.hasStartDateTimeMillis()).isFalse()
-        assertThat(reference.hasEndDateTimeMillis()).isTrue()
-        assertThat(reference.endDateTimeMillis).isEqualTo(1000L)
-    }
-}
+}
\ No newline at end of file
diff --git a/wear/wear-tiles-renderer/build.gradle b/wear/wear-tiles-renderer/build.gradle
index 70bdc56..b405d45 100644
--- a/wear/wear-tiles-renderer/build.gradle
+++ b/wear/wear-tiles-renderer/build.gradle
@@ -26,6 +26,7 @@
     id("AndroidXPlugin")
     id("com.android.library")
     id("kotlin-android")
+    id("com.google.protobuf")
 }
 
 dependencies {
@@ -39,6 +40,14 @@
     implementation(KOTLIN_COROUTINES_CORE)
     implementation(KOTLIN_COROUTINES_ANDROID)
 
+    androidTestImplementation(project(path: ":wear:wear-tiles-proto", configuration: "shadow"))
+    androidTestImplementation(project(":test-screenshot"))
+    androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
+    androidTestImplementation(ANDROIDX_TEST_CORE)
+    androidTestImplementation(ANDROIDX_TEST_RUNNER)
+    androidTestImplementation(ANDROIDX_TEST_RULES)
+    androidTestImplementation("com.google.protobuf:protobuf-java:3.10.0")
+
     testImplementation(ANDROIDX_TEST_EXT_JUNIT)
     testImplementation(ANDROIDX_TEST_EXT_TRUTH)
     testImplementation(ANDROIDX_TEST_CORE)
@@ -52,11 +61,15 @@
 
 android {
     defaultConfig {
-        minSdkVersion 25
+        minSdkVersion 26
     }
 
     // Use Robolectric 4.+
     testOptions.unitTests.includeAndroidResources = true
+
+    sourceSets {
+        androidTest.assets.srcDirs += project.rootDir.absolutePath + "/../../golden/wear/wear-tiles-renderer"
+    }
 }
 
 // Allow usage of Kotlin's @OptIn.
@@ -66,6 +79,23 @@
     }
 }
 
+protobuf {
+    protoc {
+        artifact = "com.google.protobuf:protoc:3.10.0"
+    }
+
+    // Generates the java proto-lite code for the protos in this project. See
+    // https://github.com/google/protobuf-gradle-plugin#customizing-protobuf-compilation
+    // for more information.
+    generateProtoTasks {
+        all().each { task ->
+            task.builtins {
+                java {}
+            }
+        }
+    }
+}
+
 androidx {
     name = "Android Wear Tiles Renderer"
     type = LibraryType.PUBLISHED_LIBRARY
diff --git a/car/app/app-testing/src/androidTest/AndroidManifest.xml b/wear/wear-tiles-renderer/src/androidTest/AndroidManifest.xml
similarity index 84%
rename from car/app/app-testing/src/androidTest/AndroidManifest.xml
rename to wear/wear-tiles-renderer/src/androidTest/AndroidManifest.xml
index c409a24..6c1bac5 100644
--- a/car/app/app-testing/src/androidTest/AndroidManifest.xml
+++ b/wear/wear-tiles-renderer/src/androidTest/AndroidManifest.xml
@@ -14,6 +14,7 @@
   See the License for the specific language governing permissions and
   limitations under the License.
   -->
-<manifest package="androidx.car.app.testing.test">
 
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="androidx.wear.tiles.renderer.test">
 </manifest>
diff --git a/wear/wear-tiles-renderer/src/androidTest/java/androidx/wear/tiles/renderer/test/TileRendererGoldenTest.java b/wear/wear-tiles-renderer/src/androidTest/java/androidx/wear/tiles/renderer/test/TileRendererGoldenTest.java
new file mode 100644
index 0000000..ad0b0b7
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/java/androidx/wear/tiles/renderer/test/TileRendererGoldenTest.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2021 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.wear.tiles.renderer.test;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.view.Gravity;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.widget.FrameLayout;
+
+import androidx.core.content.ContextCompat;
+import androidx.test.filters.LargeTest;
+import androidx.test.screenshot.AndroidXScreenshotTestRule;
+import androidx.test.screenshot.matchers.MSSIMMatcher;
+import androidx.wear.tiles.builders.LayoutElementBuilders;
+import androidx.wear.tiles.builders.ResourceBuilders;
+import androidx.wear.tiles.proto.LayoutElementProto.Layout;
+import androidx.wear.tiles.proto.LayoutElementProto.LayoutElement;
+import androidx.wear.tiles.proto.ResourceProto.AndroidImageResourceByResId;
+import androidx.wear.tiles.proto.ResourceProto.ImageFormat;
+import androidx.wear.tiles.proto.ResourceProto.ImageResource;
+import androidx.wear.tiles.proto.ResourceProto.InlineImageResource;
+import androidx.wear.tiles.proto.ResourceProto.Resources;
+import androidx.wear.tiles.protobuf.ByteString;
+import androidx.wear.tiles.renderer.StandardResourceAccessors;
+import androidx.wear.tiles.renderer.TileRenderer;
+
+import com.google.protobuf.TextFormat;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class TileRendererGoldenTest {
+    @Parameterized.Parameters(name = "{0}")
+    public static Collection<Object[]> data() {
+        return Arrays.asList(
+                new Object[][] {
+                    {"all_modifiers"},
+                    {"arc_above_360"},
+                    {"arc_alignment_mixed_types"},
+                    {"arc_alignment"},
+                    {"arc_anchors"},
+                    {"arc_text_and_lines"},
+                    {"arc_with_buttons_rotated"},
+                    {"arc_with_buttons_unrotated"},
+                    {"box_with_corners_and_border_rtlaware"},
+                    {"box_with_corners_and_border"},
+                    {"box_with_fixed_size"},
+                    {"broken_drawable"},
+                    {"column_with_alignment_rtlaware"},
+                    {"column_with_alignment"},
+                    {"column_with_height"},
+                    {"expanded_box_horizontal_right_align"},
+                    {"expanded_box_horizontal"},
+                    {"expanded_box_vertical"},
+                    {"expanded_children_in_row"},
+                    {"font_weights_in_arc"},
+                    {"font_weights_in_spannable"},
+                    {"image_expanded_to_parent"},
+                    {"image_expand_modes"},
+                    {"image_oversized_in_box_proportional"},
+                    {"image_oversized_in_box"},
+                    {"image_proportional_resize"},
+                    {"image_with_dimensions"},
+                    {"image_with_inline_data"},
+                    {"image_with_padding"},
+                    {"line_in_arc"},
+                    {"line_multi_height"},
+                    {"long_text"},
+                    {"multi_line_text_alignment"},
+                    {"row_column_space_test"},
+                    {"row_with_alignment"},
+                    {"row_with_width"},
+                    {"simple_text"},
+                    {"single_line_text_alignment"},
+                    {"spacer_horizontal"},
+                    {"spacer_in_arc"},
+                    {"spacer_vertical"},
+                    {"spannable_image"},
+                    {"spannable_image_with_clickable"},
+                    {"spannable_image_wrapped"},
+                    {"spannable_text"},
+                    {"text_and_image_in_box"},
+                    {"text_default_size"},
+                    {"text_in_column"},
+                    {"text_in_row"},
+                    {"text_with_font_weights_italic"},
+                    {"text_with_font_weights"},
+                    {"text_with_spacing"},
+                });
+    }
+
+    @Rule
+    public AndroidXScreenshotTestRule screenshotRule =
+            new AndroidXScreenshotTestRule("wear/wear-tiles-renderer");
+
+    // This isn't totally ideal right now.
+    // The screenshot tests run on a phone, so emulate some watch dimensions here.
+    private static final int SCREEN_WIDTH = 390;
+    private static final int SCREEN_HEIGHT = 390;
+
+    private static final int INLINE_IMAGE_WIDTH = 8;
+    private static final int INLINE_IMAGE_HEIGHT = 8;
+    private static final int INLINE_IMAGE_PIXEL_STRIDE = 2; // RGB565 = 2 bytes per pixel
+
+    private final String mProtoFile;
+
+    public TileRendererGoldenTest(String protoFile) {
+        mProtoFile = protoFile;
+    }
+
+    @Test
+    public void renderer_goldenTest() throws Exception {
+        int id =
+                getApplicationContext()
+                        .getResources()
+                        .getIdentifier(mProtoFile, "raw", getApplicationContext().getPackageName());
+
+        runSingleScreenshotTest(id, mProtoFile);
+    }
+
+    private static Resources generateResources() {
+        byte[] inlineImagePayload =
+                new byte[INLINE_IMAGE_WIDTH * INLINE_IMAGE_HEIGHT * INLINE_IMAGE_PIXEL_STRIDE];
+
+        // Generate a square image, with a white square in the center.
+        // This replaces an inline payload as a byte array. We could hardcode it, but the
+        // autoformatter will ruin the formatting.
+        for (int y = 0; y < 8; y++) {
+            for (int x = 0; x < 8; x++) {
+                int index = ((y * INLINE_IMAGE_WIDTH) + x) * INLINE_IMAGE_PIXEL_STRIDE;
+                short color = 0x0000;
+
+                if (y > 2 && y < 6 && x > 2 && x < 6) {
+                    color = (short) 0xFFFF;
+                }
+
+                inlineImagePayload[index + 0] = (byte) ((color >> 0) & 0xFF);
+                inlineImagePayload[index + 1] = (byte) ((color >> 8) & 0xFF);
+            }
+        }
+
+        return Resources.newBuilder()
+                .putIdToImage(
+                        "android",
+                        ImageResource.newBuilder()
+                                .setAndroidResourceByResid(
+                                        AndroidImageResourceByResId.newBuilder()
+                                                .setResourceId(R.drawable.android_24dp))
+                                .build())
+                .putIdToImage(
+                        "android_withbg_120dp",
+                        ImageResource.newBuilder()
+                                .setAndroidResourceByResid(
+                                        AndroidImageResourceByResId.newBuilder()
+                                                .setResourceId(R.mipmap.android_withbg_120dp))
+                                .build())
+                .putIdToImage(
+                        "inline",
+                        ImageResource.newBuilder()
+                                .setInlineResource(
+                                        InlineImageResource.newBuilder()
+                                                .setFormat(ImageFormat.IMAGE_FORMAT_RGB_565)
+                                                .setWidthPx(INLINE_IMAGE_WIDTH)
+                                                .setHeightPx(INLINE_IMAGE_HEIGHT)
+                                                .setData(ByteString.copyFrom(inlineImagePayload)))
+                                .build())
+                .putIdToImage(
+                        "broken_image",
+                        ImageResource.newBuilder()
+                                .setAndroidResourceByResid(
+                                        AndroidImageResourceByResId.newBuilder()
+                                                .setResourceId(R.drawable.broken_drawable))
+                                .build())
+                .putIdToImage(
+                        "missing_image",
+                        ImageResource.newBuilder()
+                                .setAndroidResourceByResid(
+                                        AndroidImageResourceByResId.newBuilder().setResourceId(-1))
+                                .build())
+                .build();
+    }
+
+    private void runSingleScreenshotTest(int protoResId, String expectedKey) throws Exception {
+        FrameLayout mainFrame = new FrameLayout(getApplicationContext());
+        mainFrame.setTextAlignment(View.TEXT_ALIGNMENT_TEXT_START);
+
+        Context appContext = getApplicationContext();
+
+        // This is a hack, but use the full proto lib to translate the textproto into a serialized
+        // proto, then pass into a Layout.
+        TextFormat.Parser parser = TextFormat.getParser();
+        androidx.wear.tiles.testing.proto.LayoutElementProto.LayoutElement.Builder
+                layoutElementProto =
+                        androidx.wear.tiles.testing.proto.LayoutElementProto.LayoutElement
+                                .newBuilder();
+
+        InputStream rawResStream =
+                getApplicationContext().getResources().openRawResource(protoResId);
+        try (InputStreamReader reader = new InputStreamReader(rawResStream)) {
+            parser.merge(reader, layoutElementProto);
+        }
+
+        byte[] contents = layoutElementProto.build().toByteArray();
+
+        // Inflate and go!
+        LayoutElement rootElement = LayoutElement.parseFrom(contents);
+
+        TileRenderer renderer =
+                new TileRenderer(
+                        appContext,
+                        LayoutElementBuilders.Layout.fromProto(
+                                Layout.newBuilder().setRoot(rootElement).build()),
+                        StandardResourceAccessors.forLocalApp(
+                                        appContext,
+                                        ResourceBuilders.Resources.fromProto(generateResources()))
+                                .build(),
+                        ContextCompat.getMainExecutor(getApplicationContext()),
+                        i -> {});
+
+        View firstChild = renderer.inflate(mainFrame);
+
+        if (firstChild == null) {
+            throw new RuntimeException("Failed to inflate " + expectedKey);
+        }
+
+        // Simulate what the thing outside the renderer should do. Fix the frame at the "screen"
+        // size, and center the contents.
+        FrameLayout.LayoutParams layoutParams =
+                (FrameLayout.LayoutParams) firstChild.getLayoutParams();
+        layoutParams.gravity = Gravity.CENTER;
+
+        int screenWidth = MeasureSpec.makeMeasureSpec(SCREEN_WIDTH, MeasureSpec.EXACTLY);
+        int screenHeight = MeasureSpec.makeMeasureSpec(SCREEN_HEIGHT, MeasureSpec.EXACTLY);
+
+        mainFrame.measure(screenWidth, screenHeight);
+        mainFrame.layout(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+
+        // Blit it to a bitmap for further testing.
+        Bitmap bmp = Bitmap.createBitmap(SCREEN_WIDTH, SCREEN_HEIGHT, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bmp);
+        mainFrame.draw(canvas);
+
+        screenshotRule.assertBitmapAgainstGolden(bmp, expectedKey, new MSSIMMatcher());
+    }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/proto/action.proto b/wear/wear-tiles-renderer/src/androidTest/proto/action.proto
new file mode 100644
index 0000000..eda1f13
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/proto/action.proto
@@ -0,0 +1,42 @@
+// Actions that can be performed when a user interacts with layout elements.
+syntax = "proto3";
+
+package androidx.wear.tiles.testing.proto;
+
+import "state.proto";
+
+option java_package = "androidx.wear.tiles.testing.proto";
+option java_outer_classname = "ActionProto";
+
+// A launch action to send an intent to an Android activity.
+message AndroidActivity {
+  // The package name to send the intent to, for example, "com.google.weather".
+  string package_name = 1;
+
+  // The fully qualified class name (including the package) to send the intent
+  // to, for example, "com.google.weather.WeatherOverviewActivity".
+  string class_name = 2;
+}
+
+// An action used to launch another activity on the system. This can hold
+// multiple different underlying action types, which will be picked based on
+// what the underlying runtime believes to be suitable.
+message LaunchAction {
+  // An action to launch an Android activity.
+  AndroidActivity android_activity = 1;
+}
+
+// An action used to load (or reload) the tile contents.
+message LoadAction {
+  // The state to load the next tile with. This will be included in the
+  // TileRequest sent after this action is invoked by a Clickable.
+  State request_state = 1;
+}
+
+// An action that can be used by a layout element.
+message Action {
+  oneof value {
+    LaunchAction launch_action = 1;
+    LoadAction load_action = 2;
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/proto/color.proto b/wear/wear-tiles-renderer/src/androidTest/proto/color.proto
new file mode 100644
index 0000000..68cde643
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/proto/color.proto
@@ -0,0 +1,13 @@
+// Color utilities for layout elements.
+syntax = "proto3";
+
+package androidx.wear.tiles.testing.proto;
+
+option java_package = "androidx.wear.tiles.testing.proto";
+option java_outer_classname = "ColorProto";
+
+// A property defining a color.
+message ColorProp {
+  // The color value, in ARGB format.
+  uint32 argb = 1;
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/proto/device_parameters.proto b/wear/wear-tiles-renderer/src/androidTest/proto/device_parameters.proto
new file mode 100644
index 0000000..f7b34ff
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/proto/device_parameters.proto
@@ -0,0 +1,49 @@
+// Request messages used to fetch tiles and resources
+syntax = "proto3";
+
+package androidx.wear.tiles.testing.proto;
+
+option java_package = "androidx.wear.tiles.testing.proto";
+option java_outer_classname = "DeviceParametersProto";
+
+// The platform of the device requesting a tile.
+enum DevicePlatform {
+  // Device platform is undefined.
+  DEVICE_PLATFORM_UNDEFINED = 0;
+
+  // Device is a Wear OS by Google device.
+  DEVICE_PLATFORM_WEAR_OS = 1;
+}
+
+// The shape of a screen.
+enum ScreenShape {
+  // Screen shape is undefined.
+  SCREEN_SHAPE_UNDEFINED = 0;
+
+  // A round screen (typically found on most Wear devices).
+  SCREEN_SHAPE_ROUND = 1;
+
+  // Rectangular screens.
+  SCREEN_SHAPE_RECT = 2;
+}
+
+// Parameters describing the device requesting a tile update. This contains
+// physical and logical characteristics about the device (e.g. screen size and
+// density, etc).
+message DeviceParameters {
+  // Width of the device's screen in DP.
+  uint32 screen_width_dp = 1;
+
+  // Height of the device's screen in DP.
+  uint32 screen_height_dp = 2;
+
+  // Density of the display. This value is the scaling factor to get from DP to
+  // Pixels (px = dp * density).
+  float screen_density = 3;
+
+  // The platform of the device.
+  DevicePlatform device_platform = 4;
+
+  // The shape of the device's screen
+  ScreenShape screen_shape = 5;
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/proto/dimension.proto b/wear/wear-tiles-renderer/src/androidTest/proto/dimension.proto
new file mode 100644
index 0000000..e53ddea
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/proto/dimension.proto
@@ -0,0 +1,85 @@
+// Dimensions for layout elements.
+syntax = "proto3";
+
+package androidx.wear.tiles.testing.proto;
+
+
+option java_package = "androidx.wear.tiles.testing.proto";
+option java_outer_classname = "DimensionProto";
+
+// A type for linear dimensions, measured in dp.
+message DpProp {
+  // The value, in dp.
+  float value = 1;
+}
+
+// A type for font sizes, measured in sp.
+message SpProp {
+  // The value, in sp.
+  float value = 2;
+
+  reserved 1;
+}
+
+// A type for font spacing, measured in em.
+message EmProp {
+  // The value, in em.
+  float value = 1;
+}
+
+// A type for angular dimensions, measured in degrees.
+message DegreesProp {
+  // The value, in degrees.
+  float value = 1;
+}
+
+// A type for a dimension that fills all the space it can (i.e. MATCH_PARENT in
+// Android parlance)
+message ExpandedDimensionProp {}
+
+// A type for a dimension that sizes itself to the size of its children (i.e.
+// WRAP_CONTENT in Android parlance)
+message WrappedDimensionProp {}
+
+// A type for a dimension that scales itself proportionally to another dimension
+// such that the aspect ratio defined by the given width and height values is
+// preserved.
+//
+// Note that the width and height are unitless; only their ratio is relevant.
+// This allows for specifying an element's size using common ratios (e.g.
+// width=4, height=3), or to allow an element to be resized proportionally based
+// on the size of an underlying asset (e.g. an 800x600 image being added to a
+// smaller container and resized accordingly).
+message ProportionalDimensionProp {
+  // The width to be used when calculating the aspect ratio to preserve.
+  uint32 aspect_ratio_width = 1;
+
+  // The height to be used when calculating the aspect ratio ratio to preserve.
+  uint32 aspect_ratio_height = 2;
+}
+
+// A dimension that can be applied to a container.
+message ContainerDimension {
+  oneof inner {
+    DpProp linear_dimension = 1;
+    ExpandedDimensionProp expanded_dimension = 2;
+    WrappedDimensionProp wrapped_dimension = 3;
+  }
+}
+
+// A dimension that can be applied to an image.
+message ImageDimension {
+  oneof inner {
+    DpProp linear_dimension = 1;
+    ExpandedDimensionProp expanded_dimension = 2;
+    ProportionalDimensionProp proportional_dimension = 3;
+  }
+}
+
+// A dimension that can be applied to a spacer.
+message SpacerDimension {
+  oneof inner {
+    DpProp linear_dimension = 1;
+    // TODO(b/169137847): Add ExpandedDimensionProp
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/proto/events.proto b/wear/wear-tiles-renderer/src/androidTest/proto/events.proto
new file mode 100644
index 0000000..350394c
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/proto/events.proto
@@ -0,0 +1,34 @@
+// Messages used when events happen in the Tiles system.
+syntax = "proto3";
+
+package androidx.wear.tiles.testing.proto;
+
+
+option java_package = "androidx.wear.tiles.testing.proto";
+option java_outer_classname = "EventProto";
+
+// Event fired when a tile has been added to the carousel.
+message TileAddEvent {
+  // The ID of the tile added to the carousel.
+  uint32 tile_id = 1;
+}
+
+// Event fired when a tile has been removed from the carousel.
+message TileRemoveEvent {
+  // The ID of the tile removed from the carousel.
+  uint32 tile_id = 1;
+}
+
+// Event fired when a tile is swiped to by the user (i.e. it's visible on
+// screen).
+message TileEnterEvent {
+  // The ID of the entered tile.
+  uint32 tile_id = 1;
+}
+
+// Event fired when a tile is swiped away from by the user (i.e. it's no longer
+// visible on screen).
+message TileLeaveEvent {
+  // The ID of the tile.
+  uint32 tile_id = 1;
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/proto/layout.proto b/wear/wear-tiles-renderer/src/androidTest/proto/layout.proto
new file mode 100644
index 0000000..30f6573
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/proto/layout.proto
@@ -0,0 +1,594 @@
+// Composable layout elements that can be combined together to create renderable
+// UI layouts.
+syntax = "proto3";
+
+package androidx.wear.tiles.testing.proto;
+
+import "color.proto";
+import "dimension.proto";
+import "modifiers.proto";
+import "types.proto";
+
+option java_package = "androidx.wear.tiles.testing.proto";
+option java_outer_classname = "LayoutElementProto";
+
+// The horizontal alignment of an element within its container.
+enum HorizontalAlignment {
+  // Horizontal alignment is undefined.
+  HALIGN_UNDEFINED = 0;
+
+  // Horizontally align to the left.
+  HALIGN_LEFT = 1;
+
+  // Horizontally align to center.
+  HALIGN_CENTER = 2;
+
+  // Horizontally align to the right.
+  HALIGN_RIGHT = 3;
+
+  // Horizontally align to the content start (left in LTR layouts, right in RTL
+  // layouts).
+  HALIGN_START = 4;
+
+  // Horizontally align to the content end (right in LTR layouts, left in RTL
+  // layouts).
+  HALIGN_END = 5;
+}
+
+// An extensible HorizontalAlignment property.
+message HorizontalAlignmentProp {
+  // The value
+  HorizontalAlignment value = 1;
+}
+
+// The vertical alignment of an element within its container.
+enum VerticalAlignment {
+  // Vertical alignment is undefined.
+  VALIGN_UNDEFINED = 0;
+
+  // Vertically align to the top.
+  VALIGN_TOP = 1;
+
+  // Vertically align to center.
+  VALIGN_CENTER = 2;
+
+  // Vertically align to the bottom.
+  VALIGN_BOTTOM = 3;
+}
+
+// An extensible VerticalAlignment property.
+message VerticalAlignmentProp {
+  // The value.
+  VerticalAlignment value = 1;
+}
+
+// The weight to be applied to the font.
+enum FontWeight {
+  // Font weight is undefined.
+  FONT_WEIGHT_UNDEFINED = 0;
+
+  // Normal font weight.
+  FONT_WEIGHT_NORMAL = 400;
+
+  // Bold font weight.
+  FONT_WEIGHT_BOLD = 700;
+}
+
+// An extensible FontWeight property.
+message FontWeightProp {
+  // The value.
+  FontWeight value = 1;
+}
+
+// The styling of a font (e.g. font size, and metrics).
+message FontStyle {
+  // The size of the font, in scaled pixels (sp). If not specified, defaults to
+  // the size of the system's "body" font.
+  SpProp size = 1;
+
+  // Whether the text should be rendered in a italic typeface. If not specified,
+  // defaults to "false".
+  BoolProp italic = 2;
+
+  // Whether the text should be rendered with an underline. If not specified,
+  // defaults to "false".
+  BoolProp underline = 3;
+
+  // The text color. If not defined, defaults to white.
+  ColorProp color = 4;
+
+  // The weight of the font. If the provided value is not supported on a
+  // platform, the nearest supported value will be used. If not defined, or
+  // when set to an invalid value, defaults to "normal".
+  FontWeightProp weight = 5;
+
+  // The text letter-spacing. Positive numbers increase the space between
+  // letters while negative numbers tighten the space. If not specified,
+  // defaults to 0.
+  EmProp letter_spacing = 6;
+}
+
+// Alignment of a text element.
+enum TextAlignment {
+  // Alignment is undefined.
+  TEXT_ALIGN_UNDEFINED = 0;
+
+  // Align to the "start" of the Text element (left in LTR layouts, right in
+  // RTL layouts).
+  TEXT_ALIGN_START = 1;
+
+  // Align to the center of the Text element.
+  TEXT_ALIGN_CENTER = 2;
+
+  // Align to the "end" of the Text element (right in LTR layouts, left in RTL
+  // layouts).
+  TEXT_ALIGN_END = 3;
+}
+
+// An extensible TextAlignment property.
+message TextAlignmentProp {
+  // The value.
+  TextAlignment value = 1;
+}
+
+// How text that will not fit inside the bounds of a Text element will be
+// handled.
+//
+// TODO(b/175536688): Rename this to align with Spannable
+enum TextOverflow {
+  // Overflow behavior is undefined.
+  TEXT_OVERFLOW_UNDEFINED = 0;
+
+  // Truncate the text to fit inside of the Text element's bounds. If text is
+  // truncated, it will be truncated on a word boundary.
+  TEXT_OVERFLOW_TRUNCATE = 1;
+
+  // Truncate the text to fit in the Text element's bounds, but add an ellipsis
+  // (i.e. ...) to the end of the text if it has been truncated.
+  TEXT_OVERFLOW_ELLIPSIZE_END = 2;
+}
+
+// An extensible TextOverflow property.
+message TextOverflowProp {
+  // The value.
+  TextOverflow value = 1;
+}
+
+// The anchor position of an Arc's elements. This is used to specify how
+// elements added to an Arc should be laid out with respect to anchor_angle.
+//
+// As an example, assume that the following diagrams are wrapped to an arc, and
+// each represents an Arc element containing a single Text element. The Text
+// element's anchor_angle is "0" for all cases.
+//
+// ```
+// ARC_ANCHOR_START:
+// -180                                0                                    180
+//                                     Hello World!
+//
+//
+// ARC_ANCHOR_CENTER:
+// -180                                0                                    180
+//                                Hello World!
+//
+// ARC_ANCHOR_END:
+// -180                                0                                    180
+//                          Hello World!
+// ```
+enum ArcAnchorType {
+  // Anchor position is undefined.
+  ARC_ANCHOR_UNDEFINED = 0;
+
+  // Anchor at the start of the elements. This will cause elements added to an
+  // arc to begin at the given anchor_angle, and sweep around to the right.
+  ARC_ANCHOR_START = 1;
+
+  // Anchor at the center of the elements. This will cause the center of the
+  // whole set of elements added to an arc to be pinned at the given
+  // anchor_angle.
+  ARC_ANCHOR_CENTER = 2;
+
+  // Anchor at the end of the elements. This will cause the set of elements
+  // inside the arc to end at the specified anchor_angle, i.e. all elements
+  // should be to the left of anchor_angle.
+  ARC_ANCHOR_END = 3;
+}
+
+// An extensible ArcAnchorType property.
+message ArcAnchorTypeProp {
+  // The value.
+  ArcAnchorType value = 1;
+}
+
+// A text string.
+message Text {
+  // The text to render.
+  StringProp text = 1;
+
+  // The style of font to use (size, bold etc). If not specified, defaults to
+  // the platform's default body font.
+  FontStyle font_style = 2;
+
+  // Modifiers for this element.
+  Modifiers modifiers = 3;
+
+  // The maximum number of lines that can be represented by the Text element.
+  // If not defined, the Text element will be treated as a single-line element.
+  Int32Prop max_lines = 4;
+
+  // Alignment of the text within its bounds. Note that a Text element will size
+  // itself to wrap its contents, so this option is meaningless for single-line
+  // text (for that, use alignment of the outer container). For multi-line text,
+  // however, this will set the alignment of lines relative to the Text element
+  // bounds. If not defined, defaults to TEXT_ALIGN_CENTER.
+  TextAlignmentProp multiline_alignment = 5;
+
+  // How to handle text which overflows the bound of the Text element.
+  // A Text element will grow as large as possible inside its parent container
+  // (while still respecting max_lines); if it cannot grow large  enough to
+  // render all of its text, the text which cannot fit inside its container will
+  // be truncated. If not defined, defaults to TEXT_OVERFLOW_TRUNCATE.
+  TextOverflowProp overflow = 6;
+
+  // The explicit height between lines of text. This is equivalent to the
+  // vertical distance between subsequent baselines. If not specified, defaults
+  // the font's recommended interline spacing.
+  SpProp line_height = 7;
+}
+
+// How content which does not match the dimensions of its bounds (e.g. an image
+// resource being drawn inside an Image) will be resized to fit its bounds.
+enum ContentScaleMode {
+  // Content scaling is undefined.
+  CONTENT_SCALE_MODE_UNDEFINED = 0;
+
+  // Content will be scaled to fit inside its bounds, proportionally. As an
+  // example, If a 10x5 image was going to be drawn inside a 50x50 Image
+  // element, the actual image resource would be drawn as a 50x25 image,
+  // centered within the 50x50 bounds.
+  CONTENT_SCALE_MODE_FIT = 1;
+
+  // Content will be resized proportionally so it completely fills its bounds,
+  // and anything outside of the bounds will be cropped. As an example, if a
+  // 10x5 image was going to be drawn inside a 50x50 Image element, the image
+  // resource would be drawn as a 100x50 image, centered within its bounds (and
+  // with 25px cropped from both the left and right sides).
+  CONTENT_SCALE_MODE_CROP = 2;
+
+  // Content will be resized to fill its bounds, without taking into account the
+  // aspect ratio. If a 10x5 image was going to be drawn inside a 50x50 Image
+  // element, the image would be drawn as a 50x50 image, stretched vertically.
+  CONTENT_SCALE_MODE_FILL_BOUNDS = 3;
+}
+
+// An extensible ContentScaleMode property.
+message ContentScaleModeProp {
+  ContentScaleMode value = 1;
+}
+
+// An image.
+//
+// Images used in this element must exist in the resource bundle that
+// corresponds to this layout. Images must have their dimension specified, and
+// will be rendered at this width and height, regardless of their native
+// dimension.
+message Image {
+  // The resource_id of the image to render. This must exist in the supplied
+  // resource bundle.
+  StringProp resource_id = 1;
+
+  // The width of this image. If not defined, the image will not be rendered.
+  ImageDimension width = 2;
+
+  // The height of this image. If not defined, the image will not be rendered.
+  ImageDimension height = 3;
+
+  // How to scale the image resource inside the bounds specified by width/height
+  // if its size does not match those bounds. Defaults to
+  // CONTENT_SCALE_MODE_FIT.
+  ContentScaleModeProp content_scale_mode = 4;
+
+  // Modifiers for this element.
+  Modifiers modifiers = 5;
+}
+
+// A simple spacer, typically used to provide padding between adjacent elements.
+message Spacer {
+  // The width of this Spacer. When this is added as the direct child of an Arc,
+  // this must be specified as an angular dimension, otherwise a linear
+  // dimension must be used. If not defined, defaults to 0.
+  SpacerDimension width = 1;
+
+  // The height of this spacer. If not defined, defaults to 0.
+  SpacerDimension height = 2;
+
+  // Modifiers for this element.
+  Modifiers modifiers = 3;
+}
+
+// A container which stacks all of its children on top of one another. This also
+// allows to add a background color, or to have a border around them with some
+// padding.
+message Box {
+  // The child element(s) to wrap.
+  repeated LayoutElement contents = 1;
+
+  // The height of this Box. If not defined, this will size itself to fit all of
+  // its children (i.e. a WrappedDimension).
+  ContainerDimension height = 2;
+
+  // The width of this Box. If not defined, this will size itself to fit all of
+  // its children (i.e. a WrappedDimension).
+  ContainerDimension width = 3;
+
+  // The horizontal alignment of the element inside this Box. If not defined,
+  // defaults to HALIGN_CENTER.
+  HorizontalAlignmentProp horizontal_alignment = 4;
+
+  // The vertical alignment of the element inside this Box. If not defined,
+  // defaults to VALIGN_CENTER.
+  VerticalAlignmentProp vertical_alignment = 5;
+
+  // Modifiers for this element.
+  Modifiers modifiers = 6;
+}
+
+// A portion of text which can be added to a Span. Two different SpanText
+// elements on the same line will be aligned to the same baseline, regardless of
+// the size of each SpanText.
+message SpanText {
+  // The text to render.
+  StringProp text = 1;
+
+  // The style of font to use (size, bold etc). If not specified, defaults to
+  // the platform's default body font.
+  FontStyle font_style = 2;
+
+  // Modifiers for this element.
+  SpanModifiers modifiers = 3;
+}
+
+// An image which can be added to a Span.
+message SpanImage {
+  // The resource_id of the image to render. This must exist in the supplied
+  // resource bundle.
+  StringProp resource_id = 1;
+
+  // The width of this image. If not defined, the image will not be rendered.
+  DpProp width = 2;
+
+  // The height of this image. If not defined, the image will not be rendered.
+  DpProp height = 3;
+
+  // Modifiers for this element.
+  SpanModifiers modifiers = 4;
+}
+
+// A single Span. Each Span forms part of a larger Spannable widget. At the
+// moment, the only widgets which can be added to Spannable containers are
+// SpanText and SpanImage elements.
+message Span {
+  oneof inner {
+    SpanText text = 1;
+    SpanImage image = 2;
+  }
+}
+
+// A container of Span elements. Currently, this only supports Text elements,
+// where each individual Span can have different styling applied to it but the
+// resulting text will flow naturally. This allows sections of a paragraph of
+// text to have different styling applied to it, for example, making one or two
+// words bold or italic.
+message Spannable {
+  // The Span elements that form this Spannable.
+  repeated Span spans = 1;
+
+  // Modifiers for this element.
+  Modifiers modifiers = 2;
+
+  // The maximum number of lines that can be represented by the Spannable
+  // element. If not defined, the Spannable element will be treated as a
+  // single-line element.
+  Int32Prop max_lines = 3;
+
+  // Alignment of the Spannable content within its bounds. Note that a Spannable
+  // element will size itself to wrap its contents, so this option is
+  // meaningless for single-line content (for that, use alignment of the outer
+  // container). For multi-line content, however, this will set the alignment of
+  // lines relative to the Spannable element bounds. If not defined, defaults to
+  // TEXT_ALIGN_CENTER.
+  HorizontalAlignmentProp multiline_alignment = 4;
+
+  // How to handle content which overflows the bound of the Spannable element.
+  // A Spannable element will grow as large as possible inside its parent
+  // container (while still respecting max_lines); if it cannot grow large
+  // enough to render all of its content, the content which cannot fit inside
+  // its container will  be truncated. If not defined, defaults to
+  // TEXT_OVERFLOW_TRUNCATE.
+  TextOverflowProp overflow = 5;
+
+  // Extra spacing to add between each line. This will apply to all
+  // spans regardless of their font size. This is in addition to original
+  // line heights. Note that this won't add any additional space before the
+  // first line or after the last line. The default value is zero and negative
+  // values will decrease the interline spacing.
+  SpProp line_spacing = 6;
+}
+
+// A column of elements. Each child element will be laid out vertically, one
+// after another (i.e. stacking down). This element will size itself to the
+// smallest size required to hold all of its children (e.g. if it contains three
+// elements sized 10x10, 20x20 and 30x30, the resulting column will be 30x60).
+//
+// If specified, horizontal_alignment can be used to control the gravity inside
+// the container, affecting the horizontal placement of children whose width are
+// smaller than the resulting column width.
+message Column {
+  // The list of child elements to place inside this Column.
+  repeated LayoutElement contents = 1;
+
+  // The horizontal alignment of elements inside this column, if they are
+  // narrower than the resulting width of the column. If not defined, defaults
+  // to HALIGN_CENTER.
+  HorizontalAlignmentProp horizontal_alignment = 2;
+
+  // The width of this column. If not defined, this will size itself to fit
+  // all of its children (i.e. a WrappedDimension).
+  ContainerDimension width = 3;
+
+  // The height of this column. If not defined, this will size itself to fit
+  // all of its children (i.e. a WrappedDimension).
+  ContainerDimension height = 4;
+
+  // Modifiers for this element.
+  Modifiers modifiers = 5;
+}
+
+// A row of elements. Each child will be laid out horizontally, one after
+// another (i.e. stacking to the right). This element will size itself to the
+// smallest size required to hold all of its children (e.g. if it contains three
+// elements sized 10x10, 20x20 and 30x30, the resulting row will be 60x30).
+//
+// If specified, vertical_alignment can be used to control the gravity inside
+// the container, affecting the vertical placement of children whose width are
+// smaller than the resulting row height.
+message Row {
+  // The list of child elements to place inside this Row.
+  repeated LayoutElement contents = 1;
+
+  // The vertical alignment of elements inside this row, if they are narrower
+  // than the resulting height of the row. If not defined, defaults to
+  // VALIGN_CENTER.
+  VerticalAlignmentProp vertical_alignment = 2;
+
+  // The width of this row. If not defined, this will size itself to fit
+  // all of its children (i.e. a WrappedDimension).
+  ContainerDimension width = 3;
+
+  // The height of this row. If not defined, this will size itself to fit
+  // all of its children (i.e. a WrappedDimension).
+  ContainerDimension height = 4;
+
+  // Modifiers for this element.
+  Modifiers modifiers = 5;
+}
+
+// An arc container. This container will fill itself to a circle, which fits
+// inside its parent container, and all of its children will be placed on that
+// circle. The fields anchor_angle and anchor_type can be used to specify where
+// to draw children within this circle.
+message Arc {
+  // Contents of this container.
+  repeated ArcLayoutElement contents = 1;
+
+  // The angle for the anchor, used with anchor_type to determine where to draw
+  // children. Note that 0 degrees is the 12 o clock position on a device, and
+  // the angle sweeps clockwise. If not defined, defaults to 0 degrees.
+  //
+  // Values do not have to be clamped to the range 0-360; values less than 0
+  // degrees will sweep anti-clockwise (i.e. -90 degrees is equivalent to 270
+  // degrees), and values >360 will be be placed at X mod 360 degrees.
+  DegreesProp anchor_angle = 2;
+
+  // How to align the contents of this container relative to anchor_angle. See
+  // the descriptions of options in ArcAnchorType for more information. If not
+  // defined, defaults to ARC_ANCHOR_CENTER.
+  ArcAnchorTypeProp anchor_type = 3;
+
+  // Vertical alignment of elements within the arc. If the Arc's thickness is
+  // larger than the thickness of the element being drawn, this controls whether
+  // the element should be drawn towards the inner or outer edge of the arc, or
+  // drawn in the center.
+  // If not defined, defaults to VALIGN_CENTER
+  VerticalAlignmentProp vertical_align = 4;
+
+  // Modifiers for this element.
+  Modifiers modifiers = 5;
+}
+
+// A text element that can be used in an Arc.
+message ArcText {
+  // The text to render.
+  StringProp text = 1;
+
+  // The style of font to use (size, bold etc). If not specified, defaults to
+  // the platform's default body font.
+  FontStyle font_style = 2;
+
+  // Modifiers for this element.
+  ArcModifiers modifiers = 3;
+}
+
+// A line that can be used in an Arc and renders as a round progress bar.
+message ArcLine {
+  // The length of this line, in degrees. If not defined, defaults to 0.
+  DegreesProp length = 1;
+
+  // The thickness of this line. If not defined, defaults to 0.
+  DpProp thickness = 2;
+
+  // The color of this line.
+  ColorProp color = 3;
+
+  // Modifiers for this element.
+  ArcModifiers modifiers = 4;
+}
+
+// A simple spacer used to provide padding between adjacent elements in an Arc.
+message ArcSpacer {
+  // The length of this spacer, in degrees. If not defined, defaults to 0.
+  DegreesProp length = 1;
+
+  // The thickness of this spacer, in DP. If not defined, defaults to 0.
+  DpProp thickness = 2;
+
+  // Modifiers for this element.
+  ArcModifiers modifiers = 3;
+}
+
+// A container that allows a standard LayoutElement to be added to an Arc.
+message ArcAdapter {
+  // The element to adapt to an Arc.
+  LayoutElement content = 1;
+
+  // Whether this adapter's contents should be rotated, according to its
+  // position in the arc or not. As an example, assume that an Image has been
+  // added to the arc, and ends up at the 3 o clock position. If rotate_contents
+  // = true, the image will be placed at the 3 o clock position, and will be
+  // rotated clockwise through 90 degrees. If rotate_contents = false, the image
+  // will be placed at the 3 o clock position, but itself will not be rotated.
+  // If not defined, defaults to false.
+  BoolProp rotate_contents = 2;
+}
+
+// The root of all layout elements. This exists to act as a holder for all of
+// the actual layout elements above.
+message LayoutElement {
+  oneof inner {
+    Column column = 1;
+    Row row = 2;
+    Box box = 3;
+    Spacer spacer = 4;
+    Text text = 5;
+    Image image = 6;
+    Arc arc = 7;
+    Spannable spannable = 8;
+  }
+}
+
+// The root of all elements that can be used in an Arc. This exists to act as a
+// holder for all of the actual arc layout elements above.
+message ArcLayoutElement {
+  oneof inner {
+    ArcText text = 1;
+    ArcLine line = 2;
+    ArcSpacer spacer = 3;
+    ArcAdapter adapter = 4;
+  }
+}
+
+// A complete layout.
+message Layout {
+  // The root element in the layout.
+  LayoutElement root = 1;
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/proto/modifiers.proto b/wear/wear-tiles-renderer/src/androidTest/proto/modifiers.proto
new file mode 100644
index 0000000..e4b52b9
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/proto/modifiers.proto
@@ -0,0 +1,125 @@
+// Modifiers for composable layout elements.
+syntax = "proto3";
+
+package androidx.wear.tiles.testing.proto;
+
+import "action.proto";
+import "color.proto";
+import "dimension.proto";
+import "types.proto";
+
+option java_package = "androidx.wear.tiles.testing.proto";
+option java_outer_classname = "ModifiersProto";
+
+// A modifier for an element which can have associated Actions for click events.
+// When an element with a ClickableModifier is clicked it will fire the
+// associated action.
+message Clickable {
+  // The ID associated with this action.
+  string id = 1;
+
+  // The action to perform when the element this modifier is attached to is
+  // clicked.
+  Action on_click = 2;
+}
+
+// A modifier for an element which has accessibility semantics associated with
+// it. This should generally be used sparingly, and in most cases should only be
+// applied to the top-level layout element or to Clickables.
+message Semantics {
+  // The content description associated with this element. This will be dictated
+  // when the element is focused by the screen reader.
+  string content_description = 1;
+}
+
+// A modifier to apply padding around an element.
+message Padding {
+  // The padding on the end of the content, depending on the layout direction,
+  // in DP and the value of "rtl_aware".
+  DpProp end = 1;
+
+  // The padding on the start of the content, depending on the layout direction,
+  // in DP and the value of "rtl_aware".
+  DpProp start = 2;
+
+  // The padding at the top, in DP.
+  DpProp top = 3;
+
+  // The padding at the bottom, in DP.
+  DpProp bottom = 4;
+
+  // Whether the start/end padding is aware of RTL support. If true, the values
+  // for start/end will follow the layout direction (i.e. start will refer to
+  // the right hand side of the container if the device is using an RTL locale).
+  // If false, start/end will always map to left/right, accordingly.
+  BoolProp rtl_aware = 5;
+}
+
+// A modifier to apply a border around an element.
+message Border {
+  // The width of the border, in DP.
+  DpProp width = 1;
+
+  // The color of the border.
+  ColorProp color = 2;
+}
+
+// The corner of a Box element.
+message Corner {
+  // The radius of the corner in DP.
+  DpProp radius = 1;
+}
+
+// A modifier to apply a background to an element.
+message Background {
+  // The background color for this element. If not defined, defaults to being
+  // transparent.
+  ColorProp color = 1;
+
+  // The corner properties of this element. This only affects the drawing of
+  // this element if it has a background color or border. If not defined,
+  // defaults to having a square corner.
+  Corner corner = 2;
+}
+
+// Modifiers for an element. These may change the way they are drawn (e.g.
+// Padding or Background), or change their behaviour (e.g. Clickable, or
+// Semantics).
+message Modifiers {
+  // Allows its wrapped element to have actions associated with it, which will
+  // be executed when the element is tapped.
+  Clickable clickable = 1;
+
+  // Adds metadata for the modified element, for example, screen reader content
+  // descriptions.
+  Semantics semantics = 2;
+
+  // Adds padding to the modified element.
+  Padding padding = 3;
+
+  // Draws a border around the modified element.
+  Border border = 4;
+
+  // Adds a background (with optional corner radius) to the modified element.
+  Background background = 5;
+}
+
+// Modifiers that can be used with ArcLayoutElements. These may change the way
+// they are drawn, or change their behaviour.
+message ArcModifiers {
+  // Allows its wrapped element to have actions associated with it, which will
+  // be executed when the element is tapped.
+  Clickable clickable = 1;
+
+  // Adds metadata for the modified element, for example, screen reader content
+  // descriptions.
+  Semantics semantics = 2;
+}
+
+// Modifiers that can be used with Span elements. These may change the way
+// they are drawn, or change their behaviour.
+message SpanModifiers {
+  // Allows its wrapped element to have actions associated with it, which will
+  // be executed when the element is tapped.
+  Clickable clickable = 1;
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/proto/requests.proto b/wear/wear-tiles-renderer/src/androidTest/proto/requests.proto
new file mode 100644
index 0000000..2075e7c
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/proto/requests.proto
@@ -0,0 +1,34 @@
+// Request messages used to fetch tiles and resources
+syntax = "proto3";
+
+package androidx.wear.tiles.testing.proto;
+
+import "device_parameters.proto";
+import "state.proto";
+
+option java_package = "androidx.wear.tiles.testing.proto";
+option java_outer_classname = "RequestProto";
+
+// Parameters passed to a Tile provider when the renderer is requesting a new
+// version of the tile.
+message TileRequest {
+  // Parameters describing the device requesting the tile update.
+  DeviceParameters device_parameters = 1;
+
+  // The state that should be used when building the tile.
+  State state = 2;
+}
+
+// Parameters passed to a Tile provider when the renderer is requesting a
+// specific resource version.
+message ResourcesRequest {
+  // The version of the resources being fetched
+  string version = 1;
+
+  // Requested resource IDs. If not specified, all resources for the given
+  // version must be provided in the response.
+  repeated string resource_ids = 2;
+
+  // Parameters describing the device requesting the resources.
+  DeviceParameters device_parameters = 3;
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/proto/resources.proto b/wear/wear-tiles-renderer/src/androidTest/proto/resources.proto
new file mode 100644
index 0000000..d322ede
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/proto/resources.proto
@@ -0,0 +1,73 @@
+// The resources for a layout.
+syntax = "proto3";
+
+package androidx.wear.tiles.testing.proto;
+
+
+option java_package = "androidx.wear.tiles.testing.proto";
+option java_outer_classname = "ResourceProto";
+
+// Format describing the contents of an image data byte array.
+enum ImageFormat {
+  // An undefined image format.
+  IMAGE_FORMAT_UNDEFINED = 0;
+
+  // An image format where each pixel is stored on 2 bytes, with red using 5
+  // bits, green using 6 bits and blue using 5 bits of precision.
+  IMAGE_FORMAT_RGB_565 = 1;
+}
+
+// An image resource which maps to an Android drawable by resource ID.
+message AndroidImageResourceByResId {
+  // The Android resource ID of this image. This must refer to a drawable under
+  // R.drawable.
+  int32 resource_id = 1;
+}
+
+// An image resource whose data is fully inlined, with no dependency on a
+// system or app resource.
+message InlineImageResource {
+  // The byte array representing the image.
+  bytes data = 1;
+
+  // The native width of the image, in pixels. Only required for formats
+  // (e.g. IMAGE_FORMAT_RGB_565) where the image data does not include size.
+  int32 width_px = 2;
+
+  // The native height of the image, in pixels. Only required for formats
+  // (e.g. IMAGE_FORMAT_RGB_565) where the image data does not include size.
+  int32 height_px = 3;
+
+  // The format of the byte array data representing the image. May be left
+  // unspecified or set to IMAGE_FORMAT_UNDEFINED in which case the platform
+  // will attempt to extract this from the raw image data. If the platform does
+  // not support the format, the image will not be decoded or displayed.
+  ImageFormat format = 4;
+}
+
+// An image resource, which can be used by layouts. This holds multiple
+// underlying resource types, which the underlying runtime will pick according
+// to what it thinks is appropriate.
+message ImageResource {
+  // An image resource that maps to an Android drawable by resource ID.
+  AndroidImageResourceByResId android_resource_by_resid = 1;
+
+  // An image resource that contains the image data inline.
+  InlineImageResource inline_resource = 2;
+}
+
+// The resources for a layout.
+message Resources {
+  // The version of this Resources instance.
+  //
+  // Each tile specifies the version of resources it requires. After fetching a
+  // tile, the renderer will use the resources version specified by the tile
+  // to separately fetch the resources.
+  //
+  // This value must match the version of the resources required by the tile
+  // for the tile to render successfully.
+  string version = 1;
+
+  // A map of resource_ids to images, which can be used by layouts.
+  map<string, ImageResource> id_to_image = 2;
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/proto/state.proto b/wear/wear-tiles-renderer/src/androidTest/proto/state.proto
new file mode 100644
index 0000000..b771ec3
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/proto/state.proto
@@ -0,0 +1,14 @@
+// State of a tile.
+syntax = "proto3";
+
+package androidx.wear.tiles.testing.proto;
+
+
+option java_package = "androidx.wear.tiles.testing.proto";
+option java_outer_classname = "StateProto";
+
+// State information.
+message State {
+  // The ID of the clickable that was last clicked.
+  string last_clickable_id = 1;
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/proto/tile.proto b/wear/wear-tiles-renderer/src/androidTest/proto/tile.proto
new file mode 100644
index 0000000..8831717
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/proto/tile.proto
@@ -0,0 +1,30 @@
+// The components of a tile that can be rendered by a tile renderer.
+syntax = "proto3";
+
+package androidx.wear.tiles.testing.proto;
+
+import "timeline.proto";
+import "version.proto";
+
+option java_package = "androidx.wear.tiles.testing.proto";
+option java_outer_classname = "TileProto";
+
+// A holder for a tile. This specifies the resources to use for this delivery
+// of the tile, and the timeline for the tile.
+message Tile {
+  // The resource version required for these tiles.
+  string resources_version = 1;
+
+  // The tiles to show in the carousel, along with their validity periods.
+  Timeline timeline = 2;
+
+  // The schema version that this tile was built with.
+  VersionInfo schema_version = 3;
+
+  // How many milliseconds of elapsed time (**not** wall clock time) this tile
+  // can be considered to be "fresh". The platform will attempt to refresh
+  // your tile at some point in the future after this interval has lapsed. A
+  // value of 0 here signifies that auto-refreshes should not be used (i.e. you
+  // will manually request updates via TileProviderService#getRequester).
+  uint64 freshness_interval_millis = 4;
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/proto/timeline.proto b/wear/wear-tiles-renderer/src/androidTest/proto/timeline.proto
new file mode 100644
index 0000000..8aeb4fe
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/proto/timeline.proto
@@ -0,0 +1,46 @@
+// A timeline with entries representing content that should be displayed within
+// given time intervals.
+syntax = "proto3";
+
+package androidx.wear.tiles.testing.proto;
+
+import "layout.proto";
+
+option java_package = "androidx.wear.tiles.testing.proto";
+option java_outer_classname = "TimelineProto";
+
+// A time interval, typically used to describe the validity period of a
+// TimelineEntry
+message TimeInterval {
+  // Starting point of the time interval, in milliseconds since the Unix epoch.
+  int64 start_millis = 1;
+
+  // End point of the time interval, in milliseconds since the Unix epoch.
+  int64 end_millis = 2;
+}
+
+// One piece of renderable content along with the time that it is valid for.
+message TimelineEntry {
+  // The validity period for this timeline entry.
+  TimeInterval validity = 1;
+
+  // The contents of this timeline entry.
+  Layout layout = 2;
+}
+
+// A collection of TimelineEntry items.
+//
+// TimelineEntry items can be used to update a layout on-screen at known times,
+// without having to explicitly update a layout. This allows for cases where,
+// say, a calendar can be used to show the next event, and automatically switch
+// to showing the next event when one has passed.
+//
+// The active TimelineEntry is switched, at most, once a minute. In the case
+// where the validity periods of TimelineEntry items overlap, the item with the
+// *shortest* validity period will be shown. This allows a layout provider to
+// show a "default" layout, and override it at set points without having to
+// explicitly insert the default layout between the "override" layout.
+message Timeline {
+  // The entries in a timeline.
+  repeated TimelineEntry timeline_entries = 1;
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/proto/types.proto b/wear/wear-tiles-renderer/src/androidTest/proto/types.proto
new file mode 100644
index 0000000..5a224d6
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/proto/types.proto
@@ -0,0 +1,31 @@
+// Extensible primitive types used by layout elements.
+syntax = "proto3";
+
+package androidx.wear.tiles.testing.proto;
+
+option java_package = "androidx.wear.tiles.testing.proto";
+option java_outer_classname = "TypesProto";
+
+// An int32 type.
+message Int32Prop {
+  // The value.
+  int32 value = 1;
+}
+
+// A string type.
+message StringProp {
+  // The value.
+  string value = 1;
+}
+
+// A float type.
+message FloatProp {
+  // The value.
+  float value = 1;
+}
+
+// A boolean type.
+message BoolProp {
+  // The value.
+  bool value = 1;
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/proto/version.proto b/wear/wear-tiles-renderer/src/androidTest/proto/version.proto
new file mode 100644
index 0000000..76bf0d9
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/proto/version.proto
@@ -0,0 +1,21 @@
+// The components of a tile that can be rendered by a tile renderer.
+syntax = "proto3";
+
+package androidx.wear.tiles.testing.proto;
+
+
+option java_package = "androidx.wear.tiles.testing.proto";
+option java_outer_classname = "VersionProto";
+
+// Version information. This is used to encode the schema version of a payload
+// (e.g. inside of Tile).
+message VersionInfo {
+  // Major version. Incremented on breaking changes (i.e. compatibility is not
+  // guaranteed across major versions).
+  uint32 major = 1;
+
+  // Minor version. Incremented on non-breaking changes (e.g. schema additions).
+  // Anything consuming a payload can safely consume anything with a lower
+  // minor version.
+  uint32 minor = 2;
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/drawable/android_24dp.xml b/wear/wear-tiles-renderer/src/androidTest/res/drawable/android_24dp.xml
new file mode 100644
index 0000000..17ebdea
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/drawable/android_24dp.xml
@@ -0,0 +1,5 @@
+<vector android:height="24dp" android:tint="#FFFFFF"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+  <path android:fillColor="#FF000000" android:pathData="M17.6,11.48 L19.44,8.3a0.63,0.63 0,0 0,-1.09 -0.63l-1.88,3.24a11.43,11.43 0,0 0,-8.94 0L5.65,7.67a0.63,0.63 0,0 0,-1.09 0.63L6.4,11.48A10.81,10.81 0,0 0,1 20L23,20A10.81,10.81 0,0 0,17.6 11.48ZM7,17.25A1.25,1.25 0,1 1,8.25 16,1.25 1.25,0 0,1 7,17.25ZM17,17.25A1.25,1.25 0,1 1,18.25 16,1.25 1.25,0 0,1 17,17.25Z"/>
+</vector>
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/drawable/broken_drawable.xml b/wear/wear-tiles-renderer/src/androidTest/res/drawable/broken_drawable.xml
new file mode 100644
index 0000000..04ead12
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/drawable/broken_drawable.xml
@@ -0,0 +1 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="21dp" android:height="29.7dp" android:viewportWidth="210" android:viewportHeight="297"></vector>
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/drawable/filled_image.png b/wear/wear-tiles-renderer/src/androidTest/res/drawable/filled_image.png
new file mode 100644
index 0000000..a6da988
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/drawable/filled_image.png
Binary files differ
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/drawable/ic_channel_foreground.xml b/wear/wear-tiles-renderer/src/androidTest/res/drawable/ic_channel_foreground.xml
new file mode 100644
index 0000000..399d346
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/drawable/ic_channel_foreground.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="120dp"
+    android:height="120dp"
+    android:viewportWidth="120"
+    android:viewportHeight="120"
+    android:tint="#FFFFFF">
+  <group android:scaleX="2.9"
+      android:scaleY="2.9"
+      android:translateX="25.2"
+      android:translateY="25.2">
+      <path
+          android:pathData="M17.6,11.48 L19.44,8.3a0.63,0.63 0,0 0,-1.09 -0.63l-1.88,3.24a11.43,11.43 0,0 0,-8.94 0L5.65,7.67a0.63,0.63 0,0 0,-1.09 0.63L6.4,11.48A10.81,10.81 0,0 0,1 20L23,20A10.81,10.81 0,0 0,17.6 11.48ZM7,17.25A1.25,1.25 0,1 1,8.25 16,1.25 1.25,0 0,1 7,17.25ZM17,17.25A1.25,1.25 0,1 1,18.25 16,1.25 1.25,0 0,1 17,17.25Z"
+          android:fillColor="#FF000000"/>
+  </group>
+</vector>
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/mipmap-anydpi-v26/android_withbg_120dp.xml b/wear/wear-tiles-renderer/src/androidTest/res/mipmap-anydpi-v26/android_withbg_120dp.xml
new file mode 100644
index 0000000..5c4c23a
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/mipmap-anydpi-v26/android_withbg_120dp.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@color/ic_channel_background"/>
+    <foreground android:drawable="@drawable/ic_channel_foreground"/>
+</adaptive-icon>
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/all_modifiers.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/all_modifiers.textproto
new file mode 100644
index 0000000..ac2b253
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/all_modifiers.textproto
@@ -0,0 +1,41 @@
+# Note: this test is really an analog of box_with_corners_and_border. This
+# should produce an identical result.
+text {
+  text {
+    value: "Hello World"
+  }
+  modifiers {
+    background {
+      color {
+        argb: 0xFF00FF00
+      }
+      corner {
+        radius {
+          value: 5
+        }
+      }
+    }
+    padding {
+      end {
+        value: 10
+      }
+      top {
+        value: 20
+      }
+      bottom {
+        value: 30
+      }
+      start {
+        value: 40
+      }
+    }
+    border {
+      color {
+        argb: 0xFFFF0000
+      }
+      width {
+        value: 5
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_above_360.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_above_360.textproto
new file mode 100644
index 0000000..7573de9
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_above_360.textproto
@@ -0,0 +1,76 @@
+box {
+  modifiers {
+    background {
+      color {
+        argb: 0xFF000000
+      }
+    }
+  }
+  width {
+    expanded_dimension {}
+  }
+  height {
+    expanded_dimension {}
+  }
+
+  contents {
+    arc {
+      contents {
+        line {
+          length {
+            value: 360
+          }
+          color {
+            argb: 0xFFFF0000
+          }
+          thickness {
+            value: 11
+          }
+        }
+      }
+    }
+  }
+  contents {
+    box {
+      width {
+        expanded_dimension {}
+      }
+      height {
+        expanded_dimension {}
+      }
+      modifiers {
+        padding {
+          top {
+            value: 15
+          }
+          end {
+            value: 15
+          }
+          bottom {
+            value: 15
+          }
+          start {
+            value: 15
+          }
+        }
+      }
+      contents {
+        arc {
+          contents {
+            line {
+              length {
+                value: 750
+              }
+              color {
+                argb: 0xFF00FF00
+              }
+              thickness {
+                value: 11
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_alignment.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_alignment.textproto
new file mode 100644
index 0000000..a9edc23
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_alignment.textproto
@@ -0,0 +1,213 @@
+box {
+  width {
+    expanded_dimension {}
+  }
+  height {
+    expanded_dimension {}
+  }
+
+  contents {
+    arc {
+      anchor_type: {
+        value: ARC_ANCHOR_START
+      }
+      anchor_angle: {
+        value: 0
+      }
+      vertical_align {
+        value: VALIGN_TOP
+      }
+      contents {
+        text {
+          text {
+            value: "TOP"
+          }
+          font_style {
+            weight {
+              value: FONT_WEIGHT_BOLD
+            }
+            size {
+              value: 16
+            }
+            color {
+              argb: 0xFFFF0000
+            }
+          }
+        }
+      }
+      contents {
+        spacer {
+          length {
+            value: 15
+          }
+        }
+      }
+      contents {
+        line {
+          color {
+            argb: 0xFF00FF00
+          }
+          length {
+            value: 10
+          }
+          thickness {
+            value: 50
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    arc {
+      anchor_type: {
+        value: ARC_ANCHOR_START
+      }
+      anchor_angle: {
+        value: 90
+      }
+      vertical_align {
+        value: VALIGN_CENTER
+      }
+      contents {
+        text {
+          text {
+            value: "CENTER"
+          }
+          font_style {
+            weight {
+              value: FONT_WEIGHT_BOLD
+            }
+            size {
+              value: 16
+            }
+            color {
+              argb: 0xFFFF0000
+            }
+          }
+        }
+      }
+      contents {
+        spacer {
+          length {
+            value: 15
+          }
+        }
+      }
+      contents {
+        line {
+          color {
+            argb: 0xFF00FF00
+          }
+          length {
+            value: 10
+          }
+          thickness {
+            value: 50
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    arc {
+      anchor_type: {
+        value: ARC_ANCHOR_START
+      }
+      anchor_angle: {
+        value: 180
+      }
+      vertical_align {
+        value: VALIGN_BOTTOM
+      }
+      contents {
+        text {
+          text {
+            value: "BOT"
+          }
+          font_style {
+            weight {
+              value: FONT_WEIGHT_BOLD
+            }
+            size {
+              value: 16
+            }
+            color {
+              argb: 0xFFFF0000
+            }
+          }
+        }
+      }
+      contents {
+        spacer {
+          length {
+            value: 15
+          }
+        }
+      }
+      contents {
+        line {
+          color {
+            argb: 0xFF00FF00
+          }
+          length {
+            value: 10
+          }
+          thickness {
+            value: 50
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    arc {
+      anchor_type: {
+        value: ARC_ANCHOR_START
+      }
+      anchor_angle: {
+        value: 270
+      }
+      contents {
+        text {
+          text {
+            value: "DEF"
+          }
+          font_style {
+            weight {
+              value: FONT_WEIGHT_BOLD
+            }
+            size {
+              value: 16
+            }
+            color {
+              argb: 0xFFFF0000
+            }
+          }
+        }
+      }
+      contents {
+        spacer {
+          length {
+            value: 15
+          }
+        }
+      }
+      contents {
+        line {
+          color {
+            argb: 0xFF00FF00
+          }
+          length {
+            value: 10
+          }
+          thickness {
+            value: 50
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_alignment_mixed_types.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_alignment_mixed_types.textproto
new file mode 100644
index 0000000..fc6e0e8
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_alignment_mixed_types.textproto
@@ -0,0 +1,374 @@
+box {
+  width {
+    expanded_dimension {}
+  }
+  height {
+    expanded_dimension {}
+  }
+
+  contents {
+    arc {
+      anchor_type: {
+        value: ARC_ANCHOR_START
+      }
+      anchor_angle: {
+        value: 0
+      }
+      vertical_align {
+        value: VALIGN_TOP
+      }
+      contents {
+        adapter {
+          content {
+            box {
+              horizontal_alignment {
+                value: HALIGN_CENTER
+              }
+              vertical_alignment {
+                value: VALIGN_CENTER
+              }
+              modifiers {
+                background {
+                  color {
+                    argb: 0xFFFF0000
+                  }
+                  corner {
+                    radius {
+                      value: 12
+                    }
+                  }
+                }
+              }
+              contents {
+                spacer {
+                  width {
+                    linear_dimension {
+                      value: 24
+                    }
+                  }
+                  height {
+                    linear_dimension {
+                      value: 24
+                    }
+                  }
+                }
+              }
+              contents {
+                text {
+                  text {
+                    value: "T"
+                  }
+                  font_style {
+                    weight {
+                      value: FONT_WEIGHT_BOLD
+                    }
+                    size {
+                      value: 16
+                    }
+                    color {
+                      argb: 0xFFFFFFFF
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      contents {
+        spacer {
+          length {
+            value: 20
+          }
+        }
+      }
+      contents {
+        line {
+          color {
+            argb: 0xFF00FF00
+          }
+          length {
+            value: 10
+          }
+          thickness {
+            value: 60
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    arc {
+      anchor_type: {
+        value: ARC_ANCHOR_START
+      }
+      anchor_angle: {
+        value: 90
+      }
+      vertical_align {
+        value: VALIGN_CENTER
+      }
+      contents {
+        adapter {
+          content {
+            box {
+              horizontal_alignment {
+                value: HALIGN_CENTER
+              }
+              vertical_alignment {
+                value: VALIGN_CENTER
+              }
+              modifiers {
+                background {
+                  color {
+                    argb: 0xFFFF0000
+                  }
+                  corner {
+                    radius {
+                      value: 12
+                    }
+                  }
+                }
+              }
+              contents {
+                spacer {
+                  width {
+                    linear_dimension {
+                      value: 24
+                    }
+                  }
+                  height {
+                    linear_dimension {
+                      value: 24
+                    }
+                  }
+                }
+              }
+              contents {
+                text {
+                  text {
+                    value: "C"
+                  }
+                  font_style {
+                    weight {
+                      value: FONT_WEIGHT_BOLD
+                    }
+                    size {
+                      value: 16
+                    }
+                    color {
+                      argb: 0xFFFFFFFF
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      contents {
+        spacer {
+          length {
+            value: 20
+          }
+        }
+      }
+      contents {
+        line {
+          color {
+            argb: 0xFF00FF00
+          }
+          length {
+            value: 10
+          }
+          thickness {
+            value: 60
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    arc {
+      anchor_type: {
+        value: ARC_ANCHOR_START
+      }
+      anchor_angle: {
+        value: 180
+      }
+      vertical_align {
+        value: VALIGN_BOTTOM
+      }
+      contents {
+        adapter {
+          content {
+            box {
+              horizontal_alignment {
+                value: HALIGN_CENTER
+              }
+              vertical_alignment {
+                value: VALIGN_CENTER
+              }
+              modifiers {
+                background {
+                  color {
+                    argb: 0xFFFF0000
+                  }
+                  corner {
+                    radius {
+                      value: 12
+                    }
+                  }
+                }
+              }
+              contents {
+                spacer {
+                  width {
+                    linear_dimension {
+                      value: 24
+                    }
+                  }
+                  height {
+                    linear_dimension {
+                      value: 24
+                    }
+                  }
+                }
+              }
+              contents {
+                text {
+                  text {
+                    value: "B"
+                  }
+                  font_style {
+                    weight {
+                      value: FONT_WEIGHT_BOLD
+                    }
+                    size {
+                      value: 16
+                    }
+                    color {
+                      argb: 0xFFFFFFFF
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      contents {
+        spacer {
+          length {
+            value: 20
+          }
+        }
+      }
+      contents {
+        line {
+          color {
+            argb: 0xFF00FF00
+          }
+          length {
+            value: 10
+          }
+          thickness {
+            value: 60
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    arc {
+      anchor_type: {
+        value: ARC_ANCHOR_START
+      }
+      anchor_angle: {
+        value: 270
+      }
+      contents {
+        adapter {
+          content {
+            box {
+              horizontal_alignment {
+                value: HALIGN_CENTER
+              }
+              vertical_alignment {
+                value: VALIGN_CENTER
+              }
+              modifiers {
+                background {
+                  color {
+                    argb: 0xFFFF0000
+                  }
+                  corner {
+                    radius {
+                      value: 12
+                    }
+                  }
+                }
+              }
+              contents {
+                spacer {
+                  width {
+                    linear_dimension {
+                      value: 24
+                    }
+                  }
+                  height {
+                    linear_dimension {
+                      value: 24
+                    }
+                  }
+                }
+              }
+              contents {
+                text {
+                  text {
+                    value: "DEF"
+                  }
+                  font_style {
+                    weight {
+                      value: FONT_WEIGHT_BOLD
+                    }
+                    size {
+                      value: 16
+                    }
+                    color {
+                      argb: 0xFFFFFFFF
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      contents {
+        spacer {
+          length {
+            value: 20
+          }
+        }
+      }
+      contents {
+        line {
+          color {
+            argb: 0xFF00FF00
+          }
+          length {
+            value: 10
+          }
+          thickness {
+            value: 60
+          }
+        }
+      }
+    }
+  }
+}
+
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_anchors.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_anchors.textproto
new file mode 100644
index 0000000..220ba5e
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_anchors.textproto
@@ -0,0 +1,140 @@
+box {
+  width {
+    expanded_dimension {}
+  }
+  height {
+    expanded_dimension {}
+  }
+  contents {
+    arc {
+      anchor_angle: {
+        value: 0
+      }
+      anchor_type {
+        value: ARC_ANCHOR_END
+      }
+      contents {
+        text {
+          text {
+            value: "ANCHOR_END - 0"
+          }
+          font_style {
+            weight {
+              value: FONT_WEIGHT_BOLD
+            }
+            size {
+              value: 16
+            }
+            color {
+              argb: 0xFFFF0000
+            }
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    arc {
+      anchor_angle: {
+        value: 0
+      }
+      anchor_type: {
+        value: ARC_ANCHOR_START
+      }
+      contents {
+        text {
+          text {
+            value: "ANCHOR_START - 0"
+          }
+          font_style {
+            weight {
+              value: FONT_WEIGHT_BOLD
+            }
+            size {
+              value: 16
+            }
+            color {
+              argb: 0xFFFF0000
+            }
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    arc {
+      anchor_angle: {
+        value: 180
+      }
+      anchor_type {
+        value: ARC_ANCHOR_CENTER
+      }
+      contents {
+        text {
+          text {
+            value: "ANCHOR_CENTER - 180"
+          }
+          font_style {
+            weight {
+              value: FONT_WEIGHT_BOLD
+            }
+            size {
+              value: 16
+            }
+            color {
+              argb: 0xFFFF0000
+            }
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    box {
+      modifiers {
+        padding {
+          start {
+            value: 30
+          }
+          end {
+            value: 30
+          }
+          top {
+            value: 30
+          }
+          bottom {
+            value: 30
+          }
+        }
+      }
+      contents {
+        arc {
+          anchor_angle: {
+            value: 0
+          }
+          contents {
+            text {
+              text {
+                value: "ANCHOR_DEFAULT - 0"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFF0000
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_text_and_lines.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_text_and_lines.textproto
new file mode 100644
index 0000000..e00b3e0
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_text_and_lines.textproto
@@ -0,0 +1,57 @@
+arc {
+  anchor_type: {
+    value: ARC_ANCHOR_CENTER
+  }
+  anchor_angle: {
+    value: 0
+  }
+  contents {
+    text {
+      text {
+        value: "HELLO"
+      }
+      font_style {
+        weight {
+          value: FONT_WEIGHT_BOLD
+        }
+        size {
+          value: 16
+        }
+        color {
+          argb: 0xFFFF0000
+        }
+      }
+    }
+  }
+  contents {
+    line {
+      color {
+        argb: 0xFF00FF00
+      }
+      length {
+        value: 45
+      }
+      thickness {
+        value: 11
+      }
+    }
+  }
+  contents {
+    text {
+      text {
+        value: "WORLD"
+      }
+      font_style {
+        weight {
+          value: FONT_WEIGHT_BOLD
+        }
+        size {
+          value: 16
+        }
+        color {
+          argb: 0xFF0000FF
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_with_buttons_rotated.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_with_buttons_rotated.textproto
new file mode 100644
index 0000000..69d7804
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_with_buttons_rotated.textproto
@@ -0,0 +1,374 @@
+arc {
+  anchor_angle: {
+    value: 0
+  }
+  anchor_type: {
+    value: ARC_ANCHOR_CENTER
+  }
+  contents {
+    adapter {
+      rotate_contents: {
+        value: true
+      }
+      content {
+        box {
+          horizontal_alignment {
+            value: HALIGN_CENTER
+          }
+          vertical_alignment {
+            value: VALIGN_CENTER
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFFFF0000
+              }
+              corner {
+                radius {
+                  value: 12
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              width {
+                linear_dimension {
+                  value: 24
+                }
+              }
+              height {
+                linear_dimension {
+                  value: 24
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "1"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFFFFFF
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    adapter {
+      rotate_contents: {
+        value: true
+      }
+      content {
+        box {
+          horizontal_alignment {
+            value: HALIGN_CENTER
+          }
+          vertical_alignment {
+            value: VALIGN_CENTER
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFF00FF00
+              }
+              corner {
+                radius {
+                  value: 12
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              width {
+                linear_dimension {
+                  value: 24
+                }
+              }
+              height {
+                linear_dimension {
+                  value: 24
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "2"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFFFFFF
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    adapter {
+      content {
+        box {
+          horizontal_alignment {
+            value: HALIGN_CENTER
+          }
+          vertical_alignment {
+            value: VALIGN_CENTER
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFF0000FF
+              }
+              corner {
+                radius {
+                  value: 12
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              width {
+                linear_dimension {
+                  value: 24
+                }
+              }
+              height {
+                linear_dimension {
+                  value: 24
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "3"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFFFFFF
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    adapter {
+      rotate_contents: {
+        value: true
+      }
+      content {
+        box {
+          horizontal_alignment {
+            value: HALIGN_CENTER
+          }
+          vertical_alignment {
+            value: VALIGN_CENTER
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFFFF00FF
+              }
+              corner {
+                radius {
+                  value: 12
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              width {
+                linear_dimension {
+                  value: 24
+                }
+              }
+              height {
+                linear_dimension {
+                  value: 24
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "4"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFFFFFF
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    adapter {
+      rotate_contents: {
+        value: true
+      }
+      content {
+        box {
+          horizontal_alignment {
+            value: HALIGN_CENTER
+          }
+          vertical_alignment {
+            value: VALIGN_CENTER
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFF00FFFF
+              }
+              corner {
+                radius {
+                  value: 12
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              width {
+                linear_dimension {
+                  value: 24
+                }
+              }
+              height {
+                linear_dimension {
+                  value: 24
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "5"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFFFFFF
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    adapter {
+      rotate_contents: {
+        value: true
+      }
+      content {
+        box {
+          horizontal_alignment {
+            value: HALIGN_CENTER
+          }
+          vertical_alignment {
+            value: VALIGN_CENTER
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFFFFFF00
+              }
+              corner {
+                radius {
+                  value: 12
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              width {
+                linear_dimension {
+                  value: 24
+                }
+              }
+              height {
+                linear_dimension {
+                  value: 24
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "6"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFFFFFF
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_with_buttons_unrotated.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_with_buttons_unrotated.textproto
new file mode 100644
index 0000000..d30ba9e
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/arc_with_buttons_unrotated.textproto
@@ -0,0 +1,360 @@
+arc {
+  anchor_angle: {
+    value: 0
+  }
+  anchor_type: {
+    value: ARC_ANCHOR_CENTER
+  }
+
+  contents {
+    adapter {
+      content {
+        box {
+          horizontal_alignment {
+            value: HALIGN_CENTER
+          }
+          vertical_alignment {
+            value: VALIGN_CENTER
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFFFF0000
+              }
+              corner {
+                radius {
+                  value: 12
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              width {
+                linear_dimension {
+                  value: 24
+                }
+              }
+              height {
+                linear_dimension {
+                  value: 24
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "1"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFFFFFF
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    adapter {
+      content {
+        box {
+          horizontal_alignment {
+            value: HALIGN_CENTER
+          }
+          vertical_alignment {
+            value: VALIGN_CENTER
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFF00FF00
+              }
+              corner {
+                radius {
+                  value: 12
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              width {
+                linear_dimension {
+                  value: 24
+                }
+              }
+              height {
+                linear_dimension {
+                  value: 24
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "2"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFFFFFF
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    adapter {
+      content {
+        box {
+          horizontal_alignment {
+            value: HALIGN_CENTER
+          }
+          vertical_alignment {
+            value: VALIGN_CENTER
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFF0000FF
+              }
+              corner {
+                radius {
+                  value: 12
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              width {
+                linear_dimension {
+                  value: 24
+                }
+              }
+              height {
+                linear_dimension {
+                  value: 24
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "3"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFFFFFF
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    adapter {
+      content {
+        box {
+          horizontal_alignment {
+            value: HALIGN_CENTER
+          }
+          vertical_alignment {
+            value: VALIGN_CENTER
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFFFF00FF
+              }
+              corner {
+                radius {
+                  value: 12
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              width {
+                linear_dimension {
+                  value: 24
+                }
+              }
+              height {
+                linear_dimension {
+                  value: 24
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "4"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFFFFFF
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    adapter {
+      content {
+        box {
+          horizontal_alignment {
+            value: HALIGN_CENTER
+          }
+          vertical_alignment {
+            value: VALIGN_CENTER
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFF00FFFF
+              }
+              corner {
+                radius {
+                  value: 12
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              width {
+                linear_dimension {
+                  value: 24
+                }
+              }
+              height {
+                linear_dimension {
+                  value: 24
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "5"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFFFFFF
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    adapter {
+      content {
+        box {
+          horizontal_alignment {
+            value: HALIGN_CENTER
+          }
+          vertical_alignment {
+            value: VALIGN_CENTER
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFFFFFF00
+              }
+              corner {
+                radius {
+                  value: 12
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              width {
+                linear_dimension {
+                  value: 24
+                }
+              }
+              height {
+                linear_dimension {
+                  value: 24
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "6"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFFFFFF
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/box_with_corners_and_border.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/box_with_corners_and_border.textproto
new file mode 100644
index 0000000..4011e59
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/box_with_corners_and_border.textproto
@@ -0,0 +1,43 @@
+box {
+  contents {
+    text {
+      text {
+        value: "Hello World"
+      }
+    }
+  }
+  modifiers {
+    background {
+      color {
+        argb: 0xFF00FF00
+      }
+      corner {
+        radius {
+          value: 5
+        }
+      }
+    }
+    padding {
+      end {
+        value: 10
+      }
+      top {
+        value: 20
+      }
+      bottom {
+        value: 30
+      }
+      start {
+        value: 40
+      }
+    }
+    border {
+      color {
+        argb: 0xFFFF0000
+      }
+      width {
+        value: 5
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/box_with_corners_and_border_rtlaware.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/box_with_corners_and_border_rtlaware.textproto
new file mode 100644
index 0000000..390e626
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/box_with_corners_and_border_rtlaware.textproto
@@ -0,0 +1,46 @@
+box {
+  contents {
+    text {
+      text {
+        value: "Hello World"
+      }
+    }
+  }
+  modifiers {
+    background {
+      color {
+        argb: 0xFF00FF00
+      }
+      corner {
+        radius {
+          value: 5
+        }
+      }
+    }
+    padding {
+      end {
+        value: 10
+      }
+      top {
+        value: 20
+      }
+      bottom {
+        value: 30
+      }
+      start {
+        value: 40
+      }
+      rtl_aware {
+        value: true
+      }
+    }
+    border {
+      color {
+        argb: 0xFFFF0000
+      }
+      width {
+        value: 5
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/box_with_fixed_size.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/box_with_fixed_size.textproto
new file mode 100644
index 0000000..bfaef0e
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/box_with_fixed_size.textproto
@@ -0,0 +1,35 @@
+box {
+  horizontal_alignment {
+    value: HALIGN_CENTER
+  }
+  vertical_alignment {
+    value: VALIGN_CENTER
+  }
+  width {
+    expanded_dimension {}
+  }
+  height {
+    expanded_dimension {}
+  }
+  contents {
+    box {
+      width {
+        linear_dimension {
+          value: 50
+        }
+      }
+      height {
+        linear_dimension {
+          value: 50
+        }
+      }
+      modifiers {
+        background {
+          color {
+            argb: 0xFFFF0000
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/broken_drawable.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/broken_drawable.textproto
new file mode 100644
index 0000000..a131617
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/broken_drawable.textproto
@@ -0,0 +1,46 @@
+# This is a bit of a weird Screenshot test; this won't have any output, but is needed
+# to ensure that the renderer doesn't crash with a broken image. Robolectric
+# does _not_ fail in the same way "real" Android does on invalid (or missing)
+# resources, so we're having to use layouts tests to test this case instead.
+#
+# Note the box is required though; the images should fail to inflate, so if this
+# layout only contained the image, then the renderer would just emit null and
+# the test harness would fail the test. Putting the box in ensures that the
+# renderer inflates _something_ to keep the rest of the harness happy.
+box {
+  contents {
+    image {
+      resource_id {
+        value: "broken_image"
+      }
+      width {
+        linear_dimension {
+          value: 16
+        }
+      }
+      height {
+        linear_dimension {
+          value: 16
+        }
+      }
+    }
+  }
+
+  contents {
+    image {
+      resource_id {
+        value: "missing_image"
+      }
+      width {
+        linear_dimension {
+          value: 16
+        }
+      }
+      height {
+        linear_dimension {
+          value: 16
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/column_with_alignment.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/column_with_alignment.textproto
new file mode 100644
index 0000000..1212653
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/column_with_alignment.textproto
@@ -0,0 +1,86 @@
+column {
+  contents {
+    column {
+      horizontal_alignment {
+        value: HALIGN_LEFT
+      }
+      contents {
+        text {
+          text {
+            value: "Align"
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "L"
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    column {
+      horizontal_alignment {
+        value: HALIGN_CENTER
+      }
+      contents {
+        text {
+          text {
+            value: "Align"
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "MID"
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    column {
+      horizontal_alignment {
+        value: HALIGN_RIGHT
+      }
+      contents {
+        text {
+          text {
+            value: "Align"
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "R"
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    column {
+      contents {
+        text {
+          text {
+            value: "Align undefined"
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "MID"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/column_with_alignment_rtlaware.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/column_with_alignment_rtlaware.textproto
new file mode 100644
index 0000000..1ba79d3
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/column_with_alignment_rtlaware.textproto
@@ -0,0 +1,86 @@
+column {
+  contents {
+    column {
+      horizontal_alignment {
+        value: HALIGN_START
+      }
+      contents {
+        text {
+          text {
+            value: "Align"
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "L"
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    column {
+      horizontal_alignment {
+        value: HALIGN_CENTER
+      }
+      contents {
+        text {
+          text {
+            value: "Align"
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "MID"
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    column {
+      horizontal_alignment {
+        value: HALIGN_END
+      }
+      contents {
+        text {
+          text {
+            value: "Align"
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "R"
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    column {
+      contents {
+        text {
+          text {
+            value: "Align undefined"
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "MID"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/column_with_height.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/column_with_height.textproto
new file mode 100644
index 0000000..8167667
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/column_with_height.textproto
@@ -0,0 +1,47 @@
+# This is a bit of a contrived example.
+# Add a column with minimal contents into a box, and align the box contents to
+# the bottom. If the column didn't have a height, it would just wrap its
+# contents and draw them at the bottom of the box. If the column has a height
+# then it will start placing elements from the top of the column, hence the
+# contents will be inset from the bottom of the parent box.
+box {
+  width {
+    expanded_dimension {}
+  }
+  height {
+    expanded_dimension {}
+  }
+  vertical_alignment {
+    value: VALIGN_BOTTOM
+  }
+  modifiers {
+    background {
+      color {
+        argb: 0xFFFF0000
+      }
+    }
+  }
+  contents {
+    column {
+      height {
+        linear_dimension {
+          value: 100
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "Hi"
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "World"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/expanded_box_horizontal.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/expanded_box_horizontal.textproto
new file mode 100644
index 0000000..fce3d41
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/expanded_box_horizontal.textproto
@@ -0,0 +1,45 @@
+# Check that a box that is expanded does so correctly
+# Use a box at the top level.
+#
+# This is a pretty common paradigm; tiles will use boxes at the top level to
+# allow the positioning of multiple elements without them affecting the
+# placement of each other. If this is done incorrectly though, it can lead to
+# the inner box not expanding properly.
+box {
+  horizontal_alignment {
+    value: HALIGN_CENTER
+  }
+  vertical_alignment {
+    value: VALIGN_CENTER
+  }
+  width {
+    expanded_dimension {}
+  }
+  height {
+    expanded_dimension {}
+  }
+  contents {
+    box {
+      horizontal_alignment {
+        value: HALIGN_START
+      }
+      modifiers {
+        background {
+          color {
+            argb: 0xFFFF0000
+          }
+        }
+      }
+      width {
+        expanded_dimension {}
+      }
+      contents {
+        text {
+          text {
+            value: "Hello World"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/expanded_box_horizontal_right_align.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/expanded_box_horizontal_right_align.textproto
new file mode 100644
index 0000000..5ba5696
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/expanded_box_horizontal_right_align.textproto
@@ -0,0 +1,31 @@
+# Check that a box's width will be set even when its style is not set.
+# See b/165807783
+box {
+  width {
+    expanded_dimension {}
+  }
+  contents {
+    box {
+      horizontal_alignment {
+        value: HALIGN_END
+      }
+      modifiers {
+        background {
+          color {
+            argb: 0xFFFF0000
+          }
+        }
+      }
+      width {
+        expanded_dimension {}
+      }
+      contents {
+        text {
+          text {
+            value: "Right-Aligned Text"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/expanded_box_vertical.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/expanded_box_vertical.textproto
new file mode 100644
index 0000000..44b4e02
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/expanded_box_vertical.textproto
@@ -0,0 +1,45 @@
+# Check that a box that is expanded does so correctly
+# Use a box at the top level.
+#
+# This is a pretty common paradigm; tiles will use boxes at the top level to
+# allow the positioning of multiple elements without them affecting the
+# placement of each other. If this is done incorrectly though, it can lead to
+# the inner box not expanding properly.
+box {
+  horizontal_alignment {
+    value: HALIGN_CENTER
+  }
+  vertical_alignment {
+    value: VALIGN_CENTER
+  }
+  width {
+    expanded_dimension {}
+  }
+  height {
+    expanded_dimension {}
+  }
+  contents {
+    box {
+      vertical_alignment {
+        value: VALIGN_TOP
+      }
+      modifiers {
+        background {
+          color {
+            argb: 0xFFFF0000
+          }
+        }
+      }
+      height {
+        expanded_dimension {}
+      }
+      contents {
+        text {
+          text {
+            value: "Hello World"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/expanded_children_in_row.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/expanded_children_in_row.textproto
new file mode 100644
index 0000000..aac4eaf
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/expanded_children_in_row.textproto
@@ -0,0 +1,178 @@
+column {
+  width {
+    expanded_dimension {}
+  }
+  height {
+    expanded_dimension {}
+  }
+
+  # A row that will not be displayed because it's set to wrap (by default), and
+  # all its children are set to expand, so it's undefined how to display it.
+  contents {
+    row {
+      contents {
+        box {
+          width {
+            expanded_dimension {}
+          }
+          height {
+            linear_dimension {
+              value: 20
+            }
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFFFF0000
+              }
+            }
+          }
+        }
+      }
+
+      contents {
+        box {
+          width {
+            expanded_dimension {}
+          }
+          height {
+            linear_dimension {
+              value: 20
+            }
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFF00FF00
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "Should not be displayed"
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    spacer {
+      height {
+        linear_dimension {
+          value: 10
+        }
+      }
+    }
+  }
+
+  # A row with expand = true
+  contents {
+    row {
+      width {
+        expanded_dimension {}
+      }
+      contents {
+        box {
+          width {
+            expanded_dimension {}
+          }
+          height {
+            linear_dimension {
+              value: 20
+            }
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFFFF0000
+              }
+            }
+          }
+        }
+      }
+
+      contents {
+        box {
+          width {
+            expanded_dimension {}
+          }
+          height {
+            linear_dimension {
+              value: 20
+            }
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFF00FF00
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    spacer {
+      height {
+        linear_dimension {
+          value: 10
+        }
+      }
+    }
+  }
+
+  # A row with a known width
+  contents {
+    row {
+      width {
+        linear_dimension {
+          value: 100
+        }
+      }
+      contents {
+        box {
+          width {
+            expanded_dimension {}
+          }
+          height {
+            linear_dimension {
+              value: 20
+            }
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFFFF0000
+              }
+            }
+          }
+        }
+      }
+      contents {
+        box {
+          width {
+            expanded_dimension {}
+          }
+          height {
+            linear_dimension {
+              value: 20
+            }
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFF00FF00
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/font_weights_in_arc.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/font_weights_in_arc.textproto
new file mode 100644
index 0000000..e0d399f
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/font_weights_in_arc.textproto
@@ -0,0 +1,32 @@
+arc {
+  contents {
+    text {
+      font_style {
+        weight {
+          value: FONT_WEIGHT_NORMAL
+        }
+        color {
+          argb: 0xFFFF0000
+        }
+      }
+      text {
+        value: "Normal"
+      }
+    }
+  }
+  contents {
+    text {
+      font_style {
+        weight {
+          value: FONT_WEIGHT_BOLD
+        }
+        color {
+          argb: 0xFFFF0000
+        }
+      }
+      text {
+        value: "Bold"
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/font_weights_in_spannable.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/font_weights_in_spannable.textproto
new file mode 100644
index 0000000..d5aa3bc
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/font_weights_in_spannable.textproto
@@ -0,0 +1,41 @@
+spannable {
+  max_lines {
+    value: 5
+  }
+  multiline_alignment {
+    value: HALIGN_START
+  }
+  line_spacing {
+    value: 20
+  }
+  spans {
+    text {
+      font_style {
+        weight {
+          value: FONT_WEIGHT_NORMAL
+        }
+        color {
+          argb: 0xFFFF0000
+        }
+      }
+      text {
+        value: "Normal "
+      }
+    }
+  }
+  spans {
+    text {
+      font_style {
+        weight {
+          value: FONT_WEIGHT_BOLD
+        }
+        color {
+          argb: 0xFFFF0000
+        }
+      }
+      text {
+        value: "Bold"
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/image_expand_modes.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_expand_modes.textproto
new file mode 100644
index 0000000..53933eb
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_expand_modes.textproto
@@ -0,0 +1,128 @@
+column {
+  contents {
+    text {
+      text {
+        value: "Fit"
+      }
+    }
+  }
+  contents {
+    box {
+      modifiers {
+        border {
+          width {
+            value: 1
+          }
+          color {
+            argb: 0xFFFF0000
+          }
+        }
+      }
+      contents {
+        image {
+          width {
+            linear_dimension {
+              value: 48
+            }
+          }
+          height {
+            linear_dimension {
+              value: 24
+            }
+          }
+          resource_id {
+            value: "android_withbg_120dp"
+          }
+          content_scale_mode {
+            value: CONTENT_SCALE_MODE_FIT
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    text {
+      text {
+        value: "Crop"
+      }
+    }
+  }
+
+  contents {
+    box {
+      modifiers {
+        border {
+          width {
+            value: 1
+          }
+          color {
+            argb: 0xFFFF0000
+          }
+        }
+      }
+      contents {
+        image {
+          width {
+            linear_dimension {
+              value: 48
+            }
+          }
+          height {
+            linear_dimension {
+              value: 24
+            }
+          }
+          resource_id {
+            value: "android_withbg_120dp"
+          }
+          content_scale_mode {
+            value: CONTENT_SCALE_MODE_CROP
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    text {
+      text {
+        value: "FillBounds"
+      }
+    }
+  }
+  contents {
+    box {
+      modifiers {
+        border {
+          width {
+            value: 1
+          }
+          color {
+            argb: 0xFFFF0000
+          }
+        }
+      }
+      contents {
+        image {
+          width {
+            linear_dimension {
+              value: 48
+            }
+          }
+          height {
+            linear_dimension {
+              value: 24
+            }
+          }
+          resource_id {
+            value: "android_withbg_120dp"
+          }
+          content_scale_mode {
+            value: CONTENT_SCALE_MODE_FILL_BOUNDS
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/image_expanded_to_parent.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_expanded_to_parent.textproto
new file mode 100644
index 0000000..3cc85e7
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_expanded_to_parent.textproto
@@ -0,0 +1,28 @@
+box {
+  width {
+    expanded_dimension {}
+  }
+  height {
+    expanded_dimension {}
+  }
+  modifiers {
+    padding {
+      top {
+        value: 50
+      }
+    }
+  }
+  contents {
+    image {
+      resource_id {
+        value: "android_withbg_120dp"
+      }
+      width {
+        expanded_dimension {}
+      }
+      height {
+        expanded_dimension {}
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/image_oversized_in_box.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_oversized_in_box.textproto
new file mode 100644
index 0000000..2bbb125
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_oversized_in_box.textproto
@@ -0,0 +1,142 @@
+column {
+  width {
+    expanded_dimension {}
+  }
+  horizontal_alignment {
+    value: HALIGN_CENTER
+  }
+  contents {
+    box {
+      modifiers {
+        border {
+          width {
+            value: 1
+          }
+          color {
+            argb: 0xFFFF0000
+          }
+        }
+      }
+      horizontal_alignment {
+        value: HALIGN_START
+      }
+      width {
+        linear_dimension {
+          value: 24
+        }
+      }
+      height {
+        linear_dimension {
+          value: 48
+        }
+      }
+      contents {
+        image {
+          resource_id {
+            value: "android_withbg_120dp"
+          }
+          width {
+            linear_dimension {
+              value: 48
+            }
+          }
+          height {
+            linear_dimension {
+              value: 48
+            }
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    box {
+      modifiers {
+        border {
+          width {
+            value: 1
+          }
+          color {
+            argb: 0xFFFFFF00
+          }
+        }
+      }
+      horizontal_alignment {
+        value: HALIGN_CENTER
+      }
+      width {
+        linear_dimension {
+          value: 24
+        }
+      }
+      height {
+        linear_dimension {
+          value: 48
+        }
+      }
+      contents {
+        image {
+          resource_id {
+            value: "android_withbg_120dp"
+          }
+          width {
+            linear_dimension {
+              value: 48
+            }
+          }
+          height {
+            linear_dimension {
+              value: 48
+            }
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    box {
+      modifiers {
+        border {
+          width {
+            value: 1
+          }
+          color {
+            argb: 0xFF0000FF
+          }
+        }
+      }
+      horizontal_alignment {
+        value: HALIGN_END
+      }
+      width {
+        linear_dimension {
+          value: 24
+        }
+      }
+      height {
+        linear_dimension {
+          value: 48
+        }
+      }
+      contents {
+        image {
+          resource_id {
+            value: "android_withbg_120dp"
+          }
+          width {
+            linear_dimension {
+              value: 48
+            }
+          }
+          height {
+            linear_dimension {
+              value: 48
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/image_oversized_in_box_proportional.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_oversized_in_box_proportional.textproto
new file mode 100644
index 0000000..e84fb02
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_oversized_in_box_proportional.textproto
@@ -0,0 +1,145 @@
+column {
+  width {
+    expanded_dimension {}
+  }
+  horizontal_alignment {
+    value: HALIGN_CENTER
+  }
+  contents {
+    box {
+      modifiers {
+        border {
+          width {
+            value: 1
+          }
+          color {
+            argb: 0xFFFF0000
+          }
+        }
+      }
+      horizontal_alignment {
+        value: HALIGN_START
+      }
+      width {
+        linear_dimension {
+          value: 24
+        }
+      }
+      height {
+        linear_dimension {
+          value: 48
+        }
+      }
+      contents {
+        image {
+          resource_id {
+            value: "android_withbg_120dp"
+          }
+          width {
+            proportional_dimension {
+              aspect_ratio_width: 1
+              aspect_ratio_height: 1
+            }
+          }
+          height {
+            linear_dimension {
+              value: 48
+            }
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    box {
+      modifiers {
+        border {
+          width {
+            value: 1
+          }
+          color {
+            argb: 0xFFFFFF00
+          }
+        }
+      }
+      horizontal_alignment {
+        value: HALIGN_CENTER
+      }
+      width {
+        linear_dimension {
+          value: 24
+        }
+      }
+      height {
+        linear_dimension {
+          value: 48
+        }
+      }
+      contents {
+        image {
+          resource_id {
+            value: "android_withbg_120dp"
+          }
+          width {
+            proportional_dimension {
+              aspect_ratio_width: 1
+              aspect_ratio_height: 1
+            }
+          }
+          height {
+            linear_dimension {
+              value: 48
+            }
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    box {
+      modifiers {
+        border {
+          width {
+            value: 1
+          }
+          color {
+            argb: 0xFF0000FF
+          }
+        }
+      }
+      horizontal_alignment {
+        value: HALIGN_END
+      }
+      width {
+        linear_dimension {
+          value: 24
+        }
+      }
+      height {
+        linear_dimension {
+          value: 48
+        }
+      }
+      contents {
+        image {
+          resource_id {
+            value: "android_withbg_120dp"
+          }
+          width {
+            proportional_dimension {
+              aspect_ratio_width: 1
+              aspect_ratio_height: 1
+            }
+          }
+          height {
+            linear_dimension {
+              value: 48
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/image_proportional_resize.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_proportional_resize.textproto
new file mode 100644
index 0000000..394d1f3
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_proportional_resize.textproto
@@ -0,0 +1,30 @@
+box {
+  # Add a green background, so we can tell whether the image "box" is resizing
+  # properly.
+  modifiers {
+    background {
+      color {
+        argb: 0xFF00FF00
+      }
+    }
+  }
+  width {
+    expanded_dimension {}
+  }
+  contents {
+    image {
+      width {
+        expanded_dimension {}
+      }
+      height {
+        proportional_dimension {
+          aspect_ratio_width: 2
+          aspect_ratio_height: 1
+        }
+      }
+      resource_id {
+        value: "android"
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/image_with_dimensions.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_with_dimensions.textproto
new file mode 100644
index 0000000..d017f08
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_with_dimensions.textproto
@@ -0,0 +1,15 @@
+image {
+  resource_id {
+    value: "android"
+  }
+  width {
+    linear_dimension {
+      value: 20
+    }
+  }
+  height {
+    linear_dimension {
+      value: 15
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/image_with_inline_data.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_with_inline_data.textproto
new file mode 100644
index 0000000..1daac1c
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_with_inline_data.textproto
@@ -0,0 +1,15 @@
+image {
+  resource_id {
+    value: "inline"
+  }
+  width {
+    linear_dimension {
+      value: 16
+    }
+  }
+  height {
+    linear_dimension {
+      value: 16
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/image_with_padding.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_with_padding.textproto
new file mode 100644
index 0000000..f201acb
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/image_with_padding.textproto
@@ -0,0 +1,44 @@
+image {
+  resource_id {
+    value: "android"
+  }
+  width {
+    linear_dimension {
+      value: 52
+    }
+  }
+  height {
+    linear_dimension {
+      value: 52
+    }
+  }
+  content_scale_mode {
+    value: CONTENT_SCALE_MODE_FILL_BOUNDS
+  }
+  modifiers {
+    background {
+      color {
+        argb: 0xFFFF0000
+      }
+      corner {
+        radius {
+          value: 100
+        }
+      }
+    }
+    padding {
+      start {
+        value: 16
+      }
+      end {
+        value: 16
+      }
+      top {
+        value: 16
+      }
+      bottom {
+        value: 16
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/line_in_arc.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/line_in_arc.textproto
new file mode 100644
index 0000000..60d5d53
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/line_in_arc.textproto
@@ -0,0 +1,21 @@
+arc {
+  anchor_angle: {
+    value: 0
+  }
+  anchor_type: {
+    value: ARC_ANCHOR_START
+  }
+  contents {
+    line {
+      length {
+        value: 100
+      }
+      thickness {
+        value: 10
+      }
+      color {
+        argb: 0xFFFF0000
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/line_multi_height.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/line_multi_height.textproto
new file mode 100644
index 0000000..2d0df13
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/line_multi_height.textproto
@@ -0,0 +1,269 @@
+column {
+  contents {
+    spacer {
+      width {
+        linear_dimension {
+          value: 100
+        }
+      }
+      height {
+        linear_dimension {
+          value: 10
+        }
+      }
+      modifiers {
+        background {
+          color {
+            argb: 0xFFFF0000
+          }
+          corner {
+            radius {
+              value: 5
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    spacer {
+      width {
+        linear_dimension {
+          value: 100
+        }
+      }
+      height {
+        linear_dimension {
+          value: 20
+        }
+      }
+      modifiers {
+        background {
+          color {
+            argb: 0xFF00FF00
+          }
+        }
+      }
+    }
+  }
+  contents {
+    spacer {
+      width {
+        linear_dimension {
+          value: 100
+        }
+      }
+      height {
+        linear_dimension {
+          value: 40
+        }
+      }
+      modifiers {
+        background {
+          color {
+            argb: 0xFFFFFF00
+          }
+          corner {
+            radius {
+              value: 20
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    spacer {
+      width {
+        linear_dimension {
+          value: 100
+        }
+      }
+      height {
+        linear_dimension {
+          value: 50
+        }
+      }
+      modifiers {
+        background {
+          color {
+            argb: 0xFF00FFFF
+          }
+          corner {
+            radius {
+              value: 25
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    box {
+      modifiers {
+        background {
+          color {
+            argb: 0xFFFFFF00
+          }
+        }
+      }
+      contents {
+        row {
+          contents {
+            text {
+              text {
+                value: "0-length line ->"
+              }
+              font_style {
+                size {
+                  value: 14
+                }
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                color {
+                  argb: 0xFF000000
+                }
+              }
+            }
+          }
+          contents {
+            # Spacer with no length but a thickness of 40dp.
+            spacer {
+              height {
+                linear_dimension {
+                  value: 40
+                }
+              }
+              modifiers {
+                background {
+                  color {
+                    argb: 0xFF000000
+                  }
+                  corner {
+                    radius {
+                      value: 20
+                    }
+                  }
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "<-"
+              }
+              font_style {
+                size {
+                  value: 14
+                }
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                color {
+                  argb: 0xFF000000
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    box {
+      modifiers {
+        background {
+          color {
+            argb: 0xFF00FF00
+          }
+        }
+      }
+      contents {
+        column {
+          horizontal_alignment {
+            value: HALIGN_START
+          }
+          contents {
+            text {
+              text {
+                value: "v 0-thickness line"
+              }
+              font_style {
+                size {
+                  value: 14
+                }
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                color {
+                  argb: 0xFF000000
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              # Spacer with no thickness but a length of 160dp.
+              width {
+                linear_dimension {
+                  value: 160
+                }
+              }
+              modifiers {
+                background {
+                  color {
+                    argb: 0xFF000000
+                  }
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "^"
+              }
+              font_style {
+                size {
+                  value: 14
+                }
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                color {
+                  argb: 0xFF000000
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    box {
+      modifiers {
+        background {
+          color {
+            argb: 0xFF0000FF
+          }
+        }
+      }
+      contents {
+        spacer {
+          # Spacer with no dimensions. Neither the spacer nor the blue container
+          # around it should be visible.
+          modifiers {
+            background {
+              color {
+                argb: 0xFF000000
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/long_text.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/long_text.textproto
new file mode 100644
index 0000000..9bb03b7
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/long_text.textproto
@@ -0,0 +1,84 @@
+box {
+  width {
+    linear_dimension {
+      value: 100
+    }
+  }
+  height {
+    wrapped_dimension {}
+  }
+
+  # Add a background color so it's obvious what the bounds of the text is.
+  modifiers {
+    background {
+      color {
+        argb: 0xFFFFFFFF
+      }
+    }
+  }
+
+  contents {
+    column {
+      contents {
+        text {
+          text {
+            value: "This is a really long string which really should be truncated when it's rendered in a really little container."
+          }
+          font_style {
+            color {
+              argb: 0xFF00FF00
+            }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "This is a really long string which really should be truncated when it's rendered in a really little container."
+          }
+          overflow {
+            value: TEXT_OVERFLOW_TRUNCATE
+          }
+          font_style {
+            color {
+              argb: 0xFF000000
+            }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "This is a really long string which really should be ellipsized when it's rendered in a really little container."
+          }
+          overflow {
+            value: TEXT_OVERFLOW_ELLIPSIZE_END
+          }
+          font_style {
+            color {
+              argb: 0xFFFF0000
+            }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "This is a really long string which really should be truncated when it's rendered in a really little container."
+          }
+          max_lines: {
+            value: 2
+          }
+          overflow {
+            value: TEXT_OVERFLOW_ELLIPSIZE_END
+          }
+          font_style {
+            color {
+              argb: 0xFF0000FF
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/multi_line_text_alignment.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/multi_line_text_alignment.textproto
new file mode 100644
index 0000000..1c3bc0d
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/multi_line_text_alignment.textproto
@@ -0,0 +1,111 @@
+column {
+  contents {
+    spannable {
+      multiline_alignment {
+        value: HALIGN_START
+      }
+      max_lines: {
+        value: 5
+      }
+      spans {
+        text {
+          text {
+            value: "This should be a multi-line bit of text that should be left-aligned"
+          }
+          font_style {
+            weight {
+              value: FONT_WEIGHT_BOLD
+            }
+            size {
+              value: 16
+            }
+            color {
+              argb: 0xFFFF0000
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    spannable {
+      multiline_alignment {
+        value: HALIGN_CENTER
+      }
+      max_lines: {
+        value: 5
+      }
+      spans {
+        text {
+          text {
+            value: "This should be a multi-line bit of text that should be center-aligned"
+          }
+          font_style {
+            weight {
+              value: FONT_WEIGHT_BOLD
+            }
+            size {
+              value: 16
+            }
+            color {
+              argb: 0xFF00FF00
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    spannable {
+      multiline_alignment {
+        value: HALIGN_END
+      }
+      max_lines: {
+        value: 5
+      }
+      spans {
+        text {
+          text {
+            value: "This should be a multi-line bit of text that should be right-aligned"
+          }
+          font_style {
+            weight {
+              value: FONT_WEIGHT_BOLD
+            }
+            size {
+              value: 16
+            }
+            color {
+              argb: 0xFF0000FF
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    spannable {
+      max_lines: {
+        value: 5
+      }
+      spans {
+        text {
+          text {
+            value: "Multi-line with no alignment. Should be center-aligned"
+          }
+          font_style {
+            weight {
+              value: FONT_WEIGHT_BOLD
+            }
+            size {
+              value: 16
+            }
+            color {
+              argb: 0xFFFF0000
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/row_column_space_test.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/row_column_space_test.textproto
new file mode 100644
index 0000000..3bf6e9e
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/row_column_space_test.textproto
@@ -0,0 +1,230 @@
+row {
+  contents {
+    column {
+      contents {
+        image {
+          modifiers {
+            background {
+              color {
+                argb: 0xFFFF0000
+              }
+            }
+          }
+          resource_id {
+            value: "android"
+          }
+          width {
+            linear_dimension {
+              value: 20
+            }
+          }
+          height {
+            linear_dimension {
+              value: 15
+            }
+          }
+        }
+      }
+      contents {
+        image {
+          modifiers {
+            background {
+              color {
+                argb: 0xFF00FF00
+              }
+            }
+          }
+          resource_id {
+            value: "android"
+          }
+          width {
+            linear_dimension {
+              value: 20
+            }
+          }
+          height {
+            linear_dimension {
+              value: 15
+            }
+          }
+        }
+      }
+      contents {
+        image {
+          modifiers {
+            background {
+              color {
+                argb: 0xFF0000FF
+              }
+            }
+          }
+          resource_id {
+            value: "android"
+          }
+          width {
+            linear_dimension {
+              value: 20
+            }
+          }
+          height {
+            linear_dimension {
+              value: 15
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    column {
+      contents {
+        image {
+          modifiers {
+            background {
+              color {
+                argb: 0xFF00FF00
+              }
+            }
+          }
+          resource_id {
+            value: "android"
+          }
+          width {
+            linear_dimension {
+              value: 20
+            }
+          }
+          height {
+            linear_dimension {
+              value: 15
+            }
+          }
+        }
+      }
+      contents {
+        image {
+          modifiers {
+            background {
+              color {
+                argb: 0xFF0000FF
+              }
+            }
+          }
+          resource_id {
+            value: "android"
+          }
+          width {
+            linear_dimension {
+              value: 20
+            }
+          }
+          height {
+            linear_dimension {
+              value: 15
+            }
+          }
+        }
+      }
+      contents {
+        image {
+          modifiers {
+            background {
+              color {
+                argb: 0xFFFF0000
+              }
+            }
+          }
+          resource_id {
+            value: "android"
+          }
+          width {
+            linear_dimension {
+              value: 20
+            }
+          }
+          height {
+            linear_dimension {
+              value: 15
+            }
+          }
+        }
+      }
+    }
+  }
+  contents {
+    column {
+      contents {
+        image {
+          modifiers {
+            background {
+              color {
+                argb: 0xFF0000FF
+              }
+            }
+          }
+          resource_id {
+            value: "android"
+          }
+          width {
+            linear_dimension {
+              value: 20
+            }
+          }
+          height {
+            linear_dimension {
+              value: 15
+            }
+          }
+        }
+      }
+      contents {
+        image {
+          modifiers {
+            background {
+              color {
+                argb: 0xFFFF0000
+              }
+            }
+          }
+          resource_id {
+            value: "android"
+          }
+          width {
+            linear_dimension {
+              value: 20
+            }
+          }
+          height {
+            linear_dimension {
+              value: 15
+            }
+          }
+        }
+      }
+      contents {
+        image {
+          modifiers {
+            background {
+              color {
+                argb: 0xFF00FF00
+              }
+            }
+          }
+          resource_id {
+            value: "android"
+          }
+          width {
+            linear_dimension {
+              value: 20
+            }
+          }
+          height {
+            linear_dimension {
+              value: 15
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/row_with_alignment.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/row_with_alignment.textproto
new file mode 100644
index 0000000..777566b
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/row_with_alignment.textproto
@@ -0,0 +1,126 @@
+column {
+  contents {
+    row {
+      vertical_alignment {
+        value: VALIGN_TOP
+      }
+      contents {
+        image {
+          resource_id {
+            value: "android"
+          }
+          width {
+            linear_dimension {
+              value: 45
+            }
+          }
+          height {
+            linear_dimension {
+              value: 45
+            }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "T"
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    row {
+      vertical_alignment {
+        value: VALIGN_CENTER
+      }
+      contents {
+        image {
+          resource_id {
+            value: "android"
+          }
+          width {
+            linear_dimension {
+              value: 45
+            }
+          }
+          height {
+            linear_dimension {
+              value: 45
+            }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "MID"
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    row {
+      vertical_alignment {
+        value: VALIGN_BOTTOM
+      }
+      contents {
+        image {
+          resource_id {
+            value: "android"
+          }
+          width {
+            linear_dimension {
+              value: 45
+            }
+          }
+          height {
+            linear_dimension {
+              value: 45
+            }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "B"
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    row {
+      contents {
+        image {
+          resource_id {
+            value: "android"
+          }
+          width {
+            linear_dimension {
+              value: 45
+            }
+          }
+          height {
+            linear_dimension {
+              value: 45
+            }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "Default (MID)"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/row_with_width.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/row_with_width.textproto
new file mode 100644
index 0000000..626b2a5
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/row_with_width.textproto
@@ -0,0 +1,47 @@
+# This is a bit of a contrived example.
+# Add a row with minimal contents into a box, and align the box contents to the
+# right. If the row didn't have a width, it would just wrap its contents and
+# draw them at the right of the box. If the row has a width then it will start
+# placing elements from the left of the row, hence the contents will be inset
+# from the right hand side of the parent box.
+box {
+  width {
+    expanded_dimension {}
+  }
+  height {
+    expanded_dimension {}
+  }
+  horizontal_alignment {
+    value: HALIGN_END
+  }
+  modifiers {
+    background {
+      color {
+        argb: 0xFFFF0000
+      }
+    }
+  }
+  contents {
+    row {
+      width {
+        linear_dimension {
+          value: 100
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "Hi"
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "World"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/simple_text.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/simple_text.textproto
new file mode 100644
index 0000000..4cd98d5
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/simple_text.textproto
@@ -0,0 +1,5 @@
+text {
+  text {
+    value: "Hello World"
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/single_line_text_alignment.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/single_line_text_alignment.textproto
new file mode 100644
index 0000000..c30f051
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/single_line_text_alignment.textproto
@@ -0,0 +1,65 @@
+column {
+  contents {
+    text {
+      text {
+        value: "Single-line text"
+      }
+      font_style {
+        weight {
+          value: FONT_WEIGHT_BOLD
+        }
+        size {
+          value: 16
+        }
+        color {
+          argb: 0xFFFF0000
+        }
+      }
+      multiline_alignment {
+        value: TEXT_ALIGN_START
+      }
+    }
+  }
+  contents {
+    text {
+      text {
+        value: "Single-line text"
+      }
+      font_style {
+        weight {
+          value: FONT_WEIGHT_BOLD
+        }
+        size {
+          value: 16
+        }
+        color {
+          argb: 0xFF00FF00
+        }
+      }
+      multiline_alignment {
+        value: TEXT_ALIGN_CENTER
+      }
+    }
+  }
+  contents {
+    text {
+      text {
+        value: "Single-line text"
+      }
+      font_style {
+        weight {
+          value: FONT_WEIGHT_BOLD
+        }
+        size {
+          value: 16
+        }
+        color {
+          argb: 0xFF0000FF
+        }
+      }
+      multiline_alignment {
+        value: TEXT_ALIGN_END
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/spacer_horizontal.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/spacer_horizontal.textproto
new file mode 100644
index 0000000..fa8dc2c
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/spacer_horizontal.textproto
@@ -0,0 +1,89 @@
+row {
+  contents {
+    text {
+      text {
+        value: "This"
+      }
+      font_style {
+        color {
+          argb: 0xFFFF0000
+        }
+      }
+      max_lines: {
+        value: 1000
+      }
+    }
+  }
+  contents {
+    spacer {
+      width {
+        linear_dimension {
+          value: 10
+        }
+      }
+    }
+  }
+  contents {
+    text {
+      text {
+        value: "Is"
+      }
+      font_style {
+        color {
+          argb: 0xFF00FF00
+        }
+      }
+      max_lines: {
+        value: 1000
+      }
+    }
+  }
+  contents {
+    spacer {
+      width {
+        linear_dimension {
+          value: 20
+        }
+      }
+    }
+  }
+  contents {
+    text {
+      text {
+        value: "A"
+      }
+      font_style {
+        color {
+          argb: 0xFF0000FF
+        }
+      }
+      max_lines: {
+        value: 1000
+      }
+    }
+  }
+  contents {
+    spacer {
+      width {
+        linear_dimension {
+          value: 30
+        }
+      }
+    }
+  }
+  contents {
+    text {
+      text {
+        value: "Test"
+      }
+      font_style {
+        color {
+          argb: 0xFF00FFFF
+        }
+      }
+      max_lines: {
+        value: 1000
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/spacer_in_arc.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/spacer_in_arc.textproto
new file mode 100644
index 0000000..b4477b7
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/spacer_in_arc.textproto
@@ -0,0 +1,219 @@
+arc {
+  anchor_angle: {
+    value: 0
+  }
+  anchor_type: {
+    value: ARC_ANCHOR_START
+  }
+
+  contents {
+    spacer {
+      length {
+        value: 90
+      }
+    }
+  }
+
+  contents {
+    adapter {
+      rotate_contents {
+        value: true
+      }
+      content {
+        box {
+          horizontal_alignment {
+            value: HALIGN_CENTER
+          }
+          vertical_alignment {
+            value: VALIGN_CENTER
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFFFF0000
+              }
+              corner {
+                radius {
+                  value: 12
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              width {
+                linear_dimension {
+                  value: 24
+                }
+              }
+              height {
+                linear_dimension {
+                  value: 24
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "1"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFFFFFF
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    spacer {
+      length {
+        value: 10
+      }
+    }
+  }
+
+  contents {
+    adapter {
+      rotate_contents {
+        value: true
+      }
+      content {
+        box {
+          horizontal_alignment {
+            value: HALIGN_CENTER
+          }
+          vertical_alignment {
+            value: VALIGN_CENTER
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFF00FF00
+              }
+              corner {
+                radius {
+                  value: 12
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              width {
+                linear_dimension {
+                  value: 24
+                }
+              }
+              height {
+                linear_dimension {
+                  value: 24
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "2"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFFFFFF
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  contents {
+    spacer {
+      length {
+        value: 30
+      }
+    }
+  }
+
+  contents {
+    adapter {
+      rotate_contents {
+        value: true
+      }
+      content {
+        box {
+          horizontal_alignment {
+            value: HALIGN_CENTER
+          }
+          vertical_alignment {
+            value: VALIGN_CENTER
+          }
+          modifiers {
+            background {
+              color {
+                argb: 0xFF0000FF
+              }
+              corner {
+                radius {
+                  value: 12
+                }
+              }
+            }
+          }
+          contents {
+            spacer {
+              width {
+                linear_dimension {
+                  value: 24
+                }
+              }
+              height {
+                linear_dimension {
+                  value: 24
+                }
+              }
+            }
+          }
+          contents {
+            text {
+              text {
+                value: "3"
+              }
+              font_style {
+                weight {
+                  value: FONT_WEIGHT_BOLD
+                }
+                size {
+                  value: 16
+                }
+                color {
+                  argb: 0xFFFFFFFF
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/spacer_vertical.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/spacer_vertical.textproto
new file mode 100644
index 0000000..c196cc8
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/spacer_vertical.textproto
@@ -0,0 +1,65 @@
+column {
+  contents {
+    text {
+      text {
+        value: "Hello World"
+      }
+      font_style {
+        color {
+          argb: 0xFFFF0000
+        }
+      }
+      max_lines: {
+        value: 1000
+      }
+    }
+  }
+  contents {
+    spacer {
+      height {
+        linear_dimension {
+          value: 10
+        }
+      }
+    }
+  }
+  contents {
+    text {
+      text {
+        value: "More text"
+      }
+      font_style {
+        color {
+          argb: 0xFF00FF00
+        }
+      }
+      max_lines: {
+        value: 1000
+      }
+    }
+  }
+  contents {
+    spacer {
+      height {
+        linear_dimension {
+          value: 30
+        }
+      }
+    }
+  }
+  contents {
+    text {
+      text {
+        value: "Yet more text"
+      }
+      font_style {
+        color {
+          argb: 0xFF0000FF
+        }
+      }
+      max_lines: {
+        value: 1000
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/spannable_image.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/spannable_image.textproto
new file mode 100644
index 0000000..bdafd00
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/spannable_image.textproto
@@ -0,0 +1,45 @@
+spannable {
+  max_lines {
+    value: 5
+  }
+  multiline_alignment {
+    value: HALIGN_START
+  }
+  spans {
+    text {
+      font_style {
+        color {
+          argb: 0xFFFF0000
+        }
+      }
+      text {
+        value: "Hello"
+      }
+    }
+  }
+  spans {
+    image {
+      resource_id {
+        value: "android"
+      }
+      width {
+        value: 24
+      }
+      height {
+        value: 24
+      }
+    }
+  }
+  spans {
+    text {
+      font_style {
+        color {
+          argb: 0xFF00FF00
+        }
+      }
+      text {
+        value: "World"
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/spannable_image_with_clickable.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/spannable_image_with_clickable.textproto
new file mode 100644
index 0000000..4c53354
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/spannable_image_with_clickable.textproto
@@ -0,0 +1,53 @@
+spannable {
+  max_lines {
+    value: 5
+  }
+  multiline_alignment {
+    value: HALIGN_START
+  }
+  spans {
+    text {
+      font_style {
+        color {
+          argb: 0xFFFF0000
+        }
+      }
+      text {
+        value: "Hello"
+      }
+    }
+  }
+  spans {
+    image {
+      resource_id {
+        value: "android"
+      }
+      width {
+        value: 24
+      }
+      height {
+        value: 24
+      }
+      modifiers {
+        clickable {
+          id: "HelloWorld"
+          on_click {
+            load_action {}
+          }
+        }
+      }
+    }
+  }
+  spans {
+    text {
+      font_style {
+        color {
+          argb: 0xFF00FF00
+        }
+      }
+      text {
+        value: "World"
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/spannable_image_wrapped.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/spannable_image_wrapped.textproto
new file mode 100644
index 0000000..e408122
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/spannable_image_wrapped.textproto
@@ -0,0 +1,52 @@
+column {
+  contents {
+    spannable {
+      max_lines {
+        value: 5
+      }
+      multiline_alignment {
+        value: HALIGN_START
+      }
+      spans {
+        text {
+          font_style {
+            color {
+              argb: 0xFFFF0000
+            }
+            size {
+              value: 32
+            }
+          }
+          text {
+            value: "abcdefghijk"
+          }
+        }
+      }
+      spans {
+        image {
+          resource_id {
+            value: "android"
+          }
+          width {
+            value: 24
+          }
+          height {
+            value: 24
+          }
+        }
+      }
+      spans {
+        text {
+          font_style {
+            color {
+              argb: 0xFF00FF00
+            }
+          }
+          text {
+            value: "abcdefg"
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/spannable_text.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/spannable_text.textproto
new file mode 100644
index 0000000..aba61e0
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/spannable_text.textproto
@@ -0,0 +1,124 @@
+column {
+  contents {
+    spacer {
+      width {
+        linear_dimension {
+          value: 150
+        }
+      }
+      height {
+        linear_dimension {
+          value: 2
+        }
+      }
+      modifiers {
+        background {
+          color {
+            argb: 0xfffcba03
+          }
+        }
+      }
+    }
+  }
+  contents {
+    spannable {
+      max_lines {
+        value: 5
+      }
+      multiline_alignment {
+        value: HALIGN_START
+      }
+      line_spacing {
+        value: 20
+      }
+      spans {
+        text {
+          font_style {
+            color {
+              argb: 0xFFFF0000
+            }
+          }
+          text {
+            value: "Hello World "
+          }
+        }
+      }
+      spans {
+        text {
+          font_style {
+            weight {
+              value: FONT_WEIGHT_BOLD
+            }
+            color {
+              argb: 0xFF00FF00
+            }
+          }
+          text {
+            value: "This is a test that should wrap "
+          }
+        }
+      }
+      spans {
+        text {
+          font_style {
+            italic {
+              value: true
+            }
+            underline {
+              value: true
+            }
+            size {
+              value: 24
+            }
+            color {
+              argb: 0xFF0000FF
+            }
+          }
+          text {
+            value: "across multiple lines!"
+          }
+        }
+      }
+      spans {
+        text {
+          font_style {
+            size {
+              value: 14
+            }
+            color {
+              argb: 0xFF4287f5
+            }
+            letter_spacing {
+              value: 0.6
+            }
+          }
+          text {
+            value: "Social distancing! "
+          }
+        }
+      }
+    }
+  }
+  contents {
+    spacer {
+      width {
+        linear_dimension {
+          value: 150
+        }
+      }
+      height {
+        linear_dimension {
+          value: 2
+        }
+      }
+      modifiers {
+        background {
+          color {
+            argb: 0xfffcba03
+          }
+        }
+      }
+    }
+  }
+}
+
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/text_and_image_in_box.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_and_image_in_box.textproto
new file mode 100644
index 0000000..e0d791d
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_and_image_in_box.textproto
@@ -0,0 +1,29 @@
+# A box which contains multiple children should just layer them on top of each
+# other.
+box {
+  contents {
+    image {
+      resource_id {
+        value: "android"
+      }
+      width {
+        linear_dimension {
+          value: 18
+        }
+      }
+      height {
+        linear_dimension {
+          value: 18
+        }
+      }
+    }
+  }
+
+  contents {
+    text {
+      text {
+        value: "Hello World"
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/text_default_size.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_default_size.textproto
new file mode 100644
index 0000000..7ecd823
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_default_size.textproto
@@ -0,0 +1,34 @@
+# Expect the default text size to be the same regardless of whether or not it
+# has a color style. See b/165807784
+box {
+  modifiers {
+    background {
+      color {
+        argb: 0xFF000000
+      }
+    }
+  }
+  contents {
+    column {
+      contents {
+        text {
+          text {
+            value: "Default Size (No Style)"
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "Default Size (With Style)"
+          }
+          font_style {
+            color {
+              argb: 0xFFFFBE00
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/text_in_column.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_in_column.textproto
new file mode 100644
index 0000000..ad412e1
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_in_column.textproto
@@ -0,0 +1,38 @@
+column {
+  contents {
+    text {
+      text {
+        value: "Hello World"
+      }
+      font_style {
+        color {
+          argb: 0xFFFF0000
+        }
+      }
+    }
+  }
+  contents {
+    text {
+      text {
+        value: "More text"
+      }
+      font_style {
+        color {
+          argb: 0xFF00FF00
+        }
+      }
+    }
+  }
+  contents {
+    text {
+      text {
+        value: "Yet more text"
+      }
+      font_style {
+        color {
+          argb: 0xFF0000FF
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/text_in_row.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_in_row.textproto
new file mode 100644
index 0000000..0b20258
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_in_row.textproto
@@ -0,0 +1,50 @@
+row {
+  contents {
+    text {
+      text {
+        value: "This"
+      }
+      font_style {
+        color {
+          argb: 0xFFFF0000
+        }
+      }
+    }
+  }
+  contents {
+    text {
+      text {
+        value: "Is"
+      }
+      font_style {
+        color {
+          argb: 0xFF00FF00
+        }
+      }
+    }
+  }
+  contents {
+    text {
+      text {
+        value: "A"
+      }
+      font_style {
+        color {
+          argb: 0xFF0000FF
+        }
+      }
+    }
+  }
+  contents {
+    text {
+      text {
+        value: "Test"
+      }
+      font_style {
+        color {
+          argb: 0xFF00FFFF
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/text_with_font_weights.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_with_font_weights.textproto
new file mode 100644
index 0000000..ded6fd2
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_with_font_weights.textproto
@@ -0,0 +1,71 @@
+box {
+  modifiers {
+    background {
+      color {
+        argb: 0xFF000000
+      }
+    }
+  }
+  width {
+    expanded_dimension: {}
+  }
+  height {
+    expanded_dimension: {}
+  }
+  vertical_alignment {
+    value: VALIGN_CENTER
+  }
+  horizontal_alignment {
+    value: HALIGN_CENTER
+  }
+  contents {
+    column {
+      horizontal_alignment {
+        value: HALIGN_LEFT
+      }
+      contents {
+        text {
+          text {
+            value: "Weight=Unset (Normal)"
+          }
+          font_style {
+            size { value: 14 }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "Weight=Undefined (Normal)"
+          }
+          font_style {
+            size { value: 14 }
+            weight { value: FONT_WEIGHT_UNDEFINED }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "Weight=400 (Normal)"
+          }
+          font_style {
+            size { value: 14 }
+            weight { value: FONT_WEIGHT_NORMAL }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "Weight=700 (Bold)"
+          }
+          font_style {
+            size { value: 14 }
+            weight { value: FONT_WEIGHT_BOLD }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/text_with_font_weights_italic.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_with_font_weights_italic.textproto
new file mode 100644
index 0000000..34cc5a5
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_with_font_weights_italic.textproto
@@ -0,0 +1,75 @@
+box {
+  modifiers {
+    background {
+      color {
+        argb: 0xFF000000
+      }
+    }
+  }
+  width {
+    expanded_dimension: {}
+  }
+  height {
+    expanded_dimension: {}
+  }
+  vertical_alignment {
+    value: VALIGN_CENTER
+  }
+  horizontal_alignment {
+    value: HALIGN_CENTER
+  }
+  contents {
+    column {
+      horizontal_alignment {
+        value: HALIGN_LEFT
+      }
+      contents {
+        text {
+          text {
+            value: "Weight=Unset (Normal, Italic)"
+          }
+          font_style {
+            size { value: 14 }
+            italic { value: true }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "Weight=Undef (Normal, Italic)"
+          }
+          font_style {
+            size { value: 14 }
+            weight { value: FONT_WEIGHT_UNDEFINED }
+            italic { value: true }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "Weight=400 (Normal, Italic)"
+          }
+          font_style {
+            size { value: 14 }
+            weight { value: FONT_WEIGHT_NORMAL }
+            italic { value: true }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "Weight=700 (Bold, Italic)"
+          }
+          font_style {
+            size { value: 14 }
+            weight { value: FONT_WEIGHT_BOLD }
+            italic { value: true }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/text_with_spacing.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_with_spacing.textproto
new file mode 100644
index 0000000..9e4a193
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_with_spacing.textproto
@@ -0,0 +1,73 @@
+box {
+  modifiers {
+    background {
+      color {
+        argb: 0xFF000000
+      }
+    }
+  }
+  width {
+    expanded_dimension: {}
+  }
+  height {
+    expanded_dimension: {}
+  }
+  vertical_alignment {
+    value: VALIGN_CENTER
+  }
+  horizontal_alignment {
+    value: HALIGN_CENTER
+  }
+  contents {
+    column {
+      horizontal_alignment {
+        value: HALIGN_LEFT
+      }
+      contents {
+        text {
+          text {
+            value: "Normal height"
+          }
+          font_style {
+            size { value: 14 }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "size 14sp, lineHeight 34sp. This should be a longer text to show the baseline distance."
+          }
+          max_lines { value: 10 }
+          line_height { value: 34 }
+          font_style {
+            size { value: 14 }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "size 14sp, letterSpacing 0.5em"
+          }
+          max_lines { value: 10 }
+          font_style {
+            size { value: 14 }
+            letter_spacing { value: 0.5 }
+          }
+        }
+      }
+      contents {
+        text {
+          text {
+            value: "size 14sp, letterSpacing -0.1em"
+          }
+          font_style {
+            size { value: 14 }
+            letter_spacing { value: -0.1 }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/raw/text_with_style_no_color.textproto b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_with_style_no_color.textproto
new file mode 100644
index 0000000..8206ef9
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/raw/text_with_style_no_color.textproto
@@ -0,0 +1,13 @@
+spannable {
+  multiline_alignment {
+    value: HALIGN_START
+  }
+  spans {
+    text {
+      text {
+        value: "Hello World"
+      }
+    }
+  }
+}
+
diff --git a/wear/wear-tiles-renderer/src/androidTest/res/values/ic_channel_background.xml b/wear/wear-tiles-renderer/src/androidTest/res/values/ic_channel_background.xml
new file mode 100644
index 0000000..fe558ce
--- /dev/null
+++ b/wear/wear-tiles-renderer/src/androidTest/res/values/ic_channel_background.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="ic_channel_background">#3DDC84</color>
+</resources>
diff --git a/wear/wear-tiles-renderer/src/main/java/androidx/wear/tiles/renderer/ResourceAccessors.java b/wear/wear-tiles-renderer/src/main/java/androidx/wear/tiles/renderer/ResourceAccessors.java
index 5bc9bd6..4a297d3 100644
--- a/wear/wear-tiles-renderer/src/main/java/androidx/wear/tiles/renderer/ResourceAccessors.java
+++ b/wear/wear-tiles-renderer/src/main/java/androidx/wear/tiles/renderer/ResourceAccessors.java
@@ -122,7 +122,7 @@
             this.mProtoResources = protoResources;
         }
 
-        /** Set the resource loader for {@link AndroidImageResourceByResId} resources. */
+        /** Set the resource loader for {@link AndroidImageResourceByResIdAccessor} resources. */
         @NonNull
         @SuppressLint("MissingGetterMatchingBuilder")
         public Builder setAndroidImageResourceByResIdAccessor(
diff --git a/wear/wear-tiles/src/main/java/androidx/wear/tiles/TileProviderService.java b/wear/wear-tiles/src/main/java/androidx/wear/tiles/TileProviderService.java
index ab51044..10dfabc 100644
--- a/wear/wear-tiles/src/main/java/androidx/wear/tiles/TileProviderService.java
+++ b/wear/wear-tiles/src/main/java/androidx/wear/tiles/TileProviderService.java
@@ -82,7 +82,7 @@
      * Called when the system is requesting a new timeline from this Tile Provider. Note that this
      * may be called from a background thread.
      *
-     * @param requestParams Parameters about the request. See {@link TileRequestData} for more info.
+     * @param requestParams Parameters about the request. See {@link TileRequest} for more info.
      */
     @MainThread
     @NonNull
@@ -92,8 +92,8 @@
      * Called when the system is requesting a resource bundle from this Tile Provider. Note that
      * this may be called from a background thread.
      *
-     * @param requestParams Parameters about the request. See {@link ResourcesRequestData} for more
-     *     info.
+     * @param requestParams Parameters about the request. See {@link ResourcesRequest} for more
+     *                      info.
      */
     @MainThread
     @NonNull
@@ -104,7 +104,7 @@
      * Called when a tile provided by this Tile Provider is added to the carousel. Note that this
      * may be called from a background thread.
      *
-     * @param requestParams Parameters about the request. See {@link TileAddEventData} for more
+     * @param requestParams Parameters about the request. See {@link TileAddEvent} for more
      *     info.
      */
     @MainThread
@@ -114,7 +114,7 @@
      * Called when a tile provided by this Tile Provider is removed from the carousel. Note that
      * this may be called from a background thread.
      *
-     * @param requestParams Parameters about the request. See {@link TileRemoveEventData} for more
+     * @param requestParams Parameters about the request. See {@link TileRemoveEvent} for more
      *     info.
      */
     @MainThread
@@ -124,7 +124,7 @@
      * Called when a tile provided by this Tile Provider becomes into view, on screen. Note that
      * this may be called from a background thread.
      *
-     * @param requestParams Parameters about the request. See {@link TileEnterEventData} for more
+     * @param requestParams Parameters about the request. See {@link TileEnterEvent} for more
      *     info.
      */
     @MainThread
@@ -134,7 +134,7 @@
      * Called when a tile provided by this Tile Provider goes out of view, on screen. Note that this
      * may be called from a background thread.
      *
-     * @param requestParams Parameters about the request. See {@link TileLeaveEventData} for more
+     * @param requestParams Parameters about the request. See {@link TileLeaveEvent} for more
      *     info.
      */
     @MainThread
diff --git a/wear/wear-tiles/src/main/java/androidx/wear/tiles/builders/LayoutElementBuilders.java b/wear/wear-tiles/src/main/java/androidx/wear/tiles/builders/LayoutElementBuilders.java
index eea253a..3f1f665 100644
--- a/wear/wear-tiles/src/main/java/androidx/wear/tiles/builders/LayoutElementBuilders.java
+++ b/wear/wear-tiles/src/main/java/androidx/wear/tiles/builders/LayoutElementBuilders.java
@@ -1812,8 +1812,7 @@
             }
 
             /**
-             * Sets how to align the contents of this container relative to anchor_angle. See the
-             * descriptions of options in {@link ArcAnchorType} for more information. If not
+             * Sets how to align the contents of this container relative to anchor_angle. If not
              * defined, defaults to ARC_ANCHOR_CENTER.
              */
             @SuppressLint("MissingGetterMatchingBuilder")
diff --git a/wear/wear-tiles/src/main/java/androidx/wear/tiles/readers/EventReaders.java b/wear/wear-tiles/src/main/java/androidx/wear/tiles/readers/EventReaders.java
index 8f2324e..2ae5a0a 100644
--- a/wear/wear-tiles/src/main/java/androidx/wear/tiles/readers/EventReaders.java
+++ b/wear/wear-tiles/src/main/java/androidx/wear/tiles/readers/EventReaders.java
@@ -31,7 +31,7 @@
 public class EventReaders {
     private EventReaders() {}
 
-    /** Reader for a {@link TileAddEventData} instance. */
+    /** Reader for Tile add event parameters. */
     public static class TileAddEvent {
         private final EventProto.TileAddEvent mProto;
 
@@ -64,7 +64,7 @@
         }
     }
 
-    /** Reader for a {@link TileRemoveEventData} instance. */
+    /** Reader for Tile remove event parameters. */
     public static class TileRemoveEvent {
         private final EventProto.TileRemoveEvent mProto;
 
@@ -97,7 +97,7 @@
         }
     }
 
-    /** Reader for a {@link TileEnterEventData} instance. */
+    /** Reader for Tile enter event parameters. */
     public static class TileEnterEvent {
         private final EventProto.TileEnterEvent mProto;
 
@@ -130,7 +130,7 @@
         }
     }
 
-    /** Reader for a {@link TileLeaveEventData} instance. */
+    /** Reader for a Tile leave event parameters. */
     public static class TileLeaveEvent {
         private final EventProto.TileLeaveEvent mProto;
 
diff --git a/wear/wear-tiles/src/main/java/androidx/wear/tiles/readers/RequestReaders.java b/wear/wear-tiles/src/main/java/androidx/wear/tiles/readers/RequestReaders.java
index 0584c8c..d3a50de6 100644
--- a/wear/wear-tiles/src/main/java/androidx/wear/tiles/readers/RequestReaders.java
+++ b/wear/wear-tiles/src/main/java/androidx/wear/tiles/readers/RequestReaders.java
@@ -33,7 +33,7 @@
 public class RequestReaders {
     private RequestReaders() {}
 
-    /** Reader for a {@link TileRequestData} instance. */
+    /** Reader for Tile request parameters. */
     public static class TileRequest {
         private final RequestProto.TileRequest mProto;
         private final int mTileId;
@@ -75,7 +75,7 @@
         }
     }
 
-    /** Reader for a {@link ResourcesRequestData} instance. */
+    /** Reader for resource request parameters. */
     public static class ResourcesRequest {
         private final RequestProto.ResourcesRequest mProto;
         private final int mTileId;
@@ -105,15 +105,15 @@
             return mTileId;
         }
 
-        /** Get the resource version requested by this {@link ResourcesRequestData}. */
+        /** Get the requested resource version. */
         @NonNull
         public String getVersion() {
             return mProto.getVersion();
         }
 
         /**
-         * Get the resource IDs requested by this {@link ResourcesRequestData}. May be empty, in
-         * which case all resources should be returned.
+         * Get the requested resource IDs. May be empty, in which case all resources should be
+         * returned.
          */
         @NonNull
         public List<String> getResourceIds() {
diff --git a/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/StyleParcelableTest.kt b/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/StyleParcelableTest.kt
index 3796bda..57b4cdc 100644
--- a/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/StyleParcelableTest.kt
+++ b/wear/wear-watchface-style/src/test/java/androidx/wear/watchface/style/StyleParcelableTest.kt
@@ -534,6 +534,7 @@
             )
         )
 
-        assertThat(style.toString()).isEqualTo("[id1 -> 2, id2 -> 3]")
+        assertThat(style.toString()).contains("id1 -> 2")
+        assertThat(style.toString()).contains("id2 -> 3")
     }
 }
diff --git a/wear/wear-watchface/samples/minimal/build.gradle b/wear/wear-watchface/samples/minimal/build.gradle
new file mode 100644
index 0000000..c1464dd
--- /dev/null
+++ b/wear/wear-watchface/samples/minimal/build.gradle
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import androidx.build.LibraryGroups
+import androidx.build.LibraryType
+import androidx.build.LibraryVersions
+
+import static androidx.build.dependencies.DependenciesKt.*
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.application")
+}
+
+dependencies {
+    api(project(":wear:wear-watchface"))
+    api(project(":wear:wear-watchface-guava"))
+    implementation(GUAVA_ANDROID)
+}
+
+androidx {
+    name = "AndroidX Wear Watchface Minimal Sample"
+    type = LibraryType.SAMPLES
+    mavenGroup = LibraryGroups.WEAR
+    mavenVersion = LibraryVersions.WEAR_WATCHFACE
+    inceptionYear = "2021"
+    description = "Contains the sample code for the Androidx Wear Watchface library"
+}
+
+android {
+    defaultConfig {
+        minSdkVersion 25
+    }
+    compileOptions {
+        sourceCompatibility 1.8
+        targetCompatibility 1.8
+    }
+}
diff --git a/wear/wear-watchface/samples/minimal/src/main/AndroidManifest.xml b/wear/wear-watchface/samples/minimal/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..4c45d9c
--- /dev/null
+++ b/wear/wear-watchface/samples/minimal/src/main/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="androidx.wear.watchface.samples.minimal">
+
+  <uses-feature android:name="android.hardware.type.watch" />
+
+  <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+  <application
+      android:allowBackup="true"
+      android:icon="@mipmap/ic_launcher"
+      android:label="@string/app_name"
+      android:supportsRtl="true"
+      android:theme="@android:style/Theme.DeviceDefault"
+      android:fullBackupContent="false">
+
+    <service
+        android:name=".WatchFaceService"
+        android:directBootAware="true"
+        android:exported="true"
+        android:label="@string/app_name"
+        android:permission="android.permission.BIND_WALLPAPER">
+
+      <intent-filter>
+        <action android:name="android.service.wallpaper.WallpaperService" />
+        <category android:name="com.google.android.wearable.watchface.category.WATCH_FACE" />
+      </intent-filter>
+
+      <meta-data
+          android:name="com.google.android.wearable.watchface.preview"
+          android:resource="@drawable/preview" />
+
+      <meta-data
+          android:name="android.service.wallpaper"
+          android:resource="@xml/watch_face" />
+
+    </service>
+
+  </application>
+
+</manifest>
diff --git a/wear/wear-watchface/samples/minimal/src/main/java/androidx/wear/watchface/samples/minimal/WatchFaceRenderer.java b/wear/wear-watchface/samples/minimal/src/main/java/androidx/wear/watchface/samples/minimal/WatchFaceRenderer.java
new file mode 100644
index 0000000..5271dda
--- /dev/null
+++ b/wear/wear-watchface/samples/minimal/src/main/java/androidx/wear/watchface/samples/minimal/WatchFaceRenderer.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.watchface.samples.minimal;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.graphics.Rect;
+import android.icu.util.Calendar;
+import android.view.SurfaceHolder;
+
+import androidx.wear.watchface.CanvasType;
+import androidx.wear.watchface.Renderer;
+import androidx.wear.watchface.WatchState;
+import androidx.wear.watchface.style.UserStyleRepository;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Minimal rendered for the watch face, using canvas to render hours, minutes, and a blinking
+ * separator.
+ */
+public class WatchFaceRenderer extends Renderer.CanvasRenderer {
+
+    private static final long UPDATE_DELAY_MILLIS = TimeUnit.SECONDS.toMillis(1);
+    private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
+
+    private final Paint mPaint;
+    private final char[] mTimeText = new char[5];
+
+    public WatchFaceRenderer(
+            @NotNull SurfaceHolder surfaceHolder,
+            @NotNull UserStyleRepository userStyleRepository,
+            @NotNull WatchState watchState) {
+        super(surfaceHolder, userStyleRepository, watchState, CanvasType.HARDWARE,
+                UPDATE_DELAY_MILLIS);
+        mPaint = new Paint();
+        mPaint.setTextAlign(Align.CENTER);
+        mPaint.setTextSize(64f);
+    }
+
+    @Override
+    public void render(@NotNull Canvas canvas, @NotNull Rect rect, @NotNull Calendar calendar) {
+        mPaint.setColor(Color.BLACK);
+        canvas.drawRect(rect, mPaint);
+        mPaint.setColor(Color.WHITE);
+        int hour = calendar.get(Calendar.HOUR_OF_DAY);
+        int minute = calendar.get(Calendar.MINUTE);
+        int second = calendar.get(Calendar.SECOND);
+        mTimeText[0] = DIGITS[hour / 10];
+        mTimeText[1] = DIGITS[hour % 10];
+        mTimeText[2] = second % 2 == 0 ? ':' : ' ';
+        mTimeText[3] = DIGITS[minute / 10];
+        mTimeText[4] = DIGITS[minute % 10];
+        canvas.drawText(mTimeText, 0, 5, rect.centerX(), rect.centerY(), mPaint);
+    }
+}
diff --git a/wear/wear-watchface/samples/minimal/src/main/java/androidx/wear/watchface/samples/minimal/WatchFaceService.java b/wear/wear-watchface/samples/minimal/src/main/java/androidx/wear/watchface/samples/minimal/WatchFaceService.java
new file mode 100644
index 0000000..5ceede1
--- /dev/null
+++ b/wear/wear-watchface/samples/minimal/src/main/java/androidx/wear/watchface/samples/minimal/WatchFaceService.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.wear.watchface.samples.minimal;
+
+import android.view.SurfaceHolder;
+
+import androidx.wear.watchface.Complication;
+import androidx.wear.watchface.ComplicationsManager;
+import androidx.wear.watchface.ListenableWatchFaceService;
+import androidx.wear.watchface.Renderer;
+import androidx.wear.watchface.WatchFace;
+import androidx.wear.watchface.WatchFaceType;
+import androidx.wear.watchface.WatchState;
+import androidx.wear.watchface.style.UserStyleRepository;
+import androidx.wear.watchface.style.UserStyleSchema;
+import androidx.wear.watchface.style.UserStyleSetting;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collections;
+
+/** The service that defines the watch face. */
+public class WatchFaceService extends ListenableWatchFaceService {
+
+    @NotNull
+    @Override
+    protected ListenableFuture<WatchFace> createWatchFaceFuture(
+            @NotNull SurfaceHolder surfaceHolder, @NotNull WatchState watchState) {
+        UserStyleRepository userStyleRepository =
+                new UserStyleRepository(
+                        new UserStyleSchema(Collections.<UserStyleSetting>emptyList()));
+        ComplicationsManager complicationManager =
+                new ComplicationsManager(Collections.<Complication>emptyList(),
+                        userStyleRepository);
+        Renderer renderer = new WatchFaceRenderer(surfaceHolder, userStyleRepository, watchState);
+        return Futures.immediateFuture(
+                new WatchFace(WatchFaceType.DIGITAL, userStyleRepository, renderer,
+                        complicationManager));
+    }
+}
diff --git a/wear/wear-watchface/samples/minimal/src/main/res/drawable/ic_launcher_background.xml b/wear/wear-watchface/samples/minimal/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..69d8a24
--- /dev/null
+++ b/wear/wear-watchface/samples/minimal/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+  <group android:scaleX="0.7"
+      android:scaleY="0.7"
+      android:translateX="16.2"
+      android:translateY="16.2">
+      <path android:fillColor="#3DDC84"
+            android:pathData="M0,0h108v108h-108z"/>
+      <path android:fillColor="#00000000" android:pathData="M9,0L9,108"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M19,0L19,108"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M29,0L29,108"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M39,0L39,108"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M49,0L49,108"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M59,0L59,108"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M69,0L69,108"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M79,0L79,108"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M89,0L89,108"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M99,0L99,108"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M0,9L108,9"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M0,19L108,19"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M0,29L108,29"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M0,39L108,39"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M0,49L108,49"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M0,59L108,59"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M0,69L108,69"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M0,79L108,79"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M0,89L108,89"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M0,99L108,99"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M19,29L89,29"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M19,39L89,39"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M19,49L89,49"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M19,59L89,59"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M19,69L89,69"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M19,79L89,79"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M29,19L29,89"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M39,19L39,89"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M49,19L49,89"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M59,19L59,89"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M69,19L69,89"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+      <path android:fillColor="#00000000" android:pathData="M79,19L79,89"
+            android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
+  </group>
+</vector>
diff --git a/wear/wear-watchface/samples/minimal/src/main/res/drawable/ic_launcher_foreground.xml b/wear/wear-watchface/samples/minimal/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..74f38c8
--- /dev/null
+++ b/wear/wear-watchface/samples/minimal/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108"
+    android:tint="#000000">
+  <group android:scaleX="2.61"
+      android:scaleY="2.61"
+      android:translateX="22.68"
+      android:translateY="22.68">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,2C6.5,2 2,6.5 2,12s4.5,10 10,10s10,-4.5 10,-10S17.5,2 12,2zM16.2,16.2L11,13V7h1.5v5.2l4.5,2.7L16.2,16.2z"/>
+  </group>
+</vector>
diff --git a/wear/wear-watchface/samples/minimal/src/main/res/drawable/preview.png b/wear/wear-watchface/samples/minimal/src/main/res/drawable/preview.png
new file mode 100644
index 0000000..24eadcb
--- /dev/null
+++ b/wear/wear-watchface/samples/minimal/src/main/res/drawable/preview.png
Binary files differ
diff --git a/wear/wear-watchface/samples/minimal/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/wear/wear-watchface/samples/minimal/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..bbd3e02
--- /dev/null
+++ b/wear/wear-watchface/samples/minimal/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background"/>
+    <foreground android:drawable="@drawable/ic_launcher_foreground"/>
+</adaptive-icon>
\ No newline at end of file
diff --git a/wear/wear-watchface/samples/minimal/src/main/res/mipmap-hdpi/ic_launcher.png b/wear/wear-watchface/samples/minimal/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..837401a
--- /dev/null
+++ b/wear/wear-watchface/samples/minimal/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/wear/wear-watchface/samples/minimal/src/main/res/mipmap-mdpi/ic_launcher.png b/wear/wear-watchface/samples/minimal/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f208553
--- /dev/null
+++ b/wear/wear-watchface/samples/minimal/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/wear/wear-watchface/samples/minimal/src/main/res/mipmap-xhdpi/ic_launcher.png b/wear/wear-watchface/samples/minimal/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..c9f75b4
--- /dev/null
+++ b/wear/wear-watchface/samples/minimal/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/wear/wear-watchface/samples/minimal/src/main/res/mipmap-xxhdpi/ic_launcher.png b/wear/wear-watchface/samples/minimal/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..5c6c342
--- /dev/null
+++ b/wear/wear-watchface/samples/minimal/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/wear/wear-watchface/samples/minimal/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/wear/wear-watchface/samples/minimal/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4b7cddf
--- /dev/null
+++ b/wear/wear-watchface/samples/minimal/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/wear/wear-watchface/samples/minimal/src/main/res/values/strings.xml b/wear/wear-watchface/samples/minimal/src/main/res/values/strings.xml
new file mode 100644
index 0000000..1c8f26a
--- /dev/null
+++ b/wear/wear-watchface/samples/minimal/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+  <string name="app_name">Minimal Digital</string>
+</resources>
diff --git a/wear/wear-watchface/samples/minimal/src/main/res/xml/watch_face.xml b/wear/wear-watchface/samples/minimal/src/main/res/xml/watch_face.xml
new file mode 100644
index 0000000..7e7098f
--- /dev/null
+++ b/wear/wear-watchface/samples/minimal/src/main/res/xml/watch_face.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<wallpaper/>
\ No newline at end of file
diff --git a/wear/wear-watchface/src/androidTest/AndroidManifest.xml b/wear/wear-watchface/src/androidTest/AndroidManifest.xml
index 69502ff..b18d5a3c 100644
--- a/wear/wear-watchface/src/androidTest/AndroidManifest.xml
+++ b/wear/wear-watchface/src/androidTest/AndroidManifest.xml
@@ -17,6 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="androidx.wear.watchface.test">
     <application android:requestLegacyExternalStorage="true">
+        <activity android:name=".ComplicationTapActivity"/>
     </application>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
diff --git a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceControlServiceTest.kt b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceControlServiceTest.kt
index 55b5c24..b82b434 100644
--- a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceControlServiceTest.kt
+++ b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceControlServiceTest.kt
@@ -40,7 +40,9 @@
 import androidx.wear.watchface.data.IdAndComplicationDataWireFormat
 import androidx.wear.watchface.samples.EXAMPLE_CANVAS_WATCHFACE_LEFT_COMPLICATION_ID
 import androidx.wear.watchface.samples.EXAMPLE_CANVAS_WATCHFACE_RIGHT_COMPLICATION_ID
+import androidx.wear.watchface.samples.EXAMPLE_OPENGL_COMPLICATION_ID
 import androidx.wear.watchface.samples.ExampleCanvasAnalogWatchFaceService
+import androidx.wear.watchface.samples.ExampleOpenGLWatchFaceService
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -80,6 +82,32 @@
         )
     }
 
+    private fun createOpenGlInstance(width: Int, height: Int): IHeadlessWatchFace {
+        val instanceService = IWatchFaceControlService.Stub.asInterface(
+            WatchFaceControlService().apply {
+                setContext(ApplicationProvider.getApplicationContext<Context>())
+            }.onBind(
+                Intent(WatchFaceControlService.ACTION_WATCHFACE_CONTROL_SERVICE)
+            )
+        )
+        return instanceService.createHeadlessWatchFaceInstance(
+            HeadlessWatchFaceInstanceParams(
+                ComponentName(
+                    ApplicationProvider.getApplicationContext<Context>(),
+                    ExampleOpenGLWatchFaceService::class.java
+                ),
+                DeviceConfig(
+                    false,
+                    false,
+                    0,
+                    0
+                ),
+                width,
+                height
+            )
+        )
+    }
+
     @Test
     fun createHeadlessWatchFaceInstance() {
         val instance = createInstance(100, 100)
@@ -124,6 +152,40 @@
     }
 
     @Test
+    fun createHeadlessOpenglWatchFaceInstance() {
+        val instance = createOpenGlInstance(400, 400)
+        val bitmap = SharedMemoryImage.ashmemReadImageBundle(
+            instance.takeWatchFaceScreenshot(
+                WatchfaceScreenshotParams(
+                    RenderParameters(
+                        DrawMode.INTERACTIVE,
+                        RenderParameters.DRAW_ALL_LAYERS,
+                        null,
+                        Color.RED
+                    ).toWireFormat(),
+                    1234567890,
+                    null,
+                    listOf(
+                        IdAndComplicationDataWireFormat(
+                            EXAMPLE_OPENGL_COMPLICATION_ID,
+                            ShortTextComplicationData.Builder(
+                                PlainComplicationText.Builder("Mon").build()
+                            )
+                                .setTitle(PlainComplicationText.Builder("23rd").build())
+                                .build()
+                                .asWireComplicationData()
+                        )
+                    )
+                )
+            )
+        )
+
+        bitmap.assertAgainstGolden(screenshotRule, "opengl_headless")
+
+        instance.release()
+    }
+
+    @Test
     fun testCommandTakeComplicationScreenShot() {
         val instance = createInstance(400, 400)
         val bitmap = SharedMemoryImage.ashmemReadImageBundle(
@@ -153,4 +215,4 @@
 
         instance.release()
     }
-}
+}
\ No newline at end of file
diff --git a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt
index caeba39..929dadc 100644
--- a/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt
+++ b/wear/wear-watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceServiceImageTest.kt
@@ -16,13 +16,17 @@
 
 package androidx.wear.watchface.test
 
+import android.app.Activity
+import android.app.PendingIntent
 import android.content.Context
+import android.content.Intent
 import android.graphics.Bitmap
 import android.graphics.Canvas
 import android.graphics.Color
 import android.graphics.Rect
 import android.graphics.SurfaceTexture
 import android.icu.util.TimeZone
+import android.os.Bundle
 import android.os.Handler
 import android.os.Looper
 import android.support.wearable.watchface.SharedMemoryImage
@@ -39,6 +43,7 @@
 import androidx.wear.watchface.DrawMode
 import androidx.wear.watchface.LayerMode
 import androidx.wear.watchface.RenderParameters
+import androidx.wear.watchface.TapType
 import androidx.wear.watchface.WatchFaceService
 import androidx.wear.watchface.control.IInteractiveWatchFaceWCS
 import androidx.wear.watchface.control.IPendingInteractiveWatchFaceWCS
@@ -54,6 +59,7 @@
 import androidx.wear.watchface.samples.GREEN_STYLE
 import androidx.wear.watchface.style.Layer
 import androidx.wear.watchface.style.data.UserStyleWireFormat
+import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
 import org.junit.Rule
@@ -71,6 +77,36 @@
 
 private const val INTERACTIVE_INSTANCE_ID = "InteractiveTestInstance"
 
+// Activity for testing complication taps.
+public class ComplicationTapActivity : Activity() {
+    internal companion object {
+        private val lock = Any()
+        private lateinit var theIntent: Intent
+        private var countDown: CountDownLatch? = null
+
+        fun newCountDown() {
+            countDown = CountDownLatch(1)
+        }
+
+        fun awaitIntent(): Intent? {
+            if (countDown!!.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+                return theIntent
+            } else {
+                return null
+            }
+        }
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        synchronized(lock) {
+            theIntent = intent
+        }
+        countDown!!.countDown()
+        finish()
+    }
+}
+
 @RunWith(AndroidJUnit4::class)
 @MediumTest
 class WatchFaceServiceImageTest {
@@ -87,6 +123,18 @@
         SystemProviders.DAY_OF_WEEK to
             ShortTextComplicationData.Builder(PlainComplicationText.Builder("Mon").build())
                 .setTitle(PlainComplicationText.Builder("23rd").build())
+                .setTapAction(
+                    PendingIntent.getActivity(
+                        ApplicationProvider.getApplicationContext<Context>(),
+                        123,
+                        Intent(
+                            ApplicationProvider.getApplicationContext<Context>(),
+                            ComplicationTapActivity::class.java
+                        ).apply {
+                        },
+                        PendingIntent.FLAG_ONE_SHOT
+                    )
+                )
                 .build()
                 .asWireComplicationData(),
         SystemProviders.STEP_COUNT to
@@ -518,4 +566,25 @@
             engineWrapper.onDestroy()
         }
     }
+
+    @Test
+    fun complicationTapLaunchesActivity() {
+        handler.post(this::initCanvasWatchFace)
+
+        ComplicationTapActivity.newCountDown()
+        handler.post {
+            val interactiveWatchFaceInstanceSysUi =
+                InteractiveInstanceManager.getAndRetainInstance(
+                    interactiveWatchFaceInstanceWCS.instanceId
+                )!!.createSysUiApi()
+            interactiveWatchFaceInstanceSysUi.sendTouchEvent(
+                85,
+                165,
+                TapType.TAP
+            )
+            interactiveWatchFaceInstanceSysUi.release()
+        }
+
+        assertThat(ComplicationTapActivity.awaitIntent()).isNotNull()
+    }
 }
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt
index 5417b77..a1df4f19 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/Renderer.kt
@@ -476,13 +476,23 @@
                     Log.w(TAG, "eglDestroySurface failed")
                 }
             }
-            eglSurface = EGL14.eglCreateWindowSurface(
-                eglDisplay,
-                eglConfig,
-                surfaceHolder.surface,
-                eglSurfaceAttribList,
-                0
-            )
+            eglSurface = if (watchState.isHeadless) {
+                // Headless instances have a fake surfaceHolder so fall back to a Pbuffer.
+                EGL14.eglCreatePbufferSurface(
+                    eglDisplay,
+                    eglConfig,
+                    intArrayOf(EGL14.EGL_WIDTH, width, EGL14.EGL_HEIGHT, height, EGL14.EGL_NONE),
+                    0
+                )
+            } else {
+                EGL14.eglCreateWindowSurface(
+                    eglDisplay,
+                    eglConfig,
+                    surfaceHolder.surface,
+                    eglSurfaceAttribList,
+                    0
+                )
+            }
             if (eglSurface == EGL14.EGL_NO_SURFACE) {
                 throw RuntimeException("eglCreateWindowSurface failed")
             }
diff --git a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
index ee75eb8..978e628 100644
--- a/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
+++ b/wear/wear-watchface/src/main/java/androidx/wear/watchface/WatchFaceService.kt
@@ -358,6 +358,7 @@
 
         internal var firstSetSystemState = true
         internal var immutableSystemStateDone = false
+        private var ignoreNextOnVisibilityChanged = false
 
         internal var lastActiveComplications: IntArray? = null
         internal var lastA11yLabels: Array<ContentDescriptionLabel>? = null
@@ -406,6 +407,12 @@
             if (pendingWallpaperInstance != null) {
                 val asyncTraceEvent =
                     AsyncTraceEvent("Create PendingWallpaperInteractiveWatchFaceInstance")
+                // The WallpaperService works around bugs in wallpapers (see b/5233826 and
+                // b/5209847) by sending onVisibilityChanged(true), onVisibilityChanged(false)
+                // after onSurfaceChanged during creation. This is unfortunate for us since we
+                // perform work in response (see WatchFace.visibilityObserver). So here we
+                // workaround the workaround...
+                ignoreNextOnVisibilityChanged = true
                 coroutineScope.launch {
                     pendingWallpaperInstance.callback.onInteractiveWatchFaceWcsCreated(
                         createInteractiveInstance(
@@ -1086,22 +1093,34 @@
         ).use {
             super.onVisibilityChanged(visible)
 
-            // We are requesting state every time the watch face changes its visibility because
-            // wallpaper commands have a tendency to be dropped. By requesting it on every
-            // visibility change, we ensure that we don't become a victim of some race condition.
-            sendBroadcast(
-                Intent(Constants.ACTION_REQUEST_STATE).apply {
-                    putExtra(Constants.EXTRA_WATCH_FACE_VISIBLE, visible)
-                }
-            )
-
-            // We can't guarantee the binder has been set and onSurfaceChanged called before this
-            // command.
-            if (!watchFaceCreated()) {
-                pendingVisibilityChanged = visible
+            if (ignoreNextOnVisibilityChanged) {
+                ignoreNextOnVisibilityChanged = false
                 return
             }
 
+            // In the WSL flow Home doesn't know when WallpaperService has actually launched a
+            // watchface after requesting a change. It used [Constants.ACTION_REQUEST_STATE] as a
+            // signal to trigger the old boot flow (sending the binder etc). This is no longer
+            // required from android R onwards. See (b/181965946).
+            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+                // We are requesting state every time the watch face changes its visibility because
+                // wallpaper commands have a tendency to be dropped. By requesting it on every
+                // visibility change, we ensure that we don't become a victim of some race
+                // condition.
+                sendBroadcast(
+                    Intent(Constants.ACTION_REQUEST_STATE).apply {
+                        putExtra(Constants.EXTRA_WATCH_FACE_VISIBLE, visible)
+                    }
+                )
+
+                // We can't guarantee the binder has been set and onSurfaceChanged called before
+                // this command.
+                if (!watchFaceCreated()) {
+                    pendingVisibilityChanged = visible
+                    return
+                }
+            }
+
             mutableWatchState.isVisible.value = visible
             pendingVisibilityChanged = null
         }
@@ -1275,6 +1294,7 @@
             writer.println("createdBy=$createdBy")
             writer.println("watchFaceInitStarted=$watchFaceInitStarted")
             writer.println("asyncWatchFaceConstructionPending=$asyncWatchFaceConstructionPending")
+            writer.println("ignoreNextOnVisibilityChanged=$ignoreNextOnVisibilityChanged")
 
             if (this::interactiveInstanceId.isInitialized) {
                 writer.println("interactiveInstanceId=$interactiveInstanceId")
diff --git a/wear/wear-watchface/src/main/res/values-nl/watchface_strings.xml b/wear/wear-watchface/src/main/res/values-nl/watchface_strings.xml
index 88c6c85..a6b6a0e 100644
--- a/wear/wear-watchface/src/main/res/values-nl/watchface_strings.xml
+++ b/wear/wear-watchface/src/main/res/values-nl/watchface_strings.xml
@@ -2,7 +2,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="complication_config" msgid="292306201243482945">"Wijzerplaatcomplicaties instellen"</string>
-    <string name="watchface_settings" msgid="4785773105440577595">"Wijzerplaatinstellingen configureren"</string>
+    <string name="watchface_settings" msgid="4785773105440577595">"Wijzerplaatinstellingen instellen"</string>
     <string name="style_config" msgid="2987895585951859981">"Wijzerplaatstijlen instellen"</string>
     <string name="none_background_image_provider" msgid="2326408635673026310">"Geen"</string>
     <string name="settings_complications" msgid="7688669266180209514">"Gegevens"</string>
diff --git a/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt b/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
index 13f1879..c7457c6 100644
--- a/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
+++ b/wear/wear-watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
@@ -2337,4 +2337,43 @@
         val instance = InteractiveInstanceManager.getAndRetainInstance(instanceId)
         assertThat(instance).isNull()
     }
+
+    public fun firstOnVisibilityChangedIgnoredPostRFlow() {
+        val instanceId = "interactiveInstanceId"
+        initWallpaperInteractiveWatchFaceInstance(
+            WatchFaceType.ANALOG,
+            listOf(leftComplication, rightComplication),
+            UserStyleSchema(emptyList()),
+            WallpaperInteractiveWatchFaceInstanceParams(
+                instanceId,
+                DeviceConfig(
+                    false,
+                    false,
+                    0,
+                    0
+                ),
+                SystemState(false, 0),
+                UserStyle(emptyMap()).toWireFormat(),
+                listOf(
+                    IdAndComplicationDataWireFormat(
+                        LEFT_COMPLICATION_ID,
+                        ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
+                            .setShortText(ComplicationText.plainText("INITIAL_VALUE"))
+                            .build()
+                    )
+                )
+            )
+        )
+
+        val observer = mock<Observer<Boolean>>()
+
+        // This should be ignored.
+        engineWrapper.onVisibilityChanged(true)
+        watchState.isVisible.addObserver(observer)
+        verify(observer, times(0)).onChanged(false)
+
+        // This should trigger the observer.
+        engineWrapper.onVisibilityChanged(false)
+        verify(observer).onChanged(true)
+    }
 }
diff --git a/wear/wear/src/androidTest/java/androidx/wear/widget/WearArcLayoutTest.kt b/wear/wear/src/androidTest/java/androidx/wear/widget/WearArcLayoutTest.kt
index 54988dd..47b72bb 100644
--- a/wear/wear/src/androidTest/java/androidx/wear/widget/WearArcLayoutTest.kt
+++ b/wear/wear/src/androidTest/java/androidx/wear/widget/WearArcLayoutTest.kt
@@ -46,6 +46,7 @@
 import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
 import androidx.test.espresso.matcher.ViewMatchers.withId
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.MediumTest
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.screenshot.AndroidXScreenshotTestRule
@@ -633,6 +634,7 @@
         testEventsFast("touch_fast_screenshot", views)
     }
 
+    @FlakyTest // b/182268136
     @Test(timeout = 5000)
     fun testMarginTouch() {
         val views = createTwoArcsWithMargin()
diff --git a/webkit/integration-tests/testapp/README.md b/webkit/integration-tests/testapp/README.md
index 335af43..b9a3c7f 100644
--- a/webkit/integration-tests/testapp/README.md
+++ b/webkit/integration-tests/testapp/README.md
@@ -7,6 +7,13 @@
 the latest AndroidX Webkit APIs and as a means to exercise those APIs for manual
 testing.
 
+## Reading example code
+
+Examples are organized so that each Activity showcases a small subset of related
+APIs. To get started, [find the
+Activity](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:webkit/integration-tests/testapp/src/main/java/com/example/androidx/webkit/)
+for the APIs you're interested in learning about.
+
 ## Building the demo app
 
 ```shell
@@ -58,7 +65,7 @@
 APKs by following [these
 instructions](https://docs.google.com/document/d/1K_uOjyTn_UldZP1YxmvCEYXibDn2YB-S_76r3Y-z0bg/edit?usp=sharing).
 
-## Expected behavior
+## Expected behavior (Googlers only)
 
 Most Activities have documentation for the expected behavior. See descriptions
 and screenshots at http://go/wvsl-demo-app-guide, and can see screen recording
diff --git a/webkit/webkit/src/main/java/androidx/webkit/package-info.java b/webkit/webkit/src/main/java/androidx/webkit/package-info.java
index fe19dde..181b12c 100644
--- a/webkit/webkit/src/main/java/androidx/webkit/package-info.java
+++ b/webkit/webkit/src/main/java/androidx/webkit/package-info.java
@@ -23,12 +23,24 @@
  *
  * <p><b>How to declare the dependencies to use the library</b>
  *
- * <p>Inside your app's build.gradle file, include this line in dependencies:
- * <pre class="prettyprint">
- *dependencies {
- *    ...
- *    implementation 'androidx.webkit:webkit:1.2.0'
- *}</pre>
+ * <p>Please check the <a
+ * href="https://developer.android.com/jetpack/androidx/releases/webkit#declaring_dependencies">
+ * release notes</a> for instructions to add the latest release to your {@code build.gradle} file.
+ *
+ * <p><b>Public bug tracker</b>
+ *
+ * <p>If you find bugs in the androidx.webkit library or want to request new features, please
+ * <a href="https://issuetracker.google.com/issues/new?component=460423">do so here</a>.
+ *
+ * <p><b>Sample apps</b>
+ *
+ * <p>Please check out the WebView samples <a
+ * href="https://github.com/android/views-widgets-samples/tree/main/WebView">on GitHub</a> for a
+ * showcase of a handful of androidx.webkit APIs.
+ *
+ * <p>For more APIs, check out the sample app in the <a
+ * href="https://android.googlesource.com/platform/frameworks/support/+/androidx-main/webkit/integration-tests/testapp/README.md">AndroidX
+ * repo</a>.
  *
  * <p><b>Migrating to androidx.webkit</b>
  *
diff --git a/window/window/src/androidTest/java/androidx/window/ExtensionWindowBackendTest.java b/window/window/src/androidTest/java/androidx/window/ExtensionWindowBackendTest.java
index 52a190b..7a55cb9 100644
--- a/window/window/src/androidTest/java/androidx/window/ExtensionWindowBackendTest.java
+++ b/window/window/src/androidTest/java/androidx/window/ExtensionWindowBackendTest.java
@@ -32,6 +32,7 @@
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Rect;
@@ -43,6 +44,7 @@
 
 import com.google.common.collect.BoundType;
 import com.google.common.collect.Range;
+import com.google.common.util.concurrent.MoreExecutors;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -50,6 +52,7 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 /** Tests for {@link ExtensionWindowBackend} class. */
 @SuppressWarnings({"deprecation", "unchecked"}) // TODO(b/173739071) remove DeviceState
@@ -191,22 +194,6 @@
     }
 
     @Test
-    public void testRegisterLayoutChangeCallback_relayLastEmittedValue() {
-        WindowLayoutInfo expectedWindowLayoutInfo = newTestWindowLayoutInfo();
-        ExtensionWindowBackend backend = ExtensionWindowBackend.getInstance(mContext);
-        Consumer<WindowLayoutInfo> consumer = mock(WindowLayoutInfoConsumer.class);
-        TestActivity activity = mActivityTestRule.launchActivity(new Intent());
-        backend.registerLayoutChangeCallback(activity, Runnable::run,
-                mock(WindowLayoutInfoConsumer.class));
-        backend.mWindowExtension = mock(ExtensionInterfaceCompat.class);
-        backend.mLastReportedWindowLayouts.put(activity, expectedWindowLayoutInfo);
-
-        backend.registerLayoutChangeCallback(activity, Runnable::run, consumer);
-
-        verify(consumer).accept(expectedWindowLayoutInfo);
-    }
-
-    @Test
     public void testLayoutChangeCallback_emitNewValue() {
         ExtensionWindowBackend backend = ExtensionWindowBackend.getInstance(mContext);
         backend.mWindowExtension = mock(ExtensionInterfaceCompat.class);
@@ -223,12 +210,26 @@
         backendListener.onWindowLayoutChanged(activity, windowLayoutInfo);
 
         verify(consumer).accept(eq(windowLayoutInfo));
-        assertEquals(windowLayoutInfo, backend.mLastReportedWindowLayouts.get(activity));
+    }
 
-        // Test that the same value wouldn't be reported again
-        reset(consumer);
-        backendListener.onWindowLayoutChanged(activity, windowLayoutInfo);
-        verify(consumer, never()).accept(any());
+    @Test
+    public void testWindowLayoutInfo_updatesOnSubsequentRegistration() {
+        SwitchOnUnregisterExtensionInterfaceCompat interfaceCompat =
+                new SwitchOnUnregisterExtensionInterfaceCompat();
+        ExtensionWindowBackend backend = new ExtensionWindowBackend(interfaceCompat);
+        Activity activity = mock(Activity.class);
+        SimpleConsumer<WindowLayoutInfo> consumer = new SimpleConsumer<>();
+        Executor executor = MoreExecutors.directExecutor();
+        List<WindowLayoutInfo> expected = new ArrayList<>();
+
+        backend.registerLayoutChangeCallback(activity, executor, consumer);
+        expected.add(interfaceCompat.currentWindowLayoutInfo());
+        backend.unregisterLayoutChangeCallback(consumer);
+        backend.registerLayoutChangeCallback(activity, executor, consumer);
+        expected.add(interfaceCompat.currentWindowLayoutInfo());
+        backend.unregisterLayoutChangeCallback(consumer);
+
+        assertEquals(expected, consumer.mValues);
     }
 
     @Test
@@ -384,6 +385,10 @@
             mValues.add(t);
         }
 
+        List<T> allValues() {
+            return mValues;
+        }
+
         T lastValue() {
             return mValues.get(mValues.size() - 1);
         }
diff --git a/window/window/src/main/java/androidx/window/ExtensionWindowBackend.java b/window/window/src/main/java/androidx/window/ExtensionWindowBackend.java
index 2fa539f..3379725 100644
--- a/window/window/src/main/java/androidx/window/ExtensionWindowBackend.java
+++ b/window/window/src/main/java/androidx/window/ExtensionWindowBackend.java
@@ -34,8 +34,6 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
-import java.util.WeakHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.Executor;
 
@@ -72,11 +70,6 @@
     @VisibleForTesting
     DeviceState mLastReportedDeviceState;
 
-    /** Window layouts that were last reported through callbacks, used to filter out duplicates. */
-    @GuardedBy("sLock")
-    @VisibleForTesting
-    final Map<Activity, WindowLayoutInfo> mLastReportedWindowLayouts = new WeakHashMap<>();
-
     private static final String TAG = "WindowServer";
 
     @VisibleForTesting
@@ -211,15 +204,9 @@
             WindowLayoutChangeCallbackWrapper callbackWrapper =
                     new WindowLayoutChangeCallbackWrapper(activity, executor, callback);
             mWindowLayoutChangeCallbacks.add(callbackWrapper);
-            // Read value before registering in case the extension updates synchronously.
-            // A synchronous update would result in two values emitted.
-            WindowLayoutInfo lastReportedValue = mLastReportedWindowLayouts.get(activity);
             if (!isActivityRegistered) {
                 mWindowExtension.onWindowLayoutChangeListenerAdded(activity);
             }
-            if (lastReportedValue != null) {
-                callbackWrapper.accept(lastReportedValue);
-            }
         }
     }
 
@@ -349,18 +336,6 @@
         @SuppressLint("SyntheticAccessor")
         public void onWindowLayoutChanged(@NonNull Activity activity,
                 @NonNull WindowLayoutInfo newLayout) {
-            synchronized (sLock) {
-                WindowLayoutInfo lastReportedValue = mLastReportedWindowLayouts.get(activity);
-                if (newLayout.equals(lastReportedValue)) {
-                    // Skipping, value already reported
-                    if (DEBUG) {
-                        Log.w(TAG, "Extension reported an old layout value");
-                    }
-                    return;
-                }
-                mLastReportedWindowLayouts.put(activity, newLayout);
-            }
-
             for (WindowLayoutChangeCallbackWrapper callbackWrapper : mWindowLayoutChangeCallbacks) {
                 if (!callbackWrapper.mActivity.equals(activity)) {
                     continue;
diff --git a/window/window/src/testUtil/java/androidx/window/EmptyExtensionCallbackInterface.java b/window/window/src/testUtil/java/androidx/window/EmptyExtensionCallbackInterface.java
new file mode 100644
index 0000000..2b676a4
--- /dev/null
+++ b/window/window/src/testUtil/java/androidx/window/EmptyExtensionCallbackInterface.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 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.window;
+
+import static androidx.window.ExtensionInterfaceCompat.ExtensionCallbackInterface;
+
+import android.app.Activity;
+
+import androidx.annotation.NonNull;
+
+/**
+ * An empty implementation of {@link ExtensionCallbackInterface} with no-op methods.
+ */
+public class EmptyExtensionCallbackInterface implements ExtensionCallbackInterface {
+    @Override
+    public void onDeviceStateChanged(@NonNull DeviceState newDeviceState) {
+
+    }
+
+    @Override
+    public void onWindowLayoutChanged(@NonNull Activity activity,
+            @NonNull WindowLayoutInfo newLayout) {
+
+    }
+}
diff --git a/window/window/src/testUtil/java/androidx/window/SwitchOnUnregisterExtensionInterfaceCompat.java b/window/window/src/testUtil/java/androidx/window/SwitchOnUnregisterExtensionInterfaceCompat.java
new file mode 100644
index 0000000..b49cd3d
--- /dev/null
+++ b/window/window/src/testUtil/java/androidx/window/SwitchOnUnregisterExtensionInterfaceCompat.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2021 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.window;
+
+import static androidx.window.FoldingFeature.STATE_FLAT;
+import static androidx.window.FoldingFeature.STATE_HALF_OPENED;
+import static androidx.window.FoldingFeature.TYPE_HINGE;
+
+import android.app.Activity;
+import android.graphics.Rect;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.NonNull;
+
+import java.util.Collections;
+
+/**
+ * An implementation of {@link ExtensionInterfaceCompat} that switches the state when a consumer
+ * is unregistered. Useful for testing consumers when they go through a cycle of register then
+ * unregister then register again.
+ */
+public final class SwitchOnUnregisterExtensionInterfaceCompat implements ExtensionInterfaceCompat {
+
+    private final Object mLock = new Object();
+    private final Rect mFoldBounds = new Rect(0, 100, 200, 100);
+    @GuardedBy("mLock")
+    private ExtensionCallbackInterface mCallback = new EmptyExtensionCallbackInterface();
+    @GuardedBy("mLock")
+    private int mState = STATE_FLAT;
+
+    @Override
+    public boolean validateExtensionInterface() {
+        return true;
+    }
+
+    @Override
+    public void setExtensionCallback(@NonNull ExtensionCallbackInterface extensionCallback) {
+        synchronized (mLock) {
+            mCallback = extensionCallback;
+        }
+    }
+
+    @Override
+    public void onWindowLayoutChangeListenerAdded(@NonNull Activity activity) {
+        synchronized (mLock) {
+            mCallback.onWindowLayoutChanged(activity, currentWindowLayoutInfo());
+        }
+    }
+
+    @Override
+    public void onWindowLayoutChangeListenerRemoved(@NonNull Activity activity) {
+        synchronized (mLock) {
+            mState = toggleState(mState);
+        }
+    }
+
+    @Override
+    public void onDeviceStateListenersChanged(boolean isEmpty) {
+
+    }
+
+    WindowLayoutInfo currentWindowLayoutInfo() {
+        return new WindowLayoutInfo(Collections.singletonList(currentFoldingFeature()));
+    }
+
+    FoldingFeature currentFoldingFeature() {
+        return new FoldingFeature(mFoldBounds, TYPE_HINGE, mState);
+    }
+
+    private static int toggleState(int currentState) {
+        if (currentState == STATE_FLAT) {
+            return STATE_HALF_OPENED;
+        }
+        return STATE_FLAT;
+    }
+}