Merge "disable dependency constraints for KMP projects" into androidx-main
diff --git a/ads/OWNERS b/ads/OWNERS
deleted file mode 100644
index 3720323..0000000
--- a/ads/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-# Bug component: 807287
-chaohuiw@google.com
-hanxu@google.com
diff --git a/ads/ads-identifier-benchmark/build.gradle b/ads/ads-identifier-benchmark/build.gradle
deleted file mode 100644
index 527e2f5..0000000
--- a/ads/ads-identifier-benchmark/build.gradle
+++ /dev/null
@@ -1,47 +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.
- */
-
-plugins {
-    id("AndroidXPlugin")
-    id("com.android.library")
-    id("androidx.benchmark")
-}
-
-dependencies {
-    androidTestImplementation(project(":benchmark:benchmark-junit4"))
-    androidTestImplementation(project(":ads:ads-identifier-common"))
-    androidTestImplementation(project(":ads:ads-identifier"))
-    androidTestImplementation(project(":ads:ads-identifier-provider"))
-    androidTestImplementation(project(":ads:ads-identifier-testing"))
-    androidTestImplementation("androidx.work:work-runtime:2.7.0")
-    androidTestImplementation(libs.junit)
-    androidTestImplementation(libs.multidex)
-    androidTestImplementation(libs.truth)
-    androidTestImplementation(libs.testExtJunit)
-    androidTestImplementation(libs.testCore)
-    androidTestImplementation(libs.testRunner)
-    androidTestImplementation(libs.testRules)
-    androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy)
-}
-
-android {
-    namespace "androidx.ads.identifier.benchmark"
-
-    defaultConfig {
-        multiDexEnabled true
-    }
-}
-
diff --git a/ads/ads-identifier-benchmark/lint-baseline.xml b/ads/ads-identifier-benchmark/lint-baseline.xml
deleted file mode 100644
index bbd1a88..0000000
--- a/ads/ads-identifier-benchmark/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-beta03" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.0.0-beta03">
-
-    <issue
-        id="BanThreadSleep"
-        message="Uses Thread.sleep()"
-        errorLine1="                    Thread.sleep(millis);"
-        errorLine2="                           ~~~~~">
-        <location
-            file="src/androidTest/java/androidx/ads/identifier/benchmark/AdvertisingIdBenchmark.java"/>
-    </issue>
-
-</issues>
diff --git a/ads/ads-identifier-benchmark/src/androidTest/AndroidManifest.xml b/ads/ads-identifier-benchmark/src/androidTest/AndroidManifest.xml
deleted file mode 100644
index fc0c987..0000000
--- a/ads/ads-identifier-benchmark/src/androidTest/AndroidManifest.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2018 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<manifest
-    xmlns:android="http://schemas.android.com/apk/res/android">
-    <application
-        android:name="androidx.ads.identifier.benchmark.AdsIdentifierBenchmarkApplication">
-        <!-- enable profiling by shell for non-intrusive profiling tools -->
-        <profileable android:shell="true"/>
-    </application>
-</manifest>
diff --git a/ads/ads-identifier-benchmark/src/androidTest/java/androidx/ads/identifier/benchmark/AdsIdentifierBenchmarkApplication.java b/ads/ads-identifier-benchmark/src/androidTest/java/androidx/ads/identifier/benchmark/AdsIdentifierBenchmarkApplication.java
deleted file mode 100644
index 9e71e40..0000000
--- a/ads/ads-identifier-benchmark/src/androidTest/java/androidx/ads/identifier/benchmark/AdsIdentifierBenchmarkApplication.java
+++ /dev/null
@@ -1,30 +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.ads.identifier.benchmark;
-
-import android.app.Application;
-
-@SuppressWarnings("deprecation")
-public class AdsIdentifierBenchmarkApplication extends Application {
-    @Override
-    public void onCreate() {
-        super.onCreate();
-
-        androidx.ads.identifier.provider.AdvertisingIdProviderManager.registerProviderCallable(
-                SampleAdvertisingIdProvider::new);
-    }
-}
diff --git a/ads/ads-identifier-benchmark/src/androidTest/java/androidx/ads/identifier/benchmark/AdvertisingIdBenchmark.java b/ads/ads-identifier-benchmark/src/androidTest/java/androidx/ads/identifier/benchmark/AdvertisingIdBenchmark.java
deleted file mode 100644
index 5323750..0000000
--- a/ads/ads-identifier-benchmark/src/androidTest/java/androidx/ads/identifier/benchmark/AdvertisingIdBenchmark.java
+++ /dev/null
@@ -1,248 +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.ads.identifier.benchmark;
-
-import static androidx.ads.identifier.AdvertisingIdUtils.GET_AD_ID_ACTION;
-import static androidx.ads.identifier.benchmark.SampleAdvertisingIdProvider.DUMMY_AD_ID;
-import static androidx.ads.identifier.testing.MockPackageManagerHelper.createServiceResolveInfo;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-
-import androidx.ads.identifier.provider.internal.AdvertisingIdService;
-import androidx.ads.identifier.testing.MockPackageManagerHelper;
-import androidx.annotation.NonNull;
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.LargeTest;
-import androidx.work.OneTimeWorkRequest;
-import androidx.work.WorkManager;
-import androidx.work.Worker;
-import androidx.work.WorkerParameters;
-
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.lang.reflect.Method;
-import java.util.concurrent.CountDownLatch;
-
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-@SuppressWarnings("deprecation")
-public class AdvertisingIdBenchmark {
-
-    private static final int CONCURRENCY_NUM = 10;
-    private static final String SERVICE_NAME = AdvertisingIdService.class.getName();
-
-    @Rule
-    public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
-
-    private Context mContext;
-
-    @Before
-    public void setUp() throws Exception {
-        Context applicationContext = ApplicationProvider.getApplicationContext();
-
-        mContext = mockContext(applicationContext);
-    }
-
-    private static Context mockContext(Context context) throws Exception {
-        MockPackageManagerHelper mockPackageManagerHelper = new MockPackageManagerHelper();
-        mockPackageManagerHelper.mockQueryGetAdIdServices(Lists.newArrayList(
-                createServiceResolveInfo(context.getPackageName(), SERVICE_NAME)));
-
-        return new ContextWrapper(context) {
-            @Override
-            public Context getApplicationContext() {
-                return this;
-            }
-
-            @Override
-            public PackageManager getPackageManager() {
-                return mockPackageManagerHelper.getMockPackageManager();
-            }
-        };
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        clearAdvertisingIdConnection();
-        stopAdvertisingIdService();
-    }
-
-    private void clearAdvertisingIdConnection() throws Exception {
-        Method method = androidx.ads.identifier.AdvertisingIdClient.class.getDeclaredMethod(
-                "clearConnectionClient");
-        method.setAccessible(true);
-        method.invoke(null);
-    }
-
-    private void stopAdvertisingIdService() {
-        Intent serviceIntent = new Intent(GET_AD_ID_ACTION);
-        serviceIntent.setClassName(mContext.getPackageName(), SERVICE_NAME);
-        mContext.stopService(serviceIntent);
-    }
-
-    @Test
-    public void getAdvertisingIdInfo() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
-        while (state.keepRunning()) {
-            CountDownLatch countDownLatch = new CountDownLatch(1);
-            getAdvertisingIdInfoListenableFuture(countDownLatch);
-            countDownLatch.await();
-        }
-    }
-
-    private void getAdvertisingIdInfoListenableFuture(CountDownLatch countDownLatch) {
-        ListenableFuture<androidx.ads.identifier.AdvertisingIdInfo>
-                advertisingIdInfoListenableFuture =
-                androidx.ads.identifier.AdvertisingIdClient.getAdvertisingIdInfo(mContext);
-        Futures.addCallback(advertisingIdInfoListenableFuture,
-                new FutureCallback<androidx.ads.identifier.AdvertisingIdInfo>() {
-                    @Override
-                    public void onSuccess(
-                            androidx.ads.identifier.AdvertisingIdInfo advertisingIdInfo) {
-                        assertThat(advertisingIdInfo.getId()).isEqualTo(DUMMY_AD_ID);
-                        countDownLatch.countDown();
-                    }
-
-                    @Override
-                    public void onFailure(@NonNull Throwable throwable) {
-                        throw new RuntimeException(throwable);
-                    }
-                }, MoreExecutors.directExecutor());
-    }
-
-    @Test
-    public void getAdvertisingIdInfo_worker() throws Exception {
-        WorkManager workManager = WorkManager.getInstance(mContext);
-        workManager.cancelAllWork();
-        final BenchmarkState state = mBenchmarkRule.getState();
-        while (state.keepRunning()) {
-            workManager.enqueue(OneTimeWorkRequest.from(GetAdInfoWorker.class)).getResult().get();
-        }
-    }
-
-    /** Get the Advertising ID on a worker thread. */
-    public static class GetAdInfoWorker extends Worker {
-        public GetAdInfoWorker(@NonNull Context context, @NonNull WorkerParameters params) {
-            super(context, params);
-        }
-
-        @NonNull
-        @Override
-        public Result doWork() {
-            try {
-                Context context = mockContext(getApplicationContext());
-                androidx.ads.identifier.AdvertisingIdInfo advertisingIdInfo =
-                        androidx.ads.identifier.AdvertisingIdClient.getAdvertisingIdInfo(
-                                context).get();
-                assertThat(advertisingIdInfo.getId()).isEqualTo(DUMMY_AD_ID);
-            } catch (Exception e) {
-                return Result.failure();
-            }
-            return Result.success();
-        }
-    }
-
-    @Test
-    @SuppressWarnings("deprecation") /* AsyncTask */
-    public void getAdvertisingIdInfo_asyncTask() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
-        while (state.keepRunning()) {
-            androidx.ads.identifier.AdvertisingIdInfo advertisingIdInfo =
-                    new android.os.AsyncTask<Void, Void,
-                            androidx.ads.identifier.AdvertisingIdInfo>() {
-                        @Override
-                        protected androidx.ads.identifier.AdvertisingIdInfo doInBackground(
-                                Void... voids) {
-                            try {
-                                return androidx.ads.identifier.AdvertisingIdClient
-                                        .getAdvertisingIdInfo(mContext).get();
-                            } catch (Exception e) {
-                                throw new RuntimeException(e);
-                            }
-                        }
-                    }.execute().get();
-            assertThat(advertisingIdInfo.getId()).isEqualTo(DUMMY_AD_ID);
-        }
-    }
-
-    @Test
-    public void getAdvertisingIdInfo_thread() throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
-        while (state.keepRunning()) {
-            Thread thread = new Thread(() -> {
-                try {
-                    androidx.ads.identifier.AdvertisingIdInfo advertisingIdInfo =
-                            androidx.ads.identifier.AdvertisingIdClient.getAdvertisingIdInfo(
-                                    mContext).get();
-                    assertThat(advertisingIdInfo.getId()).isEqualTo(DUMMY_AD_ID);
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
-            });
-            thread.start();
-            thread.join();
-        }
-    }
-
-    @Test
-    public void getAdvertisingIdInfo_concurrency() throws Exception {
-        getAdvertisingIdInfo_concurrencyWithDelay(0);
-    }
-
-    @Test
-    public void getAdvertisingIdInfo_concurrencyWithDelay1Millis() throws Exception {
-        getAdvertisingIdInfo_concurrencyWithDelay(1);
-    }
-
-    @Test
-    public void getAdvertisingIdInfo_concurrencyWithDelay10Millis() throws Exception {
-        getAdvertisingIdInfo_concurrencyWithDelay(10);
-    }
-
-    private void getAdvertisingIdInfo_concurrencyWithDelay(long millis) throws Exception {
-        final BenchmarkState state = mBenchmarkRule.getState();
-        while (state.keepRunning()) {
-            CountDownLatch countDownLatch = new CountDownLatch(CONCURRENCY_NUM);
-            for (int i = 0; i < CONCURRENCY_NUM; i++) {
-                if (millis != 0) {
-                    Thread.sleep(millis);
-                }
-
-                getAdvertisingIdInfoListenableFuture(countDownLatch);
-            }
-            countDownLatch.await();
-        }
-    }
-}
diff --git a/ads/ads-identifier-benchmark/src/androidTest/java/androidx/ads/identifier/benchmark/SampleAdvertisingIdProvider.java b/ads/ads-identifier-benchmark/src/androidTest/java/androidx/ads/identifier/benchmark/SampleAdvertisingIdProvider.java
deleted file mode 100644
index b53b1be..0000000
--- a/ads/ads-identifier-benchmark/src/androidTest/java/androidx/ads/identifier/benchmark/SampleAdvertisingIdProvider.java
+++ /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.ads.identifier.benchmark;
-
-import androidx.annotation.NonNull;
-
-/** An example Advertising ID Provider which always returns same ID. */
-@SuppressWarnings("deprecation")
-public class SampleAdvertisingIdProvider implements
-        androidx.ads.identifier.provider.AdvertisingIdProvider {
-
-    static final String DUMMY_AD_ID = "308f629d-c857-4026-8b62-7bdd71caaaaa";
-
-    @NonNull
-    @Override
-    public String getId() {
-        return DUMMY_AD_ID;
-    }
-
-    @Override
-    public boolean isLimitAdTrackingEnabled() {
-        return false;
-    }
-}
diff --git a/ads/ads-identifier-benchmark/src/main/AndroidManifest.xml b/ads/ads-identifier-benchmark/src/main/AndroidManifest.xml
deleted file mode 100644
index cc0959e..0000000
--- a/ads/ads-identifier-benchmark/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 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.
-  -->
-
-<manifest />
diff --git a/ads/ads-identifier-common/api/current.txt b/ads/ads-identifier-common/api/current.txt
deleted file mode 100644
index e6f50d0..0000000
--- a/ads/ads-identifier-common/api/current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 4.0
diff --git a/ads/ads-identifier-common/api/public_plus_experimental_current.txt b/ads/ads-identifier-common/api/public_plus_experimental_current.txt
deleted file mode 100644
index e6f50d0..0000000
--- a/ads/ads-identifier-common/api/public_plus_experimental_current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 4.0
diff --git a/ads/ads-identifier-common/api/res-current.txt b/ads/ads-identifier-common/api/res-current.txt
deleted file mode 100644
index e69de29..0000000
--- a/ads/ads-identifier-common/api/res-current.txt
+++ /dev/null
diff --git a/ads/ads-identifier-common/api/restricted_current.txt b/ads/ads-identifier-common/api/restricted_current.txt
deleted file mode 100644
index e5c37ac..0000000
--- a/ads/ads-identifier-common/api/restricted_current.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-// Signature format: 4.0
-package androidx.ads.identifier {
-
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public class AdvertisingIdUtils {
-    method public static java.util.List<android.content.pm.ServiceInfo!> getAdvertisingIdProviderServices(android.content.pm.PackageManager);
-    method public static android.content.pm.ServiceInfo? selectServiceByPriority(java.util.List<android.content.pm.ServiceInfo!>, android.content.pm.PackageManager);
-    field public static final String GET_AD_ID_ACTION = "androidx.ads.identifier.provider.GET_AD_ID";
-  }
-
-}
-
diff --git a/ads/ads-identifier-common/build.gradle b/ads/ads-identifier-common/build.gradle
deleted file mode 100644
index c753038..0000000
--- a/ads/ads-identifier-common/build.gradle
+++ /dev/null
@@ -1,49 +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.
- */
-
-import androidx.build.Publish
-
-plugins {
-    id("AndroidXPlugin")
-    id("com.android.library")
-}
-
-dependencies {
-    api("androidx.annotation:annotation:1.1.0")
-
-    testImplementation(project(":ads:ads-identifier-testing"))
-    testImplementation(libs.testRunner)
-    testImplementation(libs.junit)
-    testImplementation(libs.truth)
-    testImplementation(libs.mockitoCore4)
-    testImplementation(libs.robolectric)
-}
-
-android {
-    buildFeatures {
-        aidl = true
-    }
-    testOptions.unitTests.includeAndroidResources = true
-    namespace "androidx.ads.identifier.common"
-}
-
-androidx {
-    name = "AndroidX Ads Identifier Common"
-    publish = Publish.SNAPSHOT_AND_RELEASE
-    mavenVersion = LibraryVersions.ADS_IDENTIFIER
-    inceptionYear = "2019"
-    description = "AndroidX Ads Identifier Common"
-}
diff --git a/ads/ads-identifier-common/lint-baseline.xml b/ads/ads-identifier-common/lint-baseline.xml
deleted file mode 100644
index 6230722..0000000
--- a/ads/ads-identifier-common/lint-baseline.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
-
-    <issue
-        id="PrivateConstructorForUtilityClass"
-        message="Utility class is missing private constructor"
-        errorLine1="public class AdvertisingIdUtils {"
-        errorLine2="             ~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/ads/identifier/AdvertisingIdUtils.java"/>
-    </issue>
-
-</issues>
diff --git a/ads/ads-identifier-common/src/main/AndroidManifest.xml b/ads/ads-identifier-common/src/main/AndroidManifest.xml
deleted file mode 100644
index d2c9474..0000000
--- a/ads/ads-identifier-common/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android">
-</manifest>
diff --git a/ads/ads-identifier-common/src/main/aidl/androidx/ads/identifier/provider/IAdvertisingIdService.aidl b/ads/ads-identifier-common/src/main/aidl/androidx/ads/identifier/provider/IAdvertisingIdService.aidl
deleted file mode 100644
index c5bdc98..0000000
--- a/ads/ads-identifier-common/src/main/aidl/androidx/ads/identifier/provider/IAdvertisingIdService.aidl
+++ /dev/null
@@ -1,13 +0,0 @@
-package androidx.ads.identifier.provider;
-
-/**
- * The Advertising ID service used to communicate between an Advertising ID Provider and the
- * developer library.
- *
- * <p>The Advertising ID is a resettable identifier used for ads purpose.
- * @hide
- */
-interface IAdvertisingIdService {
-    String getId() = 0;
-    boolean isLimitAdTrackingEnabled() = 1;
-}
diff --git a/ads/ads-identifier-common/src/main/java/androidx/ads/identifier/AdvertisingIdUtils.java b/ads/ads-identifier-common/src/main/java/androidx/ads/identifier/AdvertisingIdUtils.java
deleted file mode 100644
index 6423a69..0000000
--- a/ads/ads-identifier-common/src/main/java/androidx/ads/identifier/AdvertisingIdUtils.java
+++ /dev/null
@@ -1,176 +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.ads.identifier;
-
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.os.Build;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
-import androidx.annotation.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Internal utilities for Advertising ID.
- *
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class AdvertisingIdUtils {
-
-    /**
-     * The Intent action used to identify an Advertising ID Provider. The Advertising ID Provider
-     * Service should declare this as an intent-filter, so that clients can find it.
-     */
-    public static final String GET_AD_ID_ACTION = "androidx.ads.identifier.provider.GET_AD_ID";
-
-    /**
-     * The permission used to indicate which Advertising ID Provider should be used in case there
-     * are multiple Advertising ID Providers on the device. Device manufacturer (OEM) should only
-     * grant this permission to the designated Advertising ID Provider.
-     */
-    @VisibleForTesting
-    static final String HIGH_PRIORITY_PERMISSION = "androidx.ads.identifier.provider.HIGH_PRIORITY";
-
-    AdvertisingIdUtils() {
-    }
-
-    /**
-     * Retrieves a list of all Advertising ID Providers' services on this device.
-     *
-     * <p>This is achieved by looking up which services can handle {@link #GET_AD_ID_ACTION}
-     * intent action.
-     * <p>Only system-level providers will be returned.
-     */
-    @NonNull
-    @SuppressWarnings({"MixedMutabilityReturnType", "deprecation"})
-    public static List<ServiceInfo> getAdvertisingIdProviderServices(
-            @NonNull PackageManager packageManager) {
-        Intent intent = new Intent(GET_AD_ID_ACTION);
-
-        List<ResolveInfo> resolveInfos =
-                packageManager.queryIntentServices(intent,
-                        Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
-                                ? PackageManager.MATCH_SYSTEM_ONLY : 0);
-        if (resolveInfos == null || resolveInfos.isEmpty()) {
-            return Collections.emptyList();
-        }
-        List<ServiceInfo> systemLevelServiceInfos = new ArrayList<>();
-        for (ResolveInfo resolveInfo : resolveInfos) {
-            ServiceInfo serviceInfo = resolveInfo.serviceInfo;
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
-                    || isSystemByApplicationInfo(serviceInfo.packageName, packageManager)) {
-                systemLevelServiceInfos.add(serviceInfo);
-            }
-        }
-        return systemLevelServiceInfos;
-    }
-
-    @SuppressWarnings("deprecation")
-    private static boolean isSystemByApplicationInfo(
-            @NonNull String packageName, @NonNull PackageManager packageManager) {
-        try {
-            ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName, 0);
-            return (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-        } catch (PackageManager.NameNotFoundException ignored) {
-            // Ignore this provider if name not found.
-            return false;
-        }
-    }
-
-    /**
-     * Selects the Service of an Advertising ID Provider which should be used by developer
-     * library when requesting an Advertising ID.
-     *
-     * <p>Note: This method should only be used with the {@link ServiceInfo}s from
-     * {@link #getAdvertisingIdProviderServices} method, this currently means that only
-     * system-level Providers will be selected.
-     * <p>It will return the same Advertising ID Provider for all apps which use the developer
-     * library, using this priority:
-     * <ol>
-     * <li>Providers with {@link #HIGH_PRIORITY_PERMISSION} permission
-     * <li>Other Providers
-     * </ol>
-     * <p>If there are ties in any of the above categories, it will use this priority:
-     * <ol>
-     * <li>First app by earliest install time ({@link PackageInfo#firstInstallTime})
-     * <li>First app by package name alphabetically sorted
-     * </ol>
-     *
-     * @return null if the input {@code serviceInfos} is null or empty, or non of the input
-     * package is found.
-     */
-    @Nullable
-    @SuppressWarnings("deprecation")
-    public static ServiceInfo selectServiceByPriority(
-            @NonNull List<ServiceInfo> serviceInfos, @NonNull PackageManager packageManager) {
-        if (serviceInfos.isEmpty()) {
-            return null;
-        }
-        ServiceInfo selectedServiceInfo = null;
-        PackageInfo selectedPackageInfo = null;
-        for (ServiceInfo serviceInfo : serviceInfos) {
-            PackageInfo packageInfo;
-            try {
-                packageInfo =
-                        packageManager.getPackageInfo(
-                                serviceInfo.packageName, PackageManager.GET_PERMISSIONS);
-            } catch (PackageManager.NameNotFoundException ignored) {
-                // Ignore this provider if name not found.
-                continue;
-            }
-            if (selectedPackageInfo == null
-                    || hasHigherPriority(packageInfo, selectedPackageInfo)) {
-                selectedServiceInfo = serviceInfo;
-                selectedPackageInfo = packageInfo;
-            }
-        }
-        return selectedServiceInfo;
-    }
-
-    private static boolean hasHigherPriority(PackageInfo candidate, PackageInfo currentHighest) {
-        boolean isCandidateRequestHighPriority = isRequestHighPriority(candidate);
-        boolean isCurrentHighestRequestHighPriority = isRequestHighPriority(currentHighest);
-        if (isCandidateRequestHighPriority != isCurrentHighestRequestHighPriority) {
-            return isCandidateRequestHighPriority;
-        }
-        if (candidate.firstInstallTime != currentHighest.firstInstallTime) {
-            return candidate.firstInstallTime < currentHighest.firstInstallTime;
-        }
-        return candidate.packageName.compareTo(currentHighest.packageName) < 0;
-    }
-
-    private static boolean isRequestHighPriority(PackageInfo packageInfo) {
-        if (packageInfo.requestedPermissions == null) {
-            return false;
-        }
-        for (String permission : packageInfo.requestedPermissions) {
-            if (HIGH_PRIORITY_PERMISSION.equals(permission)) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/ads/ads-identifier-common/src/test/java/androidx/ads/identifier/AdvertisingIdUtilsTest.java b/ads/ads-identifier-common/src/test/java/androidx/ads/identifier/AdvertisingIdUtilsTest.java
deleted file mode 100644
index 50f7933..0000000
--- a/ads/ads-identifier-common/src/test/java/androidx/ads/identifier/AdvertisingIdUtilsTest.java
+++ /dev/null
@@ -1,149 +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.ads.identifier;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-
-import com.google.common.collect.Lists;
-
-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.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-@DoNotInstrument
-public class AdvertisingIdUtilsTest {
-
-    private PackageManager mPackageManager;
-
-    @Before
-    public void setUp() {
-        mPackageManager = mock(PackageManager.class);
-    }
-
-    @Test
-    public void selectServiceByPriority() throws Exception {
-        List<ServiceInfo> serviceInfos = Lists.newArrayList(
-                createServiceInfo("c.normal.1", false, 1),
-                createServiceInfo("y.normal.0", false, 0),
-                createServiceInfo("x.normal.0", false, 0),
-                createServiceInfo("z.high.2", true, 2));
-
-        List<String> priorityList = getPriorityList(serviceInfos);
-
-        assertThat(priorityList).containsExactly(
-                "z.high.2",
-                "x.normal.0",
-                "y.normal.0",
-                "c.normal.1"
-        ).inOrder();
-    }
-
-    @Test
-    public void selectServiceByPriority_firstInstallTime() throws Exception {
-        List<ServiceInfo> serviceInfos = Lists.newArrayList(
-                createServiceInfo("com.a", false, 2),
-                createServiceInfo("com.b", false, 9),
-                createServiceInfo("com.c", false, 7),
-                createServiceInfo("com.d", false, 10),
-                createServiceInfo("com.e", false, 0));
-
-        List<String> priorityList = getPriorityList(serviceInfos);
-
-        assertThat(priorityList).containsExactly(
-                "com.e",
-                "com.a",
-                "com.c",
-                "com.b",
-                "com.d"
-        ).inOrder();
-    }
-
-    @Test
-    public void selectServiceByPriority_packageName() throws Exception {
-        List<ServiceInfo> serviceInfos = Lists.newArrayList(
-                createServiceInfo("com.abc.id", false, 0),
-                createServiceInfo("com.abc", false, 0),
-                createServiceInfo("org.example", false, 0),
-                createServiceInfo("com.abcde", false, 0),
-                createServiceInfo("com.abcde_id", false, 0));
-
-        List<String> priorityList = getPriorityList(serviceInfos);
-
-        assertThat(priorityList).containsExactly(
-                "com.abc",
-                "com.abc.id",
-                "com.abcde",
-                "com.abcde_id",
-                "org.example"
-        ).inOrder();
-    }
-
-    private List<String> getPriorityList(List<ServiceInfo> serviceInfos) {
-        List<String> result = new ArrayList<>();
-        while (serviceInfos.size() > 0) {
-            final ServiceInfo serviceInfo =
-                    AdvertisingIdUtils.selectServiceByPriority(serviceInfos, mPackageManager);
-
-            result.add(serviceInfo.packageName);
-
-            serviceInfos.remove(serviceInfo);
-        }
-        return result;
-    }
-
-    @Test
-    public void selectServiceByPriority_inputEmpty() {
-        ServiceInfo serviceInfo = AdvertisingIdUtils.selectServiceByPriority(
-                Collections.emptyList(), mPackageManager);
-
-        assertThat(serviceInfo).isNull();
-    }
-
-    @SuppressWarnings("deprecation")
-    private ServiceInfo createServiceInfo(String packageName, boolean requestHighPriority,
-            long firstInstallTime) throws Exception {
-        PackageInfo packageInfo = new PackageInfo();
-        packageInfo.packageName = packageName;
-        if (requestHighPriority) {
-            packageInfo.requestedPermissions =
-                    new String[]{AdvertisingIdUtils.HIGH_PRIORITY_PERMISSION};
-        }
-        packageInfo.firstInstallTime = firstInstallTime;
-
-        when(mPackageManager.getPackageInfo(eq(packageName), eq(PackageManager.GET_PERMISSIONS)))
-                .thenReturn(packageInfo);
-
-        ServiceInfo serviceInfo = mock(ServiceInfo.class);
-        serviceInfo.packageName = packageName;
-        return serviceInfo;
-    }
-}
diff --git a/ads/ads-identifier-common/src/test/resources/robolectric.properties b/ads/ads-identifier-common/src/test/resources/robolectric.properties
deleted file mode 100644
index 7946f01..0000000
--- a/ads/ads-identifier-common/src/test/resources/robolectric.properties
+++ /dev/null
@@ -1 +0,0 @@
-# robolectric properties
\ No newline at end of file
diff --git a/ads/ads-identifier-provider/api/current.txt b/ads/ads-identifier-provider/api/current.txt
deleted file mode 100644
index 19e5667..0000000
--- a/ads/ads-identifier-provider/api/current.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-// Signature format: 4.0
-package androidx.ads.identifier.provider {
-
-  @Deprecated public interface AdvertisingIdProvider {
-    method @Deprecated public String getId();
-    method @Deprecated public boolean isLimitAdTrackingEnabled();
-  }
-
-  @Deprecated @com.google.auto.value.AutoValue @com.google.auto.value.AutoValue.CopyAnnotations public abstract class AdvertisingIdProviderInfo {
-    method @Deprecated public abstract String getPackageName();
-    method @Deprecated public abstract android.content.Intent? getSettingsIntent();
-    method @Deprecated public abstract boolean isHighestPriority();
-  }
-
-  @Deprecated public class AdvertisingIdProviderManager {
-    method @Deprecated public static java.util.List<androidx.ads.identifier.provider.AdvertisingIdProviderInfo!> getAdvertisingIdProviders(android.content.Context);
-    method @Deprecated public static void registerProviderCallable(java.util.concurrent.Callable<androidx.ads.identifier.provider.AdvertisingIdProvider!>);
-  }
-
-}
-
diff --git a/ads/ads-identifier-provider/api/public_plus_experimental_current.txt b/ads/ads-identifier-provider/api/public_plus_experimental_current.txt
deleted file mode 100644
index 19e5667..0000000
--- a/ads/ads-identifier-provider/api/public_plus_experimental_current.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-// Signature format: 4.0
-package androidx.ads.identifier.provider {
-
-  @Deprecated public interface AdvertisingIdProvider {
-    method @Deprecated public String getId();
-    method @Deprecated public boolean isLimitAdTrackingEnabled();
-  }
-
-  @Deprecated @com.google.auto.value.AutoValue @com.google.auto.value.AutoValue.CopyAnnotations public abstract class AdvertisingIdProviderInfo {
-    method @Deprecated public abstract String getPackageName();
-    method @Deprecated public abstract android.content.Intent? getSettingsIntent();
-    method @Deprecated public abstract boolean isHighestPriority();
-  }
-
-  @Deprecated public class AdvertisingIdProviderManager {
-    method @Deprecated public static java.util.List<androidx.ads.identifier.provider.AdvertisingIdProviderInfo!> getAdvertisingIdProviders(android.content.Context);
-    method @Deprecated public static void registerProviderCallable(java.util.concurrent.Callable<androidx.ads.identifier.provider.AdvertisingIdProvider!>);
-  }
-
-}
-
diff --git a/ads/ads-identifier-provider/api/res-current.txt b/ads/ads-identifier-provider/api/res-current.txt
deleted file mode 100644
index e69de29..0000000
--- a/ads/ads-identifier-provider/api/res-current.txt
+++ /dev/null
diff --git a/ads/ads-identifier-provider/api/restricted_current.txt b/ads/ads-identifier-provider/api/restricted_current.txt
deleted file mode 100644
index 19e5667..0000000
--- a/ads/ads-identifier-provider/api/restricted_current.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-// Signature format: 4.0
-package androidx.ads.identifier.provider {
-
-  @Deprecated public interface AdvertisingIdProvider {
-    method @Deprecated public String getId();
-    method @Deprecated public boolean isLimitAdTrackingEnabled();
-  }
-
-  @Deprecated @com.google.auto.value.AutoValue @com.google.auto.value.AutoValue.CopyAnnotations public abstract class AdvertisingIdProviderInfo {
-    method @Deprecated public abstract String getPackageName();
-    method @Deprecated public abstract android.content.Intent? getSettingsIntent();
-    method @Deprecated public abstract boolean isHighestPriority();
-  }
-
-  @Deprecated public class AdvertisingIdProviderManager {
-    method @Deprecated public static java.util.List<androidx.ads.identifier.provider.AdvertisingIdProviderInfo!> getAdvertisingIdProviders(android.content.Context);
-    method @Deprecated public static void registerProviderCallable(java.util.concurrent.Callable<androidx.ads.identifier.provider.AdvertisingIdProvider!>);
-  }
-
-}
-
diff --git a/ads/ads-identifier-provider/build.gradle b/ads/ads-identifier-provider/build.gradle
deleted file mode 100644
index 395eea7..0000000
--- a/ads/ads-identifier-provider/build.gradle
+++ /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.
- */
-
-import androidx.build.Publish
-
-plugins {
-    id("AndroidXPlugin")
-    id("com.android.library")
-}
-
-dependencies {
-    api("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0")
-    implementation(libs.autoValueAnnotations)
-    annotationProcessor(libs.autoValue)
-
-    implementation(project(":ads:ads-identifier-common"))
-
-    androidTestImplementation(project(":ads:ads-identifier-testing"))
-    androidTestImplementation(libs.junit)
-    androidTestImplementation(libs.truth)
-    androidTestImplementation(libs.testExtJunit)
-    androidTestImplementation(libs.testCore)
-    androidTestImplementation(libs.testRunner)
-    androidTestImplementation(libs.testRules)
-    androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy)
-}
-
-androidx {
-    name = "AndroidX Ads Identifier Provider"
-    publish = Publish.SNAPSHOT_AND_RELEASE
-    mavenVersion = LibraryVersions.ADS_IDENTIFIER
-    inceptionYear = "2019"
-    description = "AndroidX Ads Identifier Provider"
-}
-
-android {
-    namespace "androidx.ads.identifier.provider"
-}
diff --git a/ads/ads-identifier-provider/integration-tests/testapp/build.gradle b/ads/ads-identifier-provider/integration-tests/testapp/build.gradle
deleted file mode 100644
index a03737b..0000000
--- a/ads/ads-identifier-provider/integration-tests/testapp/build.gradle
+++ /dev/null
@@ -1,33 +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.
- */
-plugins {
-    id("AndroidXPlugin")
-    id("com.android.application")
-}
-
-android {
-    defaultConfig {
-        applicationId "androidx.ads.identifier.provider.testapp"
-        minSdkVersion 14
-    }
-    namespace "androidx.ads.identifier.provider.testapp"
-}
-
-dependencies {
-    implementation(project(":ads:ads-identifier-provider"))
-    implementation("androidx.recyclerview:recyclerview:1.0.0")
-    api("androidx.annotation:annotation:1.1.0")
-}
diff --git a/ads/ads-identifier-provider/integration-tests/testapp/lint-baseline.xml b/ads/ads-identifier-provider/integration-tests/testapp/lint-baseline.xml
deleted file mode 100644
index 0160194..0000000
--- a/ads/ads-identifier-provider/integration-tests/testapp/lint-baseline.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                            ~~~~~~">
-        <location
-            file="src/main/java/androidx/ads/identifier/provider/testapp/AdsIdentifierProviderActivity.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void listProviders(View view) {"
-        errorLine2="                              ~~~~">
-        <location
-            file="src/main/java/androidx/ads/identifier/provider/testapp/AdsIdentifierProviderActivity.java"/>
-    </issue>
-
-</issues>
diff --git a/ads/ads-identifier-provider/integration-tests/testapp/src/main/AndroidManifest.xml b/ads/ads-identifier-provider/integration-tests/testapp/src/main/AndroidManifest.xml
deleted file mode 100644
index ac86787..0000000
--- a/ads/ads-identifier-provider/integration-tests/testapp/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools">
-
-    <application
-        android:name=".AdsIdentifierProviderApplication"
-        android:allowBackup="false"
-        android:label="@string/app_name"
-        tools:ignore="GoogleAppIndexingWarning,MissingApplicationIcon">
-
-        <activity
-            android:name=".AdsIdentifierProviderActivity"
-            android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-
-</manifest>
diff --git a/ads/ads-identifier-provider/integration-tests/testapp/src/main/java/androidx/ads/identifier/provider/testapp/AdsIdentifierProviderActivity.java b/ads/ads-identifier-provider/integration-tests/testapp/src/main/java/androidx/ads/identifier/provider/testapp/AdsIdentifierProviderActivity.java
deleted file mode 100644
index ebdad4d..0000000
--- a/ads/ads-identifier-provider/integration-tests/testapp/src/main/java/androidx/ads/identifier/provider/testapp/AdsIdentifierProviderActivity.java
+++ /dev/null
@@ -1,126 +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.ads.identifier.provider.testapp;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
-
-import androidx.ads.identifier.provider.AdvertisingIdProviderInfo;
-import androidx.ads.identifier.provider.AdvertisingIdProviderManager;
-import androidx.annotation.NonNull;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Simple activity as an Advertising ID Provider.
- */
-public class AdsIdentifierProviderActivity extends Activity {
-
-    private Adapter mAdapter;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_ads_identifier_provider);
-
-        RecyclerView recyclerView = findViewById(R.id.recycler_view);
-        recyclerView.setLayoutManager(new LinearLayoutManager(this));
-
-        mAdapter = new Adapter();
-        recyclerView.setAdapter(mAdapter);
-    }
-
-    /** Lists all the Advertising ID Providers. */
-    public void listProviders(View view) {
-        List<AdvertisingIdProviderInfo> allAdIdProviders =
-                AdvertisingIdProviderManager.getAdvertisingIdProviders(this);
-
-        TextView textView = findViewById(R.id.main_text);
-        textView.setText("There are " + allAdIdProviders.size() + " provider(s) on the device.\n");
-
-        mAdapter.setAdvertisingIdProviderInfoList(allAdIdProviders);
-    }
-
-    static class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
-
-        private List<AdvertisingIdProviderInfo> mAdvertisingIdProviderInfoList;
-
-        static class ViewHolder extends RecyclerView.ViewHolder {
-            @NonNull
-            TextView mTextView;
-            @NonNull
-            Button mButton;
-
-            ViewHolder(@NonNull View view) {
-                super(view);
-                mTextView = view.findViewById(R.id.text);
-                mButton = view.findViewById(R.id.button);
-            }
-        }
-
-        Adapter() {
-            mAdvertisingIdProviderInfoList = Collections.emptyList();
-        }
-
-        void setAdvertisingIdProviderInfoList(
-                List<AdvertisingIdProviderInfo> advertisingIdProviderInfoList) {
-            mAdvertisingIdProviderInfoList = advertisingIdProviderInfoList;
-            notifyDataSetChanged();
-        }
-
-        @NonNull
-        @Override
-        public Adapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
-            View view = inflater.inflate(R.layout.provider_info, parent, false);
-            return new ViewHolder(view);
-        }
-
-        @Override
-        public void onBindViewHolder(@NonNull Adapter.ViewHolder holder, int position) {
-            AdvertisingIdProviderInfo providerInfo = mAdvertisingIdProviderInfoList.get(position);
-            TextView textView = holder.mTextView;
-            textView.setText("Package name: " + providerInfo.getPackageName() + "\n");
-
-            textView.append("Settings UI intent: " + providerInfo.getSettingsIntent() + "\n");
-            if (providerInfo.getSettingsIntent() != null) {
-                holder.mButton.setClickable(true);
-                holder.mButton.setOnClickListener(view -> {
-                    view.getContext().startActivity(providerInfo.getSettingsIntent());
-                });
-            } else {
-                holder.mButton.setClickable(false);
-                textView.append(textView.getResources().getString(R.string.empty_settings_warning));
-            }
-
-            textView.append("Is highest priority: " + providerInfo.isHighestPriority() + "\n");
-        }
-
-        @Override
-        public int getItemCount() {
-            return mAdvertisingIdProviderInfoList.size();
-        }
-    }
-}
diff --git a/ads/ads-identifier-provider/integration-tests/testapp/src/main/java/androidx/ads/identifier/provider/testapp/AdsIdentifierProviderApplication.java b/ads/ads-identifier-provider/integration-tests/testapp/src/main/java/androidx/ads/identifier/provider/testapp/AdsIdentifierProviderApplication.java
deleted file mode 100644
index 77e2fea..0000000
--- a/ads/ads-identifier-provider/integration-tests/testapp/src/main/java/androidx/ads/identifier/provider/testapp/AdsIdentifierProviderApplication.java
+++ /dev/null
@@ -1,35 +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.ads.identifier.provider.testapp;
-
-import android.app.Application;
-
-import androidx.ads.identifier.provider.AdvertisingIdProviderManager;
-
-/**
- * This will show you how to make your own Advertising ID Provider for providing the developer
- * library an Advertising ID when requested by apps.
- */
-public class AdsIdentifierProviderApplication extends Application {
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-
-        AdvertisingIdProviderManager.registerProviderCallable(SampleAdvertisingIdProvider::new);
-    }
-}
diff --git a/ads/ads-identifier-provider/integration-tests/testapp/src/main/java/androidx/ads/identifier/provider/testapp/SampleAdvertisingIdProvider.java b/ads/ads-identifier-provider/integration-tests/testapp/src/main/java/androidx/ads/identifier/provider/testapp/SampleAdvertisingIdProvider.java
deleted file mode 100644
index fc5c2af..0000000
--- a/ads/ads-identifier-provider/integration-tests/testapp/src/main/java/androidx/ads/identifier/provider/testapp/SampleAdvertisingIdProvider.java
+++ /dev/null
@@ -1,35 +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.ads.identifier.provider.testapp;
-
-import androidx.ads.identifier.provider.AdvertisingIdProvider;
-import androidx.annotation.NonNull;
-
-/** An example Advertising ID Provider which always returns same ID. */
-public class SampleAdvertisingIdProvider implements AdvertisingIdProvider {
-
-    @NonNull
-    @Override
-    public String getId() {
-        return "308f629d-c857-4026-8b62-7bdd71caaaaa";
-    }
-
-    @Override
-    public boolean isLimitAdTrackingEnabled() {
-        return false;
-    }
-}
diff --git a/ads/ads-identifier-provider/integration-tests/testapp/src/main/res/layout/activity_ads_identifier_provider.xml b/ads/ads-identifier-provider/integration-tests/testapp/src/main/res/layout/activity_ads_identifier_provider.xml
deleted file mode 100644
index 9c36015..0000000
--- a/ads/ads-identifier-provider/integration-tests/testapp/src/main/res/layout/activity_ads_identifier_provider.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  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.
-  -->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    tools:context="androidx.ads.identifier.provider.testapp.AdsIdentifierProviderActivity">
-
-    <LinearLayout
-        style="?android:attr/buttonBarStyle"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal">
-
-        <Button
-            style="?android:attr/buttonBarButtonStyle"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:onClick="listProviders"
-            android:text="@string/list_providers" />
-    </LinearLayout>
-
-    <TextView
-        android:id="@+id/main_text"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="" />
-
-    <androidx.recyclerview.widget.RecyclerView
-        android:id="@+id/recycler_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:scrollbars="vertical"
-        tools:listitem="@layout/provider_info" />
-</LinearLayout>
diff --git a/ads/ads-identifier-provider/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml b/ads/ads-identifier-provider/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
deleted file mode 100644
index b738e32..0000000
--- a/ads/ads-identifier-provider/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  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.
-  -->
-
-<resources>
-    <string name="app_name">Ad ID Provider</string>
-    <string name="list_providers">List Providers</string>
-    <string name="settings">Settings</string>
-    <string name="empty_settings_warning">*WARNING*: This provider should mark its settings activity
-        with the intent androidx.ads.identifier.provider.OPEN_SETTINGS.\n</string>
-</resources>
\ No newline at end of file
diff --git a/ads/ads-identifier-provider/src/androidTest/java/androidx/ads/identifier/provider/AdvertisingIdProviderManagerTest.java b/ads/ads-identifier-provider/src/androidTest/java/androidx/ads/identifier/provider/AdvertisingIdProviderManagerTest.java
deleted file mode 100644
index b08c910..0000000
--- a/ads/ads-identifier-provider/src/androidTest/java/androidx/ads/identifier/provider/AdvertisingIdProviderManagerTest.java
+++ /dev/null
@@ -1,237 +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.ads.identifier.provider;
-
-import static androidx.ads.identifier.testing.MockPackageManagerHelper.createActivityResolveInfo;
-import static androidx.ads.identifier.testing.MockPackageManagerHelper.createServiceResolveInfo;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-
-import androidx.ads.identifier.testing.MockPackageManagerHelper;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import com.google.common.collect.Lists;
-import com.google.common.truth.Correspondence;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.Callable;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-@SuppressWarnings("deprecation")
-public class AdvertisingIdProviderManagerTest {
-
-    private static final Correspondence<AdvertisingIdProviderInfo, AdvertisingIdProviderInfo>
-            PROVIDER_INFO_EQUALITY = Correspondence.from(
-            AdvertisingIdProviderManagerTest::isProviderInfoEqual, "is equivalent to");
-
-    private MockPackageManagerHelper mMockPackageManagerHelper = new MockPackageManagerHelper();
-
-    private Context mContext;
-
-    @Before
-    public void setUp() {
-        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
-        mContext = new ContextWrapper(context) {
-            @Override
-            public PackageManager getPackageManager() {
-                return mMockPackageManagerHelper.getMockPackageManager();
-            }
-        };
-    }
-
-    @Test
-    public void getAllAdIdProviders_onlySelf() throws Exception {
-        mMockPackageManagerHelper.mockQueryGetAdIdServices(
-                Lists.newArrayList(createServiceResolveInfo(mContext.getPackageName())));
-
-        assertThat(AdvertisingIdProviderManager.getAdvertisingIdProviders(mContext))
-                .comparingElementsUsing(PROVIDER_INFO_EQUALITY)
-                .containsExactly(
-                        AdvertisingIdProviderInfo.builder()
-                                .setPackageName(mContext.getPackageName())
-                                .setHighestPriority(true)
-                                .build());
-    }
-
-    @Test
-    public void getAllAdIdProviders_noProvider() {
-        assertThat(AdvertisingIdProviderManager.getAdvertisingIdProviders(mContext)).isEmpty();
-    }
-
-    @Test
-    public void getAllAdIdProviders() throws Exception {
-        mMockPackageManagerHelper.mockQueryGetAdIdServices(
-                Lists.newArrayList(
-                        createServiceResolveInfo(mContext.getPackageName()),
-                        createServiceResolveInfo("com.a")));
-
-        assertThat(AdvertisingIdProviderManager.getAdvertisingIdProviders(mContext))
-                .comparingElementsUsing(PROVIDER_INFO_EQUALITY)
-                .containsExactly(
-                        AdvertisingIdProviderInfo.builder()
-                                .setPackageName(mContext.getPackageName())
-                                .setHighestPriority(true)
-                                .build(),
-                        AdvertisingIdProviderInfo.builder().setPackageName("com.a").build());
-    }
-
-    @Test
-    public void getAllAdIdProviders_withOpenIntent() throws Exception {
-        mMockPackageManagerHelper.mockQueryGetAdIdServices(
-                Lists.newArrayList(
-                        createServiceResolveInfo(mContext.getPackageName()),
-                        createServiceResolveInfo("com.a")));
-
-        mMockPackageManagerHelper.mockQueryOpenSettingsActivities(
-                Lists.newArrayList(
-                        createActivityResolveInfo(mContext.getPackageName(), "Activity"),
-                        createActivityResolveInfo("com.a", "A")));
-
-        assertThat(AdvertisingIdProviderManager.getAdvertisingIdProviders(mContext))
-                .comparingElementsUsing(PROVIDER_INFO_EQUALITY)
-                .containsExactly(
-                        AdvertisingIdProviderInfo.builder()
-                                .setPackageName(mContext.getPackageName())
-                                .setSettingsIntent(new Intent(
-                                        androidx.ads.identifier.provider
-                                                .AdvertisingIdProviderManager.OPEN_SETTINGS_ACTION)
-                                        .setClassName(mContext.getPackageName(), "Activity"))
-                                .setHighestPriority(true)
-                                .build(),
-                        AdvertisingIdProviderInfo.builder()
-                                .setPackageName("com.a")
-                                .setSettingsIntent(new Intent(
-                                        androidx.ads.identifier.provider
-                                                .AdvertisingIdProviderManager.OPEN_SETTINGS_ACTION)
-                                        .setClassName("com.a", "A"))
-                                .build());
-    }
-
-    @Test
-    public void getAllAdIdProviders_twoOtherProviders() throws Exception {
-        mMockPackageManagerHelper.mockQueryGetAdIdServices(
-                Lists.newArrayList(
-                        createServiceResolveInfo(mContext.getPackageName()),
-                        createServiceResolveInfo("com.a"),
-                        createServiceResolveInfo("com.b")));
-
-        mMockPackageManagerHelper.mockQueryOpenSettingsActivities(
-                Lists.newArrayList(
-                        createActivityResolveInfo(mContext.getPackageName(), "Activity"),
-                        createActivityResolveInfo("com.a", "A")));
-
-        assertThat(AdvertisingIdProviderManager.getAdvertisingIdProviders(mContext))
-                .comparingElementsUsing(PROVIDER_INFO_EQUALITY)
-                .containsExactly(
-                        AdvertisingIdProviderInfo.builder()
-                                .setPackageName(mContext.getPackageName())
-                                .setSettingsIntent(new Intent(
-                                        androidx.ads.identifier.provider
-                                                .AdvertisingIdProviderManager.OPEN_SETTINGS_ACTION)
-                                        .setClassName(mContext.getPackageName(), "Activity"))
-                                .setHighestPriority(true)
-                                .build(),
-                        AdvertisingIdProviderInfo.builder()
-                                .setPackageName("com.a")
-                                .setSettingsIntent(new Intent(
-                                        androidx.ads.identifier.provider
-                                                .AdvertisingIdProviderManager.OPEN_SETTINGS_ACTION)
-                                        .setClassName("com.a", "A"))
-                                .build(),
-                        AdvertisingIdProviderInfo.builder()
-                                .setPackageName("com.b")
-                                .build());
-    }
-
-    @Test
-    public void getAllAdIdProviders_extraOpenIntent() throws Exception {
-        mMockPackageManagerHelper.mockQueryGetAdIdServices(
-                Lists.newArrayList(
-                        createServiceResolveInfo(mContext.getPackageName()),
-                        createServiceResolveInfo("com.a")));
-
-        mMockPackageManagerHelper.mockQueryOpenSettingsActivities(
-                Lists.newArrayList(
-                        createActivityResolveInfo(mContext.getPackageName(), "Activity"),
-                        createActivityResolveInfo("com.a", "A"),
-                        createActivityResolveInfo("com.b", "B")));
-
-        assertThat(AdvertisingIdProviderManager.getAdvertisingIdProviders(mContext))
-                .comparingElementsUsing(PROVIDER_INFO_EQUALITY)
-                .containsExactly(
-                        AdvertisingIdProviderInfo.builder()
-                                .setPackageName(mContext.getPackageName())
-                                .setSettingsIntent(new Intent(
-                                        androidx.ads.identifier.provider
-                                                .AdvertisingIdProviderManager.OPEN_SETTINGS_ACTION)
-                                        .setClassName(mContext.getPackageName(), "Activity"))
-                                .setHighestPriority(true)
-                                .build(),
-                        AdvertisingIdProviderInfo.builder()
-                                .setPackageName("com.a")
-                                .setSettingsIntent(new Intent(
-                                        androidx.ads.identifier.provider
-                                                .AdvertisingIdProviderManager.OPEN_SETTINGS_ACTION)
-                                        .setClassName("com.a", "A"))
-                                .build());
-    }
-
-    @Test
-    public void registerProviderCallable() {
-        Callable<AdvertisingIdProvider> providerCallable = () -> null;
-
-        AdvertisingIdProviderManager.registerProviderCallable(providerCallable);
-
-        assertThat(AdvertisingIdProviderManager.getProviderCallable())
-                .isSameInstanceAs(providerCallable);
-    }
-
-    @Test(expected = NullPointerException.class)
-    public void registerProviderCallable_null() {
-        AdvertisingIdProviderManager.registerProviderCallable(null);
-    }
-
-    @Test
-    public void clearProviderCallable() {
-        Callable<AdvertisingIdProvider> providerCallable = () -> null;
-
-        AdvertisingIdProviderManager.registerProviderCallable(providerCallable);
-        AdvertisingIdProviderManager.clearProviderCallable();
-
-        assertThat(AdvertisingIdProviderManager.getProviderCallable()).isNull();
-    }
-
-    private static boolean isProviderInfoEqual(
-            AdvertisingIdProviderInfo actual, AdvertisingIdProviderInfo expected) {
-        return actual.getPackageName().equals(expected.getPackageName())
-                && (actual.getSettingsIntent() == null ? expected.getSettingsIntent() == null
-                : actual.getSettingsIntent().filterEquals(expected.getSettingsIntent()))
-                && actual.isHighestPriority() == expected.isHighestPriority();
-    }
-}
diff --git a/ads/ads-identifier-provider/src/androidTest/java/androidx/ads/identifier/provider/internal/AdvertisingIdServiceTest.java b/ads/ads-identifier-provider/src/androidTest/java/androidx/ads/identifier/provider/internal/AdvertisingIdServiceTest.java
deleted file mode 100644
index e34d9e8..0000000
--- a/ads/ads-identifier-provider/src/androidTest/java/androidx/ads/identifier/provider/internal/AdvertisingIdServiceTest.java
+++ /dev/null
@@ -1,166 +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.ads.identifier.provider.internal;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-
-import androidx.ads.identifier.AdvertisingIdUtils;
-import androidx.ads.identifier.provider.IAdvertisingIdService;
-import androidx.annotation.NonNull;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.concurrent.BlockingDeque;
-import java.util.concurrent.LinkedBlockingDeque;
-import java.util.concurrent.TimeUnit;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-@SuppressWarnings("deprecation")
-public class AdvertisingIdServiceTest {
-    private static final String TESTING_AD_ID = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee";
-
-    @Rule
-    public MockitoRule mMockitoRule = MockitoJUnit.rule();
-
-    private Context mContext;
-    private Intent mIntent;
-    private ServiceConnection mServiceConnection;
-
-    @Before
-    public void setUp() {
-        androidx.ads.identifier.provider.AdvertisingIdProviderManager.clearProviderCallable();
-
-        mContext = ApplicationProvider.getApplicationContext();
-
-        mIntent = new Intent(AdvertisingIdUtils.GET_AD_ID_ACTION);
-        mIntent.setClassName(mContext.getPackageName(), AdvertisingIdService.class.getName());
-    }
-
-    @After
-    public void tearDown() {
-        if (mServiceConnection != null) {
-            mContext.unbindService(mServiceConnection);
-        }
-        mContext.stopService(mIntent);
-    }
-
-    private IAdvertisingIdService getService() throws InterruptedException {
-        BlockingDeque<IAdvertisingIdService> blockingDeque = new LinkedBlockingDeque<>();
-        mServiceConnection = new ServiceConnection() {
-            @Override
-            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
-                blockingDeque.add(IAdvertisingIdService.Stub.asInterface(iBinder));
-            }
-
-            @Override
-            public void onServiceDisconnected(ComponentName componentName) {
-            }
-        };
-        mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
-        return blockingDeque.poll(1, TimeUnit.SECONDS);
-    }
-
-    @Test
-    public void getId() throws Exception {
-        androidx.ads.identifier.provider.AdvertisingIdProviderManager.registerProviderCallable(
-                () -> new MockAdvertisingIdProvider(TESTING_AD_ID, true));
-
-        IAdvertisingIdService service = getService();
-
-        assertThat(service.getId()).isEqualTo(TESTING_AD_ID);
-        assertThat(service.isLimitAdTrackingEnabled()).isEqualTo(true);
-    }
-
-    @Test(expected = RuntimeException.class)
-    public void getId_providerThrowsException() throws Exception {
-        androidx.ads.identifier.provider.AdvertisingIdProviderManager.registerProviderCallable(
-                () -> {
-                    MockAdvertisingIdProvider mockAdvertisingIdProvider =
-                            new MockAdvertisingIdProvider(TESTING_AD_ID, true);
-                    mockAdvertisingIdProvider.mGetIdThrowsException = true;
-                    return mockAdvertisingIdProvider;
-                });
-
-        IAdvertisingIdService service = getService();
-        service.getId();
-    }
-
-    private static class MockAdvertisingIdProvider implements
-            androidx.ads.identifier.provider.AdvertisingIdProvider {
-        private final String mId;
-        private final boolean mLimitAdTrackingEnabled;
-        boolean mGetIdThrowsException = false;
-
-        MockAdvertisingIdProvider(String id, boolean limitAdTrackingEnabled) {
-            mId = id;
-            mLimitAdTrackingEnabled = limitAdTrackingEnabled;
-        }
-
-        @NonNull
-        @Override
-        public String getId() {
-            if (mGetIdThrowsException) {
-                throw new RuntimeException();
-            }
-            return mId;
-        }
-
-        @Override
-        public boolean isLimitAdTrackingEnabled() {
-            return mLimitAdTrackingEnabled;
-        }
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void getId_providerNotRegistered() {
-        AdvertisingIdService.getAdvertisingIdProvider();
-    }
-
-    @Test(expected = RuntimeException.class)
-    public void getId_providerCallableThrowsException() {
-        androidx.ads.identifier.provider.AdvertisingIdProviderManager.registerProviderCallable(
-                () -> {
-                    throw new Exception();
-                });
-
-        AdvertisingIdService.getAdvertisingIdProvider();
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void getId_providerCallableReturnsNull() {
-        androidx.ads.identifier.provider.AdvertisingIdProviderManager.registerProviderCallable(
-                () -> null);
-
-        AdvertisingIdService.getAdvertisingIdProvider();
-    }
-}
diff --git a/ads/ads-identifier-provider/src/main/AndroidManifest.xml b/ads/ads-identifier-provider/src/main/AndroidManifest.xml
deleted file mode 100644
index da35f1a..0000000
--- a/ads/ads-identifier-provider/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools">
-
-    <application>
-        <service
-            android:name=".internal.AdvertisingIdService"
-            android:enabled="true"
-            android:exported="true"
-            android:visibleToInstantApps="true"
-            tools:ignore="ExportedService">
-            <intent-filter>
-                <action android:name="androidx.ads.identifier.provider.GET_AD_ID" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
-            <meta-data
-                android:name="instantapps.clients.allowed"
-                android:value="true" />
-        </service>
-    </application>
-</manifest>
diff --git a/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/AdvertisingIdProvider.java b/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/AdvertisingIdProvider.java
deleted file mode 100644
index 91728a9..0000000
--- a/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/AdvertisingIdProvider.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.ads.identifier.provider;
-
-import androidx.annotation.NonNull;
-
-/**
- * The class for the AndroidX Advertising ID Provider that should provide the resettable ID and
- * LAT preference should implement this interface.
- *
- * See {@link AdvertisingIdProviderManager} for more details.
- *
- * <p>Note: The implementation of this interface must be completely thread-safe.
- *
- * @deprecated Use the
- * <a href="https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient">
- * Advertising ID API that's available as part of Google Play Services</a> instead of this library.
- */
-@Deprecated
-public interface AdvertisingIdProvider {
-    /** Retrieves the Advertising ID. */
-    @NonNull
-    String getId();
-
-    /** Retrieves whether the user has chosen to limit ad tracking (ads personalization). */
-    boolean isLimitAdTrackingEnabled();
-}
diff --git a/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/AdvertisingIdProviderInfo.java b/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/AdvertisingIdProviderInfo.java
deleted file mode 100644
index b3094695..0000000
--- a/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/AdvertisingIdProviderInfo.java
+++ /dev/null
@@ -1,87 +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.ads.identifier.provider;
-
-import android.content.Intent;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.google.auto.value.AutoValue;
-
-/**
- * A {@link AdvertisingIdProviderInfo} represents the information about an Advertising ID Provider
- * installed on the device.
- *
- * <p>Used in cases when there are multiple Advertising ID Providers on the device. See
- * {@link AdvertisingIdProviderManager#getAdvertisingIdProviders} for more details.
- *
- * @deprecated Use the
- * <a href="https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient">
- * Advertising ID API that's available as part of Google Play Services</a> instead of this library.
- */
-@Deprecated
-@AutoValue
-@AutoValue.CopyAnnotations
-public abstract class AdvertisingIdProviderInfo {
-
-    // Create a no-args constructor so it doesn't appear in current.txt
-    AdvertisingIdProviderInfo() {
-    }
-
-    /** Retrieves the Advertising ID Provider package name. */
-    @NonNull
-    public abstract String getPackageName();
-
-    /**
-     * Retrieves the {@link Intent} to open the Advertising ID settings page for a given
-     * Advertising ID Provider.
-     *
-     * <p>This page should allow the user to reset Advertising IDs and change Limit Advertising
-     * Tracking preference.
-     */
-    @Nullable
-    public abstract Intent getSettingsIntent();
-
-    /**
-     * Retrieves whether the provider has the highest priority among all the providers for the
-     * developer library, meaning its provided ID will be used.
-     */
-    public abstract boolean isHighestPriority();
-
-    /** Create a {@link Builder}. */
-    static Builder builder() {
-        return new AutoValue_AdvertisingIdProviderInfo.Builder().setHighestPriority(false);
-    }
-
-    /** The builder for {@link AdvertisingIdProviderInfo}. */
-    @AutoValue.Builder
-    abstract static class Builder {
-
-        // Create a no-args constructor so it doesn't appear in current.txt
-        Builder() {
-        }
-
-        abstract Builder setPackageName(String packageName);
-
-        abstract Builder setSettingsIntent(Intent settingsIntent);
-
-        abstract Builder setHighestPriority(boolean highestPriority);
-
-        abstract AdvertisingIdProviderInfo build();
-    }
-}
diff --git a/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/AdvertisingIdProviderManager.java b/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/AdvertisingIdProviderManager.java
deleted file mode 100644
index 844e7f3..0000000
--- a/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/AdvertisingIdProviderManager.java
+++ /dev/null
@@ -1,164 +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.ads.identifier.provider;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-
-import androidx.ads.identifier.AdvertisingIdUtils;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
-import androidx.annotation.VisibleForTesting;
-import androidx.core.util.Preconditions;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Callable;
-
-/**
- * The AdvertisingIdProviderManager will be used by an Advertising ID Provider to register the
- * provider implementation or retrieve all the Advertising ID Providers on the device.
- *
- * This package contains an implementation of the Advertising ID Provider Service that supports
- * IAdvertisingIdService.aidl for communication with the developer library, allowing you to
- * easily make your own Advertising ID Provider. Simply do the following:
- * <ol>
- * <li>Implement the {@link AdvertisingIdProvider} interface in the provider library. Developer apps
- * will be interacting with the provider through this programmatic interface.
- * <li>Register the implementation by calling {@link #registerProviderCallable} within the
- * provider’s {@link android.app.Application#onCreate} callback.
- * <li>Register the Advertising Id settings UI with the intent filter
- * "androidx.ads.identifier.provider.OPEN_SETTINGS".
- * </ol>
- *
- * @deprecated Use the
- * <a href="https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient">
- * Advertising ID API that's available as part of Google Play Services</a> instead of this library.
- */
-@Deprecated
-public class AdvertisingIdProviderManager {
-
-    @VisibleForTesting
-    static final String OPEN_SETTINGS_ACTION = "androidx.ads.identifier.provider.OPEN_SETTINGS";
-
-    private static Callable<AdvertisingIdProvider> sProviderCallable = null;
-
-    private AdvertisingIdProviderManager() {
-    }
-
-    /**
-     * Registers the {@link Callable} to create an instance of {@link AdvertisingIdProvider}.
-     *
-     * <p>This is used to lazy load the {@link AdvertisingIdProvider} when the Service is started.
-     * <p>This {@link Callable} will be called within the library's built-in Advertising ID
-     * Service's {@link android.app.Service#onCreate} method.
-     * <p>Provider could call this method to register the implementation in
-     * {@link android.app.Application#onCreate}, which is before
-     * {@link android.app.Service#onCreate} has been called.
-     */
-    public static void registerProviderCallable(
-            @NonNull Callable<AdvertisingIdProvider> providerCallable) {
-        sProviderCallable = Preconditions.checkNotNull(providerCallable);
-    }
-
-    /**
-     * Gets the {@link Callable} to create the Advertising ID Provider.
-     *
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    @Nullable
-    public static Callable<AdvertisingIdProvider> getProviderCallable() {
-        return sProviderCallable;
-    }
-
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    @VisibleForTesting
-    public static void clearProviderCallable() {
-        sProviderCallable = null;
-    }
-
-    /**
-     * Retrieves a list of all the Advertising ID Providers' information on this device, including
-     * self and other providers which is based on the AndroidX Advertising ID Provider library.
-     *
-     * <p>This method helps one Advertising ID Provider find other providers. One usage of this is
-     * to link to other providers' settings activity from one provider's settings activity, so the
-     * user of the device can manager all the providers' settings together.
-     */
-    @NonNull
-    @SuppressWarnings("MixedMutabilityReturnType")
-    public static List<AdvertisingIdProviderInfo> getAdvertisingIdProviders(
-            @NonNull Context context) {
-        PackageManager packageManager = context.getPackageManager();
-        List<ServiceInfo> serviceInfos =
-                AdvertisingIdUtils.getAdvertisingIdProviderServices(packageManager);
-        if (serviceInfos.isEmpty()) {
-            return Collections.emptyList();
-        }
-
-        Map<String, String> activityMap = getOpenSettingsActivities(packageManager);
-        ServiceInfo highestPriorityServiceInfo =
-                AdvertisingIdUtils.selectServiceByPriority(serviceInfos, packageManager);
-
-        List<AdvertisingIdProviderInfo> providerInfos = new ArrayList<>();
-        for (ServiceInfo serviceInfo : serviceInfos) {
-            String packageName = serviceInfo.packageName;
-
-            AdvertisingIdProviderInfo.Builder builder =
-                    AdvertisingIdProviderInfo.builder()
-                            .setPackageName(packageName)
-                            .setHighestPriority(serviceInfo == highestPriorityServiceInfo);
-            String activityName = activityMap.get(packageName);
-            if (activityName != null) {
-                builder.setSettingsIntent(
-                        new Intent(OPEN_SETTINGS_ACTION).setClassName(packageName, activityName));
-            }
-            providerInfos.add(builder.build());
-        }
-        return providerInfos;
-    }
-
-    /**
-     * Retrieves a {@link Map} from package name to settings activity name.
-     *
-     * <p>This is achieved by looking up which activities can handle {@link #OPEN_SETTINGS_ACTION}
-     * intent action.
-     */
-    @SuppressWarnings({"MixedMutabilityReturnType", "deprecation"})
-    private static Map<String, String> getOpenSettingsActivities(PackageManager packageManager) {
-        Intent settingsIntent = new Intent(OPEN_SETTINGS_ACTION);
-        List<ResolveInfo> settingsResolveInfos = packageManager.queryIntentActivities(
-                settingsIntent, 0);
-        if (settingsResolveInfos.isEmpty()) {
-            return Collections.emptyMap();
-        }
-        Map<String, String> activityMap = new HashMap<>();
-        for (ResolveInfo settingsResolveInfo : settingsResolveInfos) {
-            ActivityInfo settingsActivityInfo = settingsResolveInfo.activityInfo;
-            activityMap.put(settingsActivityInfo.packageName, settingsActivityInfo.name);
-        }
-        return activityMap;
-    }
-}
diff --git a/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/internal/AdvertisingIdAidlServiceImpl.java b/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/internal/AdvertisingIdAidlServiceImpl.java
deleted file mode 100644
index ccb84ecb..0000000
--- a/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/internal/AdvertisingIdAidlServiceImpl.java
+++ /dev/null
@@ -1,44 +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.ads.identifier.provider.internal;
-
-import androidx.ads.identifier.provider.IAdvertisingIdService;
-
-/**
- * The implementation of the IAdvertisingIdService.aidl which retrieves values from
- * {@link androidx.ads.identifier.provider.AdvertisingIdProvider} and replies to the client.
- */
-@SuppressWarnings("deprecation")
-class AdvertisingIdAidlServiceImpl extends IAdvertisingIdService.Stub {
-
-    private final androidx.ads.identifier.provider.AdvertisingIdProvider mProvider;
-
-    AdvertisingIdAidlServiceImpl(
-            androidx.ads.identifier.provider.AdvertisingIdProvider advertisingIdProvider) {
-        mProvider = advertisingIdProvider;
-    }
-
-    @Override
-    public String getId() {
-        return mProvider.getId();
-    }
-
-    @Override
-    public boolean isLimitAdTrackingEnabled() {
-        return mProvider.isLimitAdTrackingEnabled();
-    }
-}
diff --git a/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/internal/AdvertisingIdService.java b/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/internal/AdvertisingIdService.java
deleted file mode 100644
index 4edeb4d..0000000
--- a/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/internal/AdvertisingIdService.java
+++ /dev/null
@@ -1,67 +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.ads.identifier.provider.internal;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
-
-import java.util.concurrent.Callable;
-
-/**
- * The internal service of AndroidX Advertising ID Provider library to provide the Advertising ID.
- */
-@SuppressWarnings("deprecation")
-public class AdvertisingIdService extends Service {
-
-    private AdvertisingIdAidlServiceImpl mAdvertisingIdAidlServiceImpl;
-
-    @Override
-    public void onCreate() {
-        mAdvertisingIdAidlServiceImpl =
-                new AdvertisingIdAidlServiceImpl(getAdvertisingIdProvider());
-    }
-
-    @Override
-    @NonNull
-    public IBinder onBind(@NonNull Intent intent) {
-        return mAdvertisingIdAidlServiceImpl;
-    }
-
-    @VisibleForTesting
-    @NonNull
-    static androidx.ads.identifier.provider.AdvertisingIdProvider getAdvertisingIdProvider() {
-        Callable<androidx.ads.identifier.provider.AdvertisingIdProvider> providerCallable =
-                androidx.ads.identifier.provider.AdvertisingIdProviderManager.getProviderCallable();
-        if (providerCallable == null) {
-            throw new IllegalStateException("Advertising ID Provider not registered.");
-        }
-        androidx.ads.identifier.provider.AdvertisingIdProvider advertisingIdProvider;
-        try {
-            advertisingIdProvider = providerCallable.call();
-        } catch (Exception e) {
-            throw new RuntimeException("Could not fetch the Advertising ID Provider.", e);
-        }
-        if (advertisingIdProvider == null) {
-            throw new IllegalArgumentException("Fetched Advertising ID Provider is null.");
-        }
-        return advertisingIdProvider;
-    }
-}
diff --git a/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/internal/package-info.java b/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/internal/package-info.java
deleted file mode 100644
index 2b8c7ca..0000000
--- a/ads/ads-identifier-provider/src/main/java/androidx/ads/identifier/provider/internal/package-info.java
+++ /dev/null
@@ -1,24 +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.
- */
-
-/**
- */
-@RestrictTo(LIBRARY)
-package androidx.ads.identifier.provider.internal;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY;
-
-import androidx.annotation.RestrictTo;
diff --git a/ads/ads-identifier-testing/build.gradle b/ads/ads-identifier-testing/build.gradle
deleted file mode 100644
index b1a7b7a..0000000
--- a/ads/ads-identifier-testing/build.gradle
+++ /dev/null
@@ -1,39 +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.
- */
-
-import androidx.build.LibraryType
-
-plugins {
-    id("AndroidXPlugin")
-    id("com.android.library")
-}
-
-dependencies {
-    implementation(project(":ads:ads-identifier-common"))
-    api("androidx.annotation:annotation:1.1.0")
-    api(libs.mockitoCore, excludes.bytebuddy)
-}
-
-android {
-    lintOptions {
-        disable "InvalidPackage" // Lint is unhappy about mockito package
-    }
-    namespace "androidx.ads.identifier.testing"
-}
-
-androidx {
-    type = LibraryType.INTERNAL_TEST_LIBRARY
-}
diff --git a/ads/ads-identifier-testing/src/main/AndroidManifest.xml b/ads/ads-identifier-testing/src/main/AndroidManifest.xml
deleted file mode 100644
index cc0959e..0000000
--- a/ads/ads-identifier-testing/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 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.
-  -->
-
-<manifest />
diff --git a/ads/ads-identifier-testing/src/main/java/androidx/ads/identifier/testing/MockPackageManagerHelper.java b/ads/ads-identifier-testing/src/main/java/androidx/ads/identifier/testing/MockPackageManagerHelper.java
deleted file mode 100644
index 1c0b28c..0000000
--- a/ads/ads-identifier-testing/src/main/java/androidx/ads/identifier/testing/MockPackageManagerHelper.java
+++ /dev/null
@@ -1,139 +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.ads.identifier.testing;
-
-import static androidx.ads.identifier.AdvertisingIdUtils.GET_AD_ID_ACTION;
-
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.when;
-
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.os.Build;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-
-import org.mockito.ArgumentMatcher;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.List;
-
-/**
- * Testing utilities for Advertising ID.
- *
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class MockPackageManagerHelper {
-
-    private static final String OPEN_SETTINGS_ACTION =
-            "androidx.ads.identifier.provider.OPEN_SETTINGS";
-
-    @Mock
-    private PackageManager mMockPackageManager;
-
-    public MockPackageManagerHelper() {
-        MockitoAnnotations.initMocks(this);
-    }
-
-    @NonNull
-    public PackageManager getMockPackageManager() {
-        return mMockPackageManager;
-    }
-
-    /** Mocks the {@link PackageManager#queryIntentServices(Intent, int)}. */
-    @SuppressWarnings("deprecation")
-    public void mockQueryGetAdIdServices(@NonNull List<ResolveInfo> resolveInfos) throws Exception {
-        boolean supportMatchSystemOnly = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
-        when(mMockPackageManager.queryIntentServices(hasAction(GET_AD_ID_ACTION),
-                eq(supportMatchSystemOnly ? PackageManager.MATCH_SYSTEM_ONLY : 0)))
-                .thenReturn(resolveInfos);
-        for (ResolveInfo resolveInfo : resolveInfos) {
-            String packageName = resolveInfo.serviceInfo.packageName;
-            if (!supportMatchSystemOnly) {
-                ApplicationInfo applicationInfo = new ApplicationInfo();
-                applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
-                when(mMockPackageManager.getApplicationInfo(packageName, 0))
-                        .thenReturn(applicationInfo);
-            }
-            PackageInfo packageInfo = new PackageInfo();
-            packageInfo.packageName = packageName;
-            when(mMockPackageManager.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS))
-                    .thenReturn(packageInfo);
-        }
-    }
-
-    /** Mocks the {@link PackageManager#queryIntentActivities(Intent, int)}. */
-    @SuppressWarnings("deprecation")
-    public void mockQueryOpenSettingsActivities(@NonNull List<ResolveInfo> resolveInfos) {
-        when(mMockPackageManager.queryIntentActivities(hasAction(OPEN_SETTINGS_ACTION), eq(0)))
-                .thenReturn(resolveInfos);
-    }
-
-    private static Intent hasAction(final String action) {
-        return argThat(new ArgumentMatcher<Intent>() {
-            @Override
-            public boolean matches(Intent intent) {
-                return intent != null && action.equals(intent.getAction());
-            }
-        });
-    }
-
-    /**
-     * Creates a {@link ResolveInfo} which contains a {@link ServiceInfo} with given package name.
-     */
-    @NonNull
-    public static ResolveInfo createServiceResolveInfo(@NonNull String packageName) {
-        ResolveInfo resolveInfo = new ResolveInfo();
-        resolveInfo.serviceInfo = new ServiceInfo();
-        resolveInfo.serviceInfo.packageName = packageName;
-        return resolveInfo;
-    }
-
-    /**
-     * Creates a {@link ResolveInfo} which contains a {@link ServiceInfo} with given package name
-     * and service name.
-     */
-    @NonNull
-    public static ResolveInfo createServiceResolveInfo(
-            @NonNull String packageName, @NonNull String serviceName) {
-        ResolveInfo resolveInfo = createServiceResolveInfo(packageName);
-        resolveInfo.serviceInfo.name = serviceName;
-        return resolveInfo;
-    }
-
-    /**
-     * Creates a {@link ResolveInfo} which contains a {@link ActivityInfo} with given package
-     * name and activity name.
-     */
-    @NonNull
-    public static ResolveInfo createActivityResolveInfo(
-            @NonNull String packageName, @NonNull String activityName) {
-        ResolveInfo resolveInfo = new ResolveInfo();
-        resolveInfo.activityInfo = new ActivityInfo();
-        resolveInfo.activityInfo.packageName = packageName;
-        resolveInfo.activityInfo.name = activityName;
-        return resolveInfo;
-    }
-}
diff --git a/ads/ads-identifier/api/api_lint.ignore b/ads/ads-identifier/api/api_lint.ignore
deleted file mode 100644
index a514159..0000000
--- a/ads/ads-identifier/api/api_lint.ignore
+++ /dev/null
@@ -1,3 +0,0 @@
-// Baseline format: 1.0
-AsyncSuffixFuture: androidx.ads.identifier.AdvertisingIdClient#getAdvertisingIdInfo(android.content.Context):
-    Methods returning com.google.common.util.concurrent.ListenableFuture should have a suffix *Async to reserve unmodified name for a suspend function
diff --git a/ads/ads-identifier/api/current.txt b/ads/ads-identifier/api/current.txt
deleted file mode 100644
index 41188c1..0000000
--- a/ads/ads-identifier/api/current.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-// Signature format: 4.0
-package androidx.ads.identifier {
-
-  @Deprecated public class AdvertisingIdClient {
-    method @Deprecated public static com.google.common.util.concurrent.ListenableFuture<androidx.ads.identifier.AdvertisingIdInfo!> getAdvertisingIdInfo(android.content.Context);
-    method @Deprecated public static boolean isAdvertisingIdProviderAvailable(android.content.Context);
-  }
-
-  @Deprecated @com.google.auto.value.AutoValue @com.google.auto.value.AutoValue.CopyAnnotations public abstract class AdvertisingIdInfo {
-    method @Deprecated public abstract String getId();
-    method @Deprecated public abstract String getProviderPackageName();
-    method @Deprecated public abstract boolean isLimitAdTrackingEnabled();
-  }
-
-  @Deprecated public class AdvertisingIdNotAvailableException extends java.lang.Exception {
-    ctor @Deprecated public AdvertisingIdNotAvailableException(String);
-    ctor @Deprecated public AdvertisingIdNotAvailableException(String, Throwable);
-  }
-
-}
-
diff --git a/ads/ads-identifier/api/public_plus_experimental_current.txt b/ads/ads-identifier/api/public_plus_experimental_current.txt
deleted file mode 100644
index 41188c1..0000000
--- a/ads/ads-identifier/api/public_plus_experimental_current.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-// Signature format: 4.0
-package androidx.ads.identifier {
-
-  @Deprecated public class AdvertisingIdClient {
-    method @Deprecated public static com.google.common.util.concurrent.ListenableFuture<androidx.ads.identifier.AdvertisingIdInfo!> getAdvertisingIdInfo(android.content.Context);
-    method @Deprecated public static boolean isAdvertisingIdProviderAvailable(android.content.Context);
-  }
-
-  @Deprecated @com.google.auto.value.AutoValue @com.google.auto.value.AutoValue.CopyAnnotations public abstract class AdvertisingIdInfo {
-    method @Deprecated public abstract String getId();
-    method @Deprecated public abstract String getProviderPackageName();
-    method @Deprecated public abstract boolean isLimitAdTrackingEnabled();
-  }
-
-  @Deprecated public class AdvertisingIdNotAvailableException extends java.lang.Exception {
-    ctor @Deprecated public AdvertisingIdNotAvailableException(String);
-    ctor @Deprecated public AdvertisingIdNotAvailableException(String, Throwable);
-  }
-
-}
-
diff --git a/ads/ads-identifier/api/res-current.txt b/ads/ads-identifier/api/res-current.txt
deleted file mode 100644
index e69de29..0000000
--- a/ads/ads-identifier/api/res-current.txt
+++ /dev/null
diff --git a/ads/ads-identifier/api/restricted_current.txt b/ads/ads-identifier/api/restricted_current.txt
deleted file mode 100644
index 41188c1..0000000
--- a/ads/ads-identifier/api/restricted_current.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-// Signature format: 4.0
-package androidx.ads.identifier {
-
-  @Deprecated public class AdvertisingIdClient {
-    method @Deprecated public static com.google.common.util.concurrent.ListenableFuture<androidx.ads.identifier.AdvertisingIdInfo!> getAdvertisingIdInfo(android.content.Context);
-    method @Deprecated public static boolean isAdvertisingIdProviderAvailable(android.content.Context);
-  }
-
-  @Deprecated @com.google.auto.value.AutoValue @com.google.auto.value.AutoValue.CopyAnnotations public abstract class AdvertisingIdInfo {
-    method @Deprecated public abstract String getId();
-    method @Deprecated public abstract String getProviderPackageName();
-    method @Deprecated public abstract boolean isLimitAdTrackingEnabled();
-  }
-
-  @Deprecated public class AdvertisingIdNotAvailableException extends java.lang.Exception {
-    ctor @Deprecated public AdvertisingIdNotAvailableException(String);
-    ctor @Deprecated public AdvertisingIdNotAvailableException(String, Throwable);
-  }
-
-}
-
diff --git a/ads/ads-identifier/build.gradle b/ads/ads-identifier/build.gradle
deleted file mode 100644
index 90bd660..0000000
--- a/ads/ads-identifier/build.gradle
+++ /dev/null
@@ -1,54 +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.
- */
-
-import androidx.build.Publish
-
-plugins {
-    id("AndroidXPlugin")
-    id("com.android.library")
-}
-
-dependencies {
-    api("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0")
-    implementation(libs.autoValueAnnotations)
-    annotationProcessor(libs.autoValue)
-    api(libs.guavaListenableFuture)
-    implementation("androidx.concurrent:concurrent-futures:1.0.0")
-
-    implementation(project(":ads:ads-identifier-common"))
-
-    androidTestImplementation(project(":ads:ads-identifier-testing"))
-    androidTestImplementation(libs.junit)
-    androidTestImplementation(libs.truth)
-    androidTestImplementation(libs.testExtJunit)
-    androidTestImplementation(libs.testCore)
-    androidTestImplementation(libs.testRunner)
-    androidTestImplementation(libs.testRules)
-    androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy)
-}
-
-androidx {
-    name = "AndroidX Ads Identifier"
-    publish = Publish.SNAPSHOT_AND_RELEASE
-    mavenVersion = LibraryVersions.ADS_IDENTIFIER
-    inceptionYear = "2019"
-    description = "AndroidX Ads Identifier"
-}
-
-android {
-    namespace "androidx.ads.identifier"
-}
diff --git a/ads/ads-identifier/integration-tests/testapp/build.gradle b/ads/ads-identifier/integration-tests/testapp/build.gradle
deleted file mode 100644
index 6a99797..0000000
--- a/ads/ads-identifier/integration-tests/testapp/build.gradle
+++ /dev/null
@@ -1,34 +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.
- */
-
-plugins {
-    id("AndroidXPlugin")
-    id("com.android.application")
-}
-
-android {
-    defaultConfig {
-        applicationId "androidx.ads.identifier.testapp"
-        minSdkVersion 14
-    }
-    namespace "androidx.ads.identifier.testapp"
-}
-
-dependencies {
-    implementation(project(":ads:ads-identifier"))
-    implementation(project(":ads:ads-identifier-common"))
-    implementation(libs.guavaAndroid)
-}
diff --git a/ads/ads-identifier/integration-tests/testapp/lint-baseline.xml b/ads/ads-identifier/integration-tests/testapp/lint-baseline.xml
deleted file mode 100644
index eabfd5a..0000000
--- a/ads/ads-identifier/integration-tests/testapp/lint-baseline.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.4.0-alpha08" type="baseline" client="gradle" dependencies="false" name="AGP (7.4.0-alpha08)" variant="all" version="7.4.0-alpha08">
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    protected void onCreate(Bundle savedInstanceState) {"
-        errorLine2="                            ~~~~~~">
-        <location
-            file="src/main/java/androidx/ads/identifier/testapp/AdsIdentifierActivity.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void getId(View view) {"
-        errorLine2="                      ~~~~">
-        <location
-            file="src/main/java/androidx/ads/identifier/testapp/AdsIdentifierActivity.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void getIdSync(View view) {"
-        errorLine2="                          ~~~~">
-        <location
-            file="src/main/java/androidx/ads/identifier/testapp/AdsIdentifierActivity.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void isProviderAvailable(View view) {"
-        errorLine2="                                    ~~~~">
-        <location
-            file="src/main/java/androidx/ads/identifier/testapp/AdsIdentifierActivity.java"/>
-    </issue>
-
-    <issue
-        id="UnknownNullness"
-        message="Unknown nullability; explicitly declare as `@Nullable` or `@NonNull` to improve Kotlin interoperability; see https://developer.android.com/kotlin/interop#nullability_annotations"
-        errorLine1="    public void listProvider(View view) {"
-        errorLine2="                             ~~~~">
-        <location
-            file="src/main/java/androidx/ads/identifier/testapp/AdsIdentifierActivity.java"/>
-    </issue>
-
-</issues>
diff --git a/ads/ads-identifier/integration-tests/testapp/src/main/AndroidManifest.xml b/ads/ads-identifier/integration-tests/testapp/src/main/AndroidManifest.xml
deleted file mode 100644
index 6e3275e..0000000
--- a/ads/ads-identifier/integration-tests/testapp/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools">
-
-    <application
-        android:allowBackup="false"
-        android:label="@string/app_name"
-        tools:ignore="GoogleAppIndexingWarning,MissingApplicationIcon">
-        <activity
-            android:name=".AdsIdentifierActivity"
-            android:exported="true">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-
-</manifest>
\ No newline at end of file
diff --git a/ads/ads-identifier/integration-tests/testapp/src/main/java/androidx/ads/identifier/testapp/AdsIdentifierActivity.java b/ads/ads-identifier/integration-tests/testapp/src/main/java/androidx/ads/identifier/testapp/AdsIdentifierActivity.java
deleted file mode 100644
index 2f575fd..0000000
--- a/ads/ads-identifier/integration-tests/testapp/src/main/java/androidx/ads/identifier/testapp/AdsIdentifierActivity.java
+++ /dev/null
@@ -1,146 +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.ads.identifier.testapp;
-
-import android.app.Activity;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-import android.os.Bundle;
-import android.text.format.DateFormat;
-import android.view.View;
-import android.widget.TextView;
-
-import androidx.ads.identifier.AdvertisingIdClient;
-import androidx.ads.identifier.AdvertisingIdInfo;
-import androidx.ads.identifier.AdvertisingIdUtils;
-
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.ExecutionException;
-
-/**
- * Simple activity as an ads identifier developer.
- */
-public class AdsIdentifierActivity extends Activity {
-
-    private static final String HIGH_PRIORITY_PERMISSION =
-            "androidx.ads.identifier.provider.HIGH_PRIORITY";
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        setContentView(R.layout.activity_ads_identifier);
-    }
-
-    /** Gets Advertising ID. */
-    public void getId(View view) {
-        TextView textView = findViewById(R.id.text);
-        ListenableFuture<AdvertisingIdInfo> advertisingIdInfoListenableFuture =
-                AdvertisingIdClient.getAdvertisingIdInfo(getApplicationContext());
-        Futures.addCallback(advertisingIdInfoListenableFuture,
-                new FutureCallback<AdvertisingIdInfo>() {
-                    @Override
-                    public void onSuccess(AdvertisingIdInfo advertisingIdInfo) {
-                        runOnUiThread(() -> textView.setText(advertisingIdInfo.toString()));
-                    }
-
-                    @Override
-                    public void onFailure(Throwable throwable) {
-                        runOnUiThread(() -> textView.setText(throwable.toString()));
-                    }
-                }, MoreExecutors.directExecutor());
-    }
-
-    /** Gets Advertising ID synchronously. */
-    public void getIdSync(View view) {
-        TextView textView = findViewById(R.id.text);
-        new Thread(() -> {
-            AdvertisingIdInfo advertisingIdInfo;
-            try {
-                advertisingIdInfo =
-                        AdvertisingIdClient.getAdvertisingIdInfo(getApplicationContext()).get();
-            } catch (ExecutionException e) {
-                Throwable cause = e.getCause() != null ? e.getCause() : e;
-                runOnUiThread(() -> textView.setText(cause.toString()));
-                return;
-
-            } catch (InterruptedException e) {
-                Thread.currentThread().interrupt();
-                runOnUiThread(() -> textView.setText(e.toString()));
-                return;
-            }
-            runOnUiThread(() -> textView.setText(advertisingIdInfo.toString()));
-        }).start();
-    }
-
-    /** Checks is provider available. */
-    public void isProviderAvailable(View view) {
-        TextView textView = findViewById(R.id.text);
-        boolean isAvailable = AdvertisingIdClient.isAdvertisingIdProviderAvailable(this);
-        textView.setText(String.valueOf(isAvailable));
-    }
-
-    /** Lists all the providers. */
-    @SuppressWarnings("deprecation")
-    public void listProvider(View view) {
-        TextView textView = findViewById(R.id.text);
-        textView.setText("Services:\n");
-
-        List<ServiceInfo> serviceInfos =
-                AdvertisingIdUtils.getAdvertisingIdProviderServices(getPackageManager());
-        for (ServiceInfo serviceInfo : serviceInfos) {
-            PackageInfo packageInfo;
-            try {
-                packageInfo = getPackageManager().getPackageInfo(serviceInfo.packageName,
-                        PackageManager.GET_PERMISSIONS);
-            } catch (PackageManager.NameNotFoundException e) {
-                continue;
-            }
-            show(textView, packageInfo);
-        }
-    }
-
-    private void show(TextView textView, PackageInfo packageInfo) {
-        textView.append(String.format(Locale.US, "%s\nFLAG_SYSTEM:%d\n",
-                packageInfo.packageName,
-                packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM));
-        textView.append(String.format(Locale.US, "isRequestHighPriority:%s\n",
-                isRequestHighPriority(packageInfo.requestedPermissions)));
-        textView.append(String.format(Locale.US, "firstInstallTime:%s\n",
-                DateFormat.format("yyyy-MM-dd HH:mm:ss", packageInfo.firstInstallTime)));
-        textView.append("\n");
-    }
-
-    private static boolean isRequestHighPriority(String[] array) {
-        if (array == null) {
-            return false;
-        }
-        for (String permission : array) {
-            if (HIGH_PRIORITY_PERMISSION.equals(permission)) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/ads/ads-identifier/integration-tests/testapp/src/main/res/layout/activity_ads_identifier.xml b/ads/ads-identifier/integration-tests/testapp/src/main/res/layout/activity_ads_identifier.xml
deleted file mode 100644
index 0f4f3ea..0000000
--- a/ads/ads-identifier/integration-tests/testapp/src/main/res/layout/activity_ads_identifier.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  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.
-  -->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    tools:context="androidx.ads.identifier.testapp.AdsIdentifierActivity">
-
-    <LinearLayout
-        style="?android:attr/buttonBarStyle"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal">
-
-        <Button
-            style="?android:attr/buttonBarButtonStyle"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:onClick="getId"
-            android:text="@string/get_ad_id" />
-
-        <Button
-            style="?android:attr/buttonBarButtonStyle"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:onClick="getIdSync"
-            android:text="@string/get_ad_id_sync" />
-    </LinearLayout>
-
-    <LinearLayout
-        style="?android:attr/buttonBarStyle"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal">
-
-        <Button
-            style="?android:attr/buttonBarButtonStyle"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:onClick="isProviderAvailable"
-            android:text="@string/is_provider_available" />
-
-        <Button
-            style="?android:attr/buttonBarButtonStyle"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:onClick="listProvider"
-            android:text="@string/list_provider" />
-    </LinearLayout>
-
-    <TextView
-        android:id="@+id/text"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="" />
-</LinearLayout>
diff --git a/ads/ads-identifier/lint-baseline.xml b/ads/ads-identifier/lint-baseline.xml
deleted file mode 100644
index 2284798..0000000
--- a/ads/ads-identifier/lint-baseline.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-beta03" type="baseline" client="gradle" dependencies="false" name="AGP (8.0.0-beta03)" variant="all" version="8.0.0-beta03">
-
-    <issue
-        id="BanThreadSleep"
-        message="Uses Thread.sleep()"
-        errorLine1="        Thread.sleep(20000);"
-        errorLine2="               ~~~~~">
-        <location
-            file="src/androidTest/java/androidx/ads/identifier/AdvertisingIdClientTest.java"/>
-    </issue>
-
-    <issue
-        id="BanThreadSleep"
-        message="Uses Thread.sleep()"
-        errorLine1="        Thread.sleep(11000);"
-        errorLine2="               ~~~~~">
-        <location
-            file="src/androidTest/java/androidx/ads/identifier/AdvertisingIdClientTest.java"/>
-    </issue>
-
-    <issue
-        id="BanThreadSleep"
-        message="Uses Thread.sleep()"
-        errorLine1="        Thread.sleep(20000);"
-        errorLine2="               ~~~~~">
-        <location
-            file="src/androidTest/java/androidx/ads/identifier/AdvertisingIdClientTest.java"/>
-    </issue>
-
-    <issue
-        id="BanThreadSleep"
-        message="Uses Thread.sleep()"
-        errorLine1="        Thread.sleep(20000);"
-        errorLine2="               ~~~~~">
-        <location
-            file="src/androidTest/java/androidx/ads/identifier/AdvertisingIdClientTest.java"/>
-    </issue>
-
-    <issue
-        id="BanThreadSleep"
-        message="Uses Thread.sleep()"
-        errorLine1="        Thread.sleep(11000);"
-        errorLine2="               ~~~~~">
-        <location
-            file="src/androidTest/java/androidx/ads/identifier/AdvertisingIdClientTest.java"/>
-    </issue>
-
-</issues>
diff --git a/ads/ads-identifier/src/androidTest/AndroidManifest.xml b/ads/ads-identifier/src/androidTest/AndroidManifest.xml
deleted file mode 100644
index 453fdfb..0000000
--- a/ads/ads-identifier/src/androidTest/AndroidManifest.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<!--
-  Copyright (C) 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
-  -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools">
-
-    <application>
-        <service
-            android:name="androidx.ads.identifier.MockAdvertisingIdService"
-            android:enabled="true"
-            android:exported="true"
-            android:process=":test"
-            tools:ignore="ExportedService">
-            <intent-filter>
-                <action android:name="androidx.ads.identifier.provider.GET_AD_ID" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
-        </service>
-
-        <service
-            android:name="androidx.ads.identifier.MockAdvertisingIdThrowsNpeService"
-            android:enabled="true"
-            android:exported="true"
-            android:process=":test"
-            tools:ignore="ExportedService">
-            <intent-filter>
-                <action android:name="androidx.ads.identifier.provider.GET_AD_ID" />
-                <category android:name="android.intent.category.DEFAULT" />
-            </intent-filter>
-        </service>
-    </application>
-</manifest>
diff --git a/ads/ads-identifier/src/androidTest/java/androidx/ads/identifier/AdvertisingIdClientTest.java b/ads/ads-identifier/src/androidTest/java/androidx/ads/identifier/AdvertisingIdClientTest.java
deleted file mode 100644
index 164c2b2..0000000
--- a/ads/ads-identifier/src/androidTest/java/androidx/ads/identifier/AdvertisingIdClientTest.java
+++ /dev/null
@@ -1,198 +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.ads.identifier;
-
-import static androidx.ads.identifier.AdvertisingIdUtils.GET_AD_ID_ACTION;
-import static androidx.ads.identifier.MockAdvertisingIdService.TESTING_AD_ID;
-import static androidx.ads.identifier.testing.MockPackageManagerHelper.createServiceResolveInfo;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.fail;
-
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-
-import androidx.ads.identifier.testing.MockPackageManagerHelper;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.LargeTest;
-
-import com.google.common.collect.Lists;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Collections;
-import java.util.concurrent.ExecutionException;
-
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-@SuppressWarnings("deprecation")
-public class AdvertisingIdClientTest {
-    private static final String MOCK_SERVICE_NAME = MockAdvertisingIdService.class.getName();
-    private static final String MOCK_THROWS_NPE_SERVICE_NAME =
-            MockAdvertisingIdThrowsNpeService.class.getName();
-
-    private MockPackageManagerHelper mMockPackageManagerHelper = new MockPackageManagerHelper();
-
-    private Context mContext;
-
-    @Before
-    public void setUp() throws Exception {
-        Context applicationContext = ApplicationProvider.getApplicationContext();
-
-        mContext = new ContextWrapper(applicationContext) {
-            @Override
-            public Context getApplicationContext() {
-                return this;
-            }
-
-            @Override
-            public PackageManager getPackageManager() {
-                return mMockPackageManagerHelper.getMockPackageManager();
-            }
-        };
-
-        mMockPackageManagerHelper.mockQueryGetAdIdServices(Lists.newArrayList(
-                createServiceResolveInfo(mContext.getPackageName(), MOCK_SERVICE_NAME)));
-    }
-
-    @After
-    public void tearDown() {
-        AdvertisingIdClient.clearConnectionClient();
-
-        Intent serviceIntent = new Intent(GET_AD_ID_ACTION);
-        serviceIntent.setClassName(mContext.getPackageName(), MOCK_SERVICE_NAME);
-        mContext.stopService(serviceIntent);
-
-        Intent npeServiceIntent = new Intent(GET_AD_ID_ACTION);
-        npeServiceIntent.setClassName(mContext.getPackageName(), MOCK_THROWS_NPE_SERVICE_NAME);
-        mContext.stopService(npeServiceIntent);
-    }
-
-    @Test
-    public void getAdvertisingIdInfo() throws Exception {
-        AdvertisingIdInfo info = AdvertisingIdClient.getAdvertisingIdInfo(mContext).get();
-
-        assertThat(info).isEqualTo(AdvertisingIdInfo.builder()
-                .setId(TESTING_AD_ID)
-                .setLimitAdTrackingEnabled(true)
-                .setProviderPackageName(mContext.getPackageName())
-                .build());
-    }
-
-    public void getAdvertisingIdInfo_noProvider() throws Exception {
-        mMockPackageManagerHelper.mockQueryGetAdIdServices(Collections.<ResolveInfo>emptyList());
-
-        try {
-            AdvertisingIdClient.getAdvertisingIdInfo(mContext).get();
-        } catch (ExecutionException e) {
-            assertThat(e).hasCauseThat().isInstanceOf(AdvertisingIdNotAvailableException.class);
-            return;
-        }
-        fail("Expected ExecutionException");
-    }
-
-    @Test
-    public void getAdvertisingIdInfo_serviceThrowsNullPointerException() throws Exception {
-        mMockPackageManagerHelper.mockQueryGetAdIdServices(Lists.newArrayList(
-                createServiceResolveInfo(mContext.getPackageName(), MOCK_THROWS_NPE_SERVICE_NAME)));
-
-        try {
-            AdvertisingIdClient.getAdvertisingIdInfo(mContext).get();
-        } catch (ExecutionException e) {
-            assertThat(e).hasCauseThat().isInstanceOf(AdvertisingIdNotAvailableException.class);
-            return;
-        }
-        fail("Expected ExecutionException");
-    }
-
-    @Test
-    public void getAdvertisingIdInfo_getTwice() throws Exception {
-        AdvertisingIdInfo info1 = AdvertisingIdClient.getAdvertisingIdInfo(mContext).get();
-        AdvertisingIdInfo info2 = AdvertisingIdClient.getAdvertisingIdInfo(mContext).get();
-
-        AdvertisingIdInfo expected = AdvertisingIdInfo.builder()
-                .setId(TESTING_AD_ID)
-                .setLimitAdTrackingEnabled(true)
-                .setProviderPackageName(mContext.getPackageName())
-                .build();
-        assertThat(info1).isEqualTo(expected);
-        assertThat(info2).isEqualTo(expected);
-    }
-
-    @Test
-    public void notConnectedAtBeginning() {
-        assertThat(AdvertisingIdClient.isConnected()).isFalse();
-    }
-
-    @Test
-    public void scheduleAutoDisconnect() throws Exception {
-        AdvertisingIdClient.getAdvertisingIdInfo(mContext).get();
-        assertThat(AdvertisingIdClient.isConnected()).isTrue();
-
-        Thread.sleep(20000);
-        assertThat(AdvertisingIdClient.isConnected()).isTrue();
-
-        Thread.sleep(11000);
-        assertThat(AdvertisingIdClient.isConnected()).isFalse();
-    }
-
-    @Test
-    public void scheduleAutoDisconnect_extend() throws Exception {
-        AdvertisingIdClient.getAdvertisingIdInfo(mContext).get();
-        assertThat(AdvertisingIdClient.isConnected()).isTrue();
-
-        Thread.sleep(20000);
-        assertThat(AdvertisingIdClient.isConnected()).isTrue();
-        AdvertisingIdClient.getAdvertisingIdInfo(mContext).get();
-
-        Thread.sleep(20000);
-        assertThat(AdvertisingIdClient.isConnected()).isTrue();
-
-        Thread.sleep(11000);
-        assertThat(AdvertisingIdClient.isConnected()).isFalse();
-    }
-
-    @Test
-    public void isAdvertisingIdProviderAvailable() {
-        assertThat(AdvertisingIdClient.isAdvertisingIdProviderAvailable(mContext)).isTrue();
-    }
-
-    @Test
-    public void isAdvertisingIdProviderAvailable_noProvider() throws Exception {
-        mMockPackageManagerHelper.mockQueryGetAdIdServices(Collections.<ResolveInfo>emptyList());
-
-        assertThat(AdvertisingIdClient.isAdvertisingIdProviderAvailable(mContext)).isFalse();
-    }
-
-    @Test
-    public void isAdvertisingIdProviderAvailable_twoProviders() throws Exception {
-        mMockPackageManagerHelper.mockQueryGetAdIdServices(Lists.newArrayList(
-                createServiceResolveInfo("com.a", "A"),
-                createServiceResolveInfo("com.b", "B")));
-
-        assertThat(AdvertisingIdClient.isAdvertisingIdProviderAvailable(mContext)).isTrue();
-    }
-
-}
diff --git a/ads/ads-identifier/src/androidTest/java/androidx/ads/identifier/MockAdvertisingIdService.java b/ads/ads-identifier/src/androidTest/java/androidx/ads/identifier/MockAdvertisingIdService.java
deleted file mode 100644
index 691a37c..0000000
--- a/ads/ads-identifier/src/androidTest/java/androidx/ads/identifier/MockAdvertisingIdService.java
+++ /dev/null
@@ -1,58 +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.ads.identifier;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-import androidx.ads.identifier.provider.IAdvertisingIdService;
-import androidx.annotation.Nullable;
-
-/**
- * Provide a mock for {@link androidx.ads.identifier.provider.IAdvertisingIdService}.
- * To be used in unit tests.
- */
-public class MockAdvertisingIdService extends Service {
-
-    public static final String TESTING_AD_ID = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee";
-
-    private MockAdvertisingIdServiceImpl mAdvertisingIdServiceImpl;
-
-    @Override
-    public void onCreate() {
-        mAdvertisingIdServiceImpl = new MockAdvertisingIdServiceImpl();
-    }
-
-    @Nullable
-    @Override
-    public IBinder onBind(Intent intent) {
-        return mAdvertisingIdServiceImpl;
-    }
-
-    private static class MockAdvertisingIdServiceImpl extends IAdvertisingIdService.Stub {
-        @Override
-        public String getId() {
-            return TESTING_AD_ID;
-        }
-
-        @Override
-        public boolean isLimitAdTrackingEnabled() {
-            return true;
-        }
-    }
-}
diff --git a/ads/ads-identifier/src/androidTest/java/androidx/ads/identifier/MockAdvertisingIdThrowsNpeService.java b/ads/ads-identifier/src/androidTest/java/androidx/ads/identifier/MockAdvertisingIdThrowsNpeService.java
deleted file mode 100644
index 3ed2714..0000000
--- a/ads/ads-identifier/src/androidTest/java/androidx/ads/identifier/MockAdvertisingIdThrowsNpeService.java
+++ /dev/null
@@ -1,56 +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.ads.identifier;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-import androidx.ads.identifier.provider.IAdvertisingIdService;
-import androidx.annotation.Nullable;
-
-/**
- * Provide a mock for {@link IAdvertisingIdService} which always throw {@link NullPointerException}.
- * To be used in unit tests.
- */
-public class MockAdvertisingIdThrowsNpeService extends Service {
-
-    private MockAdvertisingIdServiceImpl mAdvertisingIdServiceImpl;
-
-    @Override
-    public void onCreate() {
-        mAdvertisingIdServiceImpl = new MockAdvertisingIdServiceImpl();
-    }
-
-    @Nullable
-    @Override
-    public IBinder onBind(Intent intent) {
-        return mAdvertisingIdServiceImpl;
-    }
-
-    private static class MockAdvertisingIdServiceImpl extends IAdvertisingIdService.Stub {
-        @Override
-        public String getId() {
-            throw new NullPointerException();
-        }
-
-        @Override
-        public boolean isLimitAdTrackingEnabled() {
-            throw new NullPointerException();
-        }
-    }
-}
diff --git a/ads/ads-identifier/src/androidTest/java/androidx/ads/identifier/internal/HoldingConnectionClientTest.java b/ads/ads-identifier/src/androidTest/java/androidx/ads/identifier/internal/HoldingConnectionClientTest.java
deleted file mode 100644
index 17557a45..0000000
--- a/ads/ads-identifier/src/androidTest/java/androidx/ads/identifier/internal/HoldingConnectionClientTest.java
+++ /dev/null
@@ -1,167 +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.ads.identifier.internal;
-
-import static androidx.ads.identifier.AdvertisingIdUtils.GET_AD_ID_ACTION;
-import static androidx.ads.identifier.MockAdvertisingIdService.TESTING_AD_ID;
-import static androidx.ads.identifier.testing.MockPackageManagerHelper.createServiceResolveInfo;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-
-import androidx.ads.identifier.MockAdvertisingIdService;
-import androidx.ads.identifier.provider.IAdvertisingIdService;
-import androidx.ads.identifier.testing.MockPackageManagerHelper;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.LargeTest;
-
-import com.google.common.collect.Lists;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.IOException;
-import java.util.concurrent.TimeoutException;
-
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-@SuppressWarnings("deprecation")
-public class HoldingConnectionClientTest {
-    private static final String MOCK_SERVICE_NAME = MockAdvertisingIdService.class.getName();
-
-    private MockPackageManagerHelper mMockPackageManagerHelper = new MockPackageManagerHelper();
-
-    private Context mContext;
-
-    private HoldingConnectionClient mClient;
-
-    @Before
-    public void setUp() throws Exception {
-        MockHoldingConnectionClient.sGetServiceConnectionThrowException = false;
-        MockHoldingConnectionClient.sGetServiceFromConnectionThrowInterruptedException = false;
-
-        Context applicationContext = ApplicationProvider.getApplicationContext();
-
-        mContext = new ContextWrapper(applicationContext) {
-            @Override
-            public Context getApplicationContext() {
-                return this;
-            }
-
-            @Override
-            public PackageManager getPackageManager() {
-                return mMockPackageManagerHelper.getMockPackageManager();
-            }
-        };
-
-        mMockPackageManagerHelper.mockQueryGetAdIdServices(Lists.newArrayList(
-                createServiceResolveInfo(mContext.getPackageName(), MOCK_SERVICE_NAME)));
-
-        mClient = new HoldingConnectionClient(mContext);
-    }
-
-    @After
-    public void tearDown() {
-        mClient.finish();
-
-        Intent serviceIntent = new Intent(GET_AD_ID_ACTION);
-        serviceIntent.setClassName(mContext.getPackageName(), MOCK_SERVICE_NAME);
-        mContext.stopService(serviceIntent);
-    }
-
-    @Test
-    public void connectedAtBeginning() {
-        assertThat(mClient.isConnected()).isTrue();
-    }
-
-    @Test
-    public void finish() {
-        mClient.finish();
-
-        assertThat(mClient.isConnected()).isFalse();
-    }
-
-    @Test
-    public void getService() throws Exception {
-        assertThat(mClient.getIdService().getId()).isEqualTo(TESTING_AD_ID);
-    }
-
-    @Test
-    public void getPackageName() {
-        assertThat(mClient.getPackageName()).isEqualTo(mContext.getPackageName());
-    }
-
-    @Test(expected = TimeoutException.class)
-    public void getServiceWithPackageName_connectionTimeout() throws Exception {
-        new MockHoldingConnectionClient(mContext);
-    }
-
-    @Test(expected = InterruptedException.class)
-    public void getServiceWithPackageName_interrupted() throws Exception {
-        MockHoldingConnectionClient.sGetServiceFromConnectionThrowInterruptedException = true;
-
-        new MockHoldingConnectionClient(mContext);
-    }
-
-    @Test(expected = IOException.class)
-    public void getServiceWithPackageName_connectionFailed() throws Exception {
-        MockHoldingConnectionClient.sGetServiceConnectionThrowException = true;
-
-        new MockHoldingConnectionClient(mContext);
-    }
-
-    private static class MockHoldingConnectionClient extends HoldingConnectionClient {
-
-        static boolean sGetServiceConnectionThrowException = false;
-        static boolean sGetServiceFromConnectionThrowInterruptedException = false;
-
-        MockHoldingConnectionClient(Context context)
-                throws InterruptedException, TimeoutException,
-                androidx.ads.identifier.AdvertisingIdNotAvailableException,
-                IOException {
-            super(context);
-        }
-
-        @Override
-        BlockingServiceConnection getServiceConnection(ComponentName componentName)
-                throws IOException {
-            if (sGetServiceConnectionThrowException) {
-                throw new IOException();
-            }
-
-            // This connection does not bind to any service, so it always timeout.
-            return new BlockingServiceConnection();
-        }
-
-        @Override
-        IAdvertisingIdService getIdServiceFromConnection()
-                throws TimeoutException, InterruptedException {
-            if (sGetServiceFromConnectionThrowInterruptedException) {
-                throw new InterruptedException();
-            }
-            return super.getIdServiceFromConnection();
-        }
-    }
-}
diff --git a/ads/ads-identifier/src/main/AndroidManifest.xml b/ads/ads-identifier/src/main/AndroidManifest.xml
deleted file mode 100644
index 0d0975d..0000000
--- a/ads/ads-identifier/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android">
-</manifest>
\ No newline at end of file
diff --git a/ads/ads-identifier/src/main/java/androidx/ads/identifier/AdvertisingIdClient.java b/ads/ads-identifier/src/main/java/androidx/ads/identifier/AdvertisingIdClient.java
deleted file mode 100644
index e2ab65d..0000000
--- a/ads/ads-identifier/src/main/java/androidx/ads/identifier/AdvertisingIdClient.java
+++ /dev/null
@@ -1,293 +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.ads.identifier;
-
-import android.content.Context;
-import android.os.RemoteException;
-
-import androidx.ads.identifier.internal.HoldingConnectionClient;
-import androidx.ads.identifier.provider.IAdvertisingIdService;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-import androidx.annotation.WorkerThread;
-import androidx.concurrent.futures.CallbackToFutureAdapter;
-
-import com.google.auto.value.AutoValue;
-import com.google.common.util.concurrent.ListenableFuture;
-
-import java.io.IOException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Client for retrieving Advertising ID related info from an AndroidX ID Provider installed on
- * the device.
- *
- * <p>Typical usage would be:
- * <ol>
- * <li>Call {@link #isAdvertisingIdProviderAvailable} to make sure there is an Advertising ID
- * Provider available.
- * <li>Call {@link #getAdvertisingIdInfo} to get Advertising ID info (the Advertising ID and LAT
- * setting).
- * </ol>
- *
- * @deprecated Use the
- * <a href="https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient">
- * Advertising ID API that's available as part of Google Play Services</a> instead of this library.
- */
-@Deprecated
-public class AdvertisingIdClient {
-
-    /**
-     * Amount of time to wait before timing out when trying to get the ID info from the
-     * Provider. Including the binding service time and the remote calling time.
-     */
-    private static final long TIMEOUT_SECONDS = 20;
-
-    private static final long AUTO_DISCONNECT_SECONDS = 30;
-
-    @SuppressWarnings("WeakerAccess") /* synthetic accessor */
-    static final ExecutorService QUERY_EXECUTOR_SERVICE = Executors.newCachedThreadPool();
-
-    @SuppressWarnings("WeakerAccess") /* synthetic accessor */
-    static final ScheduledExecutorService SCHEDULED_EXECUTOR_SERVICE =
-            Executors.newSingleThreadScheduledExecutor();
-
-    private static final Object sLock = new Object();
-
-    /**
-     * The client holding connection which can be reused if connected.
-     *
-     * <p>This value will only be set at 2 places at production when setup new connection or auto
-     * disconnect timeout happen, and 1 place at testing when clear connection.
-     * <p>There could be multiple connection clients in corner cases, but each of them will be
-     * auto disconnect eventually.
-     * <p>Each connection client has a last connection ID field, which ties to the connection
-     * client and also indicates the status of connection. See {@link HoldingConnectionClient}'s
-     * mLastConnectionId filed for details.
-     * <p>Each get ID instance will get a pair of connection client and connection ID (which ties
-     * to the connection client) first, then use this pair to schedule an auto disconnection at
-     * {@link #AUTO_DISCONNECT_SECONDS} later.
-     */
-    @SuppressWarnings("WeakerAccess") /* synthetic accessor */
-    @NonNull
-    static final AtomicReference<HoldingConnectionClient> sConnectionClient =
-            new AtomicReference<>(null);
-
-    @AutoValue
-    @AutoValue.CopyAnnotations
-    @SuppressWarnings("deprecation")
-    abstract static class ConnectionPair {
-        @NonNull
-        abstract HoldingConnectionClient getConnectionClient();
-
-        abstract long getConnectionId();
-
-        @NonNull
-        static ConnectionPair of(HoldingConnectionClient connectionClient, long connectionId) {
-            return new AutoValue_AdvertisingIdClient_ConnectionPair(connectionClient, connectionId);
-        }
-    }
-
-    private AdvertisingIdClient() {
-    }
-
-    @SuppressWarnings("WeakerAccess") /* synthetic accessor */
-    @WorkerThread
-    @NonNull
-    static ConnectionPair getConnection(Context context)
-            throws IOException, AdvertisingIdNotAvailableException, TimeoutException,
-            InterruptedException {
-        ConnectionPair connectionPair = tryConnect();
-        if (connectionPair == null) {
-            synchronized (sLock) {
-                connectionPair = tryConnect();
-                if (connectionPair == null) {
-                    HoldingConnectionClient connectionClient = new HoldingConnectionClient(context);
-                    sConnectionClient.set(connectionClient);
-                    connectionPair = ConnectionPair.of(connectionClient, 0);
-                }
-            }
-        }
-        return connectionPair;
-    }
-
-    @Nullable
-    private static ConnectionPair tryConnect() {
-        HoldingConnectionClient connectionClient = sConnectionClient.get();
-        if (connectionClient != null) {
-            long connectionId = connectionClient.askConnectionId();
-            if (connectionId >= 0) {
-                return ConnectionPair.of(connectionClient, connectionId);
-            }
-        }
-        return null;
-    }
-
-    /** Returns the Advertising ID info as {@link AdvertisingIdInfo}. */
-    @SuppressWarnings("WeakerAccess") /* synthetic accessor */
-    @VisibleForTesting
-    @WorkerThread
-    @NonNull
-    static AdvertisingIdInfo getIdInfo(HoldingConnectionClient connectionClient)
-            throws IOException, AdvertisingIdNotAvailableException {
-        IAdvertisingIdService service = connectionClient.getIdService();
-
-        try {
-            String id = service.getId();
-            if (id == null || id.trim().isEmpty()) {
-                throw new AdvertisingIdNotAvailableException(
-                        "Advertising ID Provider does not returns an Advertising ID.");
-            }
-            return AdvertisingIdInfo.builder()
-                    .setId(id)
-                    .setProviderPackageName(connectionClient.getPackageName())
-                    .setLimitAdTrackingEnabled(service.isLimitAdTrackingEnabled())
-                    .build();
-        } catch (RemoteException e) {
-            throw new IOException("Remote exception", e);
-        } catch (RuntimeException e) {
-            throw new AdvertisingIdNotAvailableException(
-                    "Advertising ID Provider throws a exception.", e);
-        }
-    }
-
-    @VisibleForTesting
-    static void clearConnectionClient() {
-        sConnectionClient.set(null);
-    }
-
-    @VisibleForTesting
-    static boolean isConnected() {
-        HoldingConnectionClient connectionClient = sConnectionClient.get();
-        return connectionClient != null && connectionClient.isConnected();
-    }
-
-    /**
-     * Checks whether there is any Advertising ID Provider installed on the device.
-     *
-     * <p>This method does a quick check for the Advertising ID providers.
-     * <p>Note: Even if this method returns true, there is still a possibility that the
-     * {@link #getAdvertisingIdInfo(Context)} method throws an exception for some reason.
-     *
-     * @param context Current {@link Context} (such as the current {@link android.app.Activity}).
-     * @return whether there is an Advertising ID Provider available on the device.
-     */
-    public static boolean isAdvertisingIdProviderAvailable(@NonNull Context context) {
-        return !AdvertisingIdUtils.getAdvertisingIdProviderServices(context.getPackageManager())
-                .isEmpty();
-    }
-
-    /**
-     * Retrieves the user's Advertising ID info.
-     *
-     * <p>When multiple Advertising ID Providers are installed on the device, this method will
-     * always return the Advertising ID information from same Advertising ID Provider for all
-     * apps which use this library, using following priority:
-     * <ol>
-     * <li>System-level providers with "androidx.ads.identifier.provider.HIGH_PRIORITY" permission
-     * <li>Other system-level providers
-     * </ol>
-     * <p>If there are ties in any of the above categories, it will use this priority:
-     * <ol>
-     * <li>First app by earliest install time
-     * ({@link android.content.pm.PackageInfo#firstInstallTime})
-     * <li>First app by package name alphabetically sorted
-     * </ol>
-     *
-     * @param context Current {@link Context} (such as the current {@link android.app.Activity}).
-     * @return A {@link ListenableFuture} that will be fulfilled with a {@link AdvertisingIdInfo}
-     * which contains the user's Advertising ID info, or rejected with the following exceptions,
-     * <ul>
-     * <li><b>IOException</b> signaling connection to Advertising ID Providers failed.
-     * <li><b>AdvertisingIdNotAvailableException</b> indicating Advertising ID is not available,
-     * like no Advertising ID Provider found or provider does not return an Advertising ID.
-     * <li><b>TimeoutException</b> indicating timeout period (20s) has expired.
-     * <li><b>InterruptedException</b> indicating the current thread has been interrupted.
-     * </ul>
-     */
-    @NonNull
-    public static ListenableFuture<AdvertisingIdInfo> getAdvertisingIdInfo(
-            @NonNull Context context) {
-        final Context applicationContext = context.getApplicationContext();
-
-        return CallbackToFutureAdapter.getFuture(
-                new CallbackToFutureAdapter.Resolver<AdvertisingIdInfo>() {
-                    @Override
-                    public Object attachCompleter(
-                            @NonNull CallbackToFutureAdapter.Completer<AdvertisingIdInfo>
-                                    completer) {
-                        submitAdvertisingIdInfoTask(applicationContext, completer);
-                        return "getAdvertisingIdInfo";
-                    }
-                });
-    }
-
-    @SuppressWarnings("WeakerAccess") /* synthetic accessor */
-    static void submitAdvertisingIdInfoTask(
-            final Context applicationContext,
-            @NonNull final CallbackToFutureAdapter.Completer<AdvertisingIdInfo> completer) {
-        final Future<?> getIdInfoFuture = QUERY_EXECUTOR_SERVICE.submit(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    ConnectionPair connectionPair = getConnection(applicationContext);
-                    scheduleAutoDisconnect(connectionPair);
-                    completer.set(getIdInfo(connectionPair.getConnectionClient()));
-                } catch (IOException | AdvertisingIdNotAvailableException | TimeoutException
-                        | InterruptedException e) {
-                    completer.setException(e);
-                }
-            }
-        });
-        scheduleTimeoutCheck(getIdInfoFuture, completer);
-    }
-
-    @SuppressWarnings("FutureReturnValueIgnored")
-    private static void scheduleTimeoutCheck(
-            final Future<?> getIdInfoFuture,
-            @NonNull final CallbackToFutureAdapter.Completer<AdvertisingIdInfo> completer) {
-        SCHEDULED_EXECUTOR_SERVICE.schedule(new Runnable() {
-            @Override
-            public void run() {
-                if (!getIdInfoFuture.isDone()) {
-                    completer.setException(new TimeoutException());
-                    getIdInfoFuture.cancel(true);
-                }
-            }
-        }, TIMEOUT_SECONDS, TimeUnit.SECONDS);
-    }
-
-    @SuppressWarnings({"WeakerAccess", "FutureReturnValueIgnored"}) /* synthetic accessor */
-    static void scheduleAutoDisconnect(final ConnectionPair connectionPair) {
-        SCHEDULED_EXECUTOR_SERVICE.schedule(new Runnable() {
-            @Override
-            public void run() {
-                HoldingConnectionClient connectionClient = connectionPair.getConnectionClient();
-                if (connectionClient.tryFinish(connectionPair.getConnectionId())) {
-                    sConnectionClient.compareAndSet(connectionClient, null);
-                }
-            }
-        }, AUTO_DISCONNECT_SECONDS, TimeUnit.SECONDS);
-    }
-}
diff --git a/ads/ads-identifier/src/main/java/androidx/ads/identifier/AdvertisingIdInfo.java b/ads/ads-identifier/src/main/java/androidx/ads/identifier/AdvertisingIdInfo.java
deleted file mode 100644
index 1e6380d..0000000
--- a/ads/ads-identifier/src/main/java/androidx/ads/identifier/AdvertisingIdInfo.java
+++ /dev/null
@@ -1,72 +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.ads.identifier;
-
-import androidx.annotation.NonNull;
-
-import com.google.auto.value.AutoValue;
-
-/**
- * Advertising ID Information.
- * Includes both the Advertising ID and the limit ad tracking setting.
- *
- * @deprecated Use the
- * <a href="https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient">
- * Advertising ID API that's available as part of Google Play Services</a> instead of this library.
- */
-@Deprecated
-@AutoValue
-@AutoValue.CopyAnnotations
-public abstract class AdvertisingIdInfo {
-
-    // Create a no-args constructor so it doesn't appear in current.txt
-    AdvertisingIdInfo() {
-    }
-
-    /** Retrieves the Advertising ID. */
-    @NonNull
-    public abstract String getId();
-
-    /** Retrieves the Advertising ID provider package name. */
-    @NonNull
-    public abstract String getProviderPackageName();
-
-    /** Retrieves whether the user has set Limit Advertising Tracking. */
-    public abstract boolean isLimitAdTrackingEnabled();
-
-    /** Create a {@link Builder}. */
-    static Builder builder() {
-        return new AutoValue_AdvertisingIdInfo.Builder();
-    }
-
-    /** The builder for {@link AdvertisingIdInfo}. */
-    @AutoValue.Builder
-    abstract static class Builder {
-
-        // Create a no-args constructor so it doesn't appear in current.txt
-        Builder() {
-        }
-
-        abstract Builder setId(String id);
-
-        abstract Builder setProviderPackageName(String providerPackageName);
-
-        abstract Builder setLimitAdTrackingEnabled(boolean limitAdTrackingEnabled);
-
-        abstract AdvertisingIdInfo build();
-    }
-}
diff --git a/ads/ads-identifier/src/main/java/androidx/ads/identifier/AdvertisingIdNotAvailableException.java b/ads/ads-identifier/src/main/java/androidx/ads/identifier/AdvertisingIdNotAvailableException.java
deleted file mode 100644
index 3bb057d..0000000
--- a/ads/ads-identifier/src/main/java/androidx/ads/identifier/AdvertisingIdNotAvailableException.java
+++ /dev/null
@@ -1,37 +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.ads.identifier;
-
-import androidx.annotation.NonNull;
-
-/**
- * Indicates an AndroidX Advertising ID is not available.
- *
- * @deprecated Use the
- * <a href="https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient">
- * Advertising ID API that's available as part of Google Play Services</a> instead of this library.
- */
-@Deprecated
-public class AdvertisingIdNotAvailableException extends Exception {
-    public AdvertisingIdNotAvailableException(@NonNull String message) {
-        super(message);
-    }
-
-    public AdvertisingIdNotAvailableException(@NonNull String message, @NonNull Throwable cause) {
-        super(message, cause);
-    }
-}
diff --git a/ads/ads-identifier/src/main/java/androidx/ads/identifier/internal/HoldingConnectionClient.java b/ads/ads-identifier/src/main/java/androidx/ads/identifier/internal/HoldingConnectionClient.java
deleted file mode 100644
index 330cde5..0000000
--- a/ads/ads-identifier/src/main/java/androidx/ads/identifier/internal/HoldingConnectionClient.java
+++ /dev/null
@@ -1,232 +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.ads.identifier.internal;
-
-import static androidx.ads.identifier.AdvertisingIdUtils.GET_AD_ID_ACTION;
-
-import android.app.Service;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.ServiceInfo;
-import android.os.IBinder;
-
-import androidx.ads.identifier.AdvertisingIdUtils;
-import androidx.ads.identifier.provider.IAdvertisingIdService;
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
-import androidx.annotation.WorkerThread;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicLong;
-
-/** A client which keeps the ServiceConnection to the {@link IAdvertisingIdService}. */
-@SuppressWarnings("deprecation")
-public class HoldingConnectionClient {
-
-    private static final long SERVICE_CONNECTION_TIMEOUT_SECONDS = 10;
-
-    private final Context mContext;
-
-    @NonNull
-    private final BlockingServiceConnection mConnection;
-
-    @NonNull
-    private final String mPackageName;
-
-    @NonNull
-    private final IAdvertisingIdService mIdService;
-
-    /**
-     * The last connection ID which assign to the users of this client.
-     *
-     * <p>This also indicates the connection status, >= 0 indicates this client is connected,
-     * otherwise this client has already been disconnected.
-     * <p>It helps to synchronize between the usages of this client and auto disconnection task by
-     * using this single atomic, which supports 3 kinds of atomic operations:
-     * <ul>
-     *     <li>Checks whether this client is connected, if yes, increment and get a connection ID.
-     *     <li>When an auto disconnect task is due, it compares its connection ID to this value, if
-     *     same, unbind the service and sets this atomic to {@link Long#MIN_VALUE}.
-     *     <li>When this client's connection has lost and
-     *     {@link BlockingServiceConnection#onServiceDisconnected} is called, unbind the service
-     *     and sets this atomic to {@link Long#MIN_VALUE}.
-     * </ul>
-     * <p>This ID is monotonically increasing, except when this client is disconnected, this ID
-     * sets to {@link Long#MIN_VALUE}.
-     */
-    private final AtomicLong mLastConnectionId = new AtomicLong(0);
-
-    @WorkerThread
-    public HoldingConnectionClient(@NonNull Context context)
-            throws androidx.ads.identifier.AdvertisingIdNotAvailableException, IOException,
-            TimeoutException,
-            InterruptedException {
-        mContext = context;
-        ComponentName componentName = getProviderComponentName(mContext);
-        mConnection = getServiceConnection(componentName);
-        mIdService = getIdServiceFromConnection();
-        mPackageName = componentName.getPackageName();
-    }
-
-    /** Gets the connected {@link IAdvertisingIdService}. */
-    @NonNull
-    public IAdvertisingIdService getIdService() {
-        return mIdService;
-    }
-
-    /** Gets the connected service's package name. */
-    @NonNull
-    public String getPackageName() {
-        return mPackageName;
-    }
-
-    /** Gets whether the client is connected to the {@link IAdvertisingIdService}. */
-    public boolean isConnected() {
-        return mLastConnectionId.get() >= 0;
-    }
-
-    /**
-     * Gets a connection ID before using this client which prevents race condition with the auto
-     * disconnection task.
-     *
-     * @return connection ID, >= 0 indicates this client is connected, otherwise this client has
-     * already been disconnected.
-     */
-    public long askConnectionId() {
-        return mLastConnectionId.incrementAndGet();
-    }
-
-    /**
-     * Closes the connection to the Advertising ID Provider Service.
-     *
-     * <p>Note: If the connection has already been closed, does nothing.
-     */
-    void finish() {
-        if (mLastConnectionId.getAndSet(Long.MIN_VALUE) >= 0) {
-            mContext.unbindService(mConnection);
-        }
-    }
-
-    /**
-     * Tries to close the connection to the Advertising ID Provider Service if no one is using the
-     * client.
-     *
-     * @return true if this client is disconnected after this method returns.
-     */
-    public boolean tryFinish(long connectionId) {
-        if (mLastConnectionId.compareAndSet(connectionId, Long.MIN_VALUE)) {
-            mContext.unbindService(mConnection);
-            return true;
-        }
-        return !isConnected();
-    }
-
-    private static ComponentName getProviderComponentName(Context context)
-            throws androidx.ads.identifier.AdvertisingIdNotAvailableException {
-        PackageManager packageManager = context.getPackageManager();
-        List<ServiceInfo> serviceInfos =
-                AdvertisingIdUtils.getAdvertisingIdProviderServices(packageManager);
-        ServiceInfo serviceInfo =
-                AdvertisingIdUtils.selectServiceByPriority(serviceInfos, packageManager);
-        if (serviceInfo == null) {
-            throw new androidx.ads.identifier.AdvertisingIdNotAvailableException(
-                    "No compatible AndroidX Advertising ID Provider available.");
-        }
-        return new ComponentName(serviceInfo.packageName, serviceInfo.name);
-    }
-
-    /**
-     * Retrieves BlockingServiceConnection which must be unbound after use.
-     *
-     * @throws IOException when unable to bind service successfully.
-     */
-    @VisibleForTesting
-    BlockingServiceConnection getServiceConnection(ComponentName componentName) throws IOException {
-        Intent intent = new Intent(GET_AD_ID_ACTION);
-        intent.setComponent(componentName);
-
-        BlockingServiceConnection bsc = new BlockingServiceConnection();
-        if (mContext.bindService(intent, bsc, Service.BIND_AUTO_CREATE)) {
-            return bsc;
-        } else {
-            throw new IOException("Connection failure");
-        }
-    }
-
-    /**
-     * Gets the {@link IAdvertisingIdService} from the blocking queue. This should wait until
-     * {@link ServiceConnection#onServiceConnected} event with a
-     * {@link #SERVICE_CONNECTION_TIMEOUT_SECONDS} second timeout.
-     *
-     * @throws TimeoutException     if connection timeout period has expired.
-     * @throws InterruptedException if connection has been interrupted before connected.
-     */
-    @VisibleForTesting
-    @WorkerThread
-    IAdvertisingIdService getIdServiceFromConnection()
-            throws TimeoutException, InterruptedException {
-        // Block until the bind is complete, or timeout period is over.
-        return IAdvertisingIdService.Stub.asInterface(mConnection.getServiceWithTimeout());
-    }
-
-    /**
-     * A one-time use ServiceConnection that facilitates waiting for the bind to complete and the
-     * passing of the IBinder from the callback thread to the waiting thread.
-     */
-    class BlockingServiceConnection implements ServiceConnection {
-        // Facilitates passing of the IBinder across threads
-        private final BlockingQueue<IBinder> mBlockingQueue = new LinkedBlockingQueue<>();
-
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            mBlockingQueue.add(service);
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-            finish();
-        }
-
-        /**
-         * Blocks until the bind is complete with a timeout and returns the bound IBinder. This must
-         * only be called once.
-         *
-         * @return the IBinder of the bound service
-         * @throws InterruptedException if the current thread is interrupted while waiting for
-         *                              the bind
-         * @throws TimeoutException     if the timeout period has elapsed
-         */
-        @WorkerThread
-        @NonNull
-        IBinder getServiceWithTimeout() throws InterruptedException, TimeoutException {
-            IBinder binder =
-                    mBlockingQueue.poll(SERVICE_CONNECTION_TIMEOUT_SECONDS, TimeUnit.SECONDS);
-            if (binder == null) {
-                throw new TimeoutException("Timed out waiting for the service connection");
-            }
-            return binder;
-        }
-    }
-}
diff --git a/ads/ads-identifier/src/main/java/androidx/ads/identifier/internal/package-info.java b/ads/ads-identifier/src/main/java/androidx/ads/identifier/internal/package-info.java
deleted file mode 100644
index e9ad310..0000000
--- a/ads/ads-identifier/src/main/java/androidx/ads/identifier/internal/package-info.java
+++ /dev/null
@@ -1,25 +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.
- */
-
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-package androidx.ads.identifier.internal;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import androidx.annotation.RestrictTo;
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResetTimer.kt b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResetTimer.kt
index d62d99a..3198cc1 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResetTimer.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResetTimer.kt
@@ -26,7 +26,6 @@
 import androidx.appactions.interaction.capabilities.core.task.impl.AbstractTaskUpdater
 import androidx.appactions.interaction.capabilities.core.values.GenericErrorStatus
 import androidx.appactions.interaction.capabilities.core.values.SuccessStatus
-import androidx.appactions.interaction.capabilities.core.values.Timer
 import androidx.appactions.interaction.proto.ParamValue
 import androidx.appactions.interaction.protobuf.Struct
 import androidx.appactions.interaction.protobuf.Value
@@ -42,7 +41,7 @@
         "timer",
         { property -> Optional.ofNullable(property.timerList) },
         ResetTimer.Argument.Builder::setTimerList,
-        TypeConverters::toTimer
+        TimerValue.FROM_PARAM_VALUE
     ).bindOptionalOutput(
         "executionStatus",
         { output -> Optional.ofNullable(output.executionStatus) },
@@ -96,7 +95,7 @@
     }
 
     class Argument internal constructor(
-        val timerList: List<Timer>?
+        val timerList: List<TimerValue>?
     ) {
         override fun toString(): String {
             return "Argument(timerList=$timerList)"
@@ -118,9 +117,11 @@
         }
 
         class Builder : BuilderOf<Argument> {
-            private var timerList: List<Timer>? = null
+            private var timerList: List<TimerValue>? = null
 
-            fun setTimerList(timerList: List<Timer>): Builder = apply { this.timerList = timerList }
+            fun setTimerList(
+                timerList: List<TimerValue>,
+            ): Builder = apply { this.timerList = timerList }
 
             override fun build(): Argument = Argument(timerList)
         }
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimer.kt b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimer.kt
index 367ecce..4473c32 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimer.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/ResumeTimer.kt
@@ -26,7 +26,6 @@
 import androidx.appactions.interaction.capabilities.core.task.impl.AbstractTaskUpdater
 import androidx.appactions.interaction.capabilities.core.values.GenericErrorStatus
 import androidx.appactions.interaction.capabilities.core.values.SuccessStatus
-import androidx.appactions.interaction.capabilities.core.values.Timer
 import androidx.appactions.interaction.proto.ParamValue
 import androidx.appactions.interaction.protobuf.Struct
 import androidx.appactions.interaction.protobuf.Value
@@ -42,7 +41,7 @@
         "timer",
         { property -> Optional.ofNullable(property.timerList) },
         ResumeTimer.Argument.Builder::setTimerList,
-        TypeConverters::toTimer
+        TimerValue.FROM_PARAM_VALUE,
     ).bindOptionalOutput(
         "executionStatus",
         { output -> Optional.ofNullable(output.executionStatus) },
@@ -96,7 +95,7 @@
     }
 
     class Argument internal constructor(
-        val timerList: List<Timer>?
+        val timerList: List<TimerValue>?
     ) {
         override fun toString(): String {
             return "Argument(timerList=$timerList)"
@@ -118,9 +117,11 @@
         }
 
         class Builder : BuilderOf<Argument> {
-            private var timerList: List<Timer>? = null
+            private var timerList: List<TimerValue>? = null
 
-            fun setTimerList(timerList: List<Timer>): Builder = apply { this.timerList = timerList }
+            fun setTimerList(
+                timerList: List<TimerValue>,
+            ): Builder = apply { this.timerList = timerList }
 
             override fun build(): Argument = Argument(timerList)
         }
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StopTimer.kt b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StopTimer.kt
index 24e9407..10c06c0 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StopTimer.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/StopTimer.kt
@@ -26,7 +26,6 @@
 import androidx.appactions.interaction.capabilities.core.task.impl.AbstractTaskUpdater
 import androidx.appactions.interaction.capabilities.core.values.GenericErrorStatus
 import androidx.appactions.interaction.capabilities.core.values.SuccessStatus
-import androidx.appactions.interaction.capabilities.core.values.Timer
 import androidx.appactions.interaction.proto.ParamValue
 import androidx.appactions.interaction.protobuf.Struct
 import androidx.appactions.interaction.protobuf.Value
@@ -42,7 +41,7 @@
         "timer",
         { property -> Optional.ofNullable(property.timerList) },
         StopTimer.Argument.Builder::setTimerList,
-        TypeConverters::toTimer
+        TimerValue.FROM_PARAM_VALUE
     ).bindOptionalOutput(
         "executionStatus",
         { output -> Optional.ofNullable(output.executionStatus) },
@@ -96,7 +95,7 @@
     }
 
     class Argument internal constructor(
-        val timerList: List<Timer>?
+        val timerList: List<TimerValue>?
     ) {
         override fun toString(): String {
             return "Argument(timerList=$timerList)"
@@ -118,9 +117,11 @@
         }
 
         class Builder : BuilderOf<Argument> {
-            private var timerList: List<Timer>? = null
+            private var timerList: List<TimerValue>? = null
 
-            fun setTimerList(timerList: List<Timer>): Builder = apply { this.timerList = timerList }
+            fun setTimerList(
+                timerList: List<TimerValue>,
+            ): Builder = apply { this.timerList = timerList }
 
             override fun build(): Argument = Argument(timerList)
         }
diff --git a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/TimerValue.kt b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/TimerValue.kt
index 76515c8..42b5118 100644
--- a/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/TimerValue.kt
+++ b/appactions/interaction/interaction-capabilities-productivity/src/main/java/androidx/appactions/interaction/capabilities/productivity/TimerValue.kt
@@ -21,6 +21,7 @@
 import androidx.appactions.interaction.capabilities.core.impl.converters.UnionTypeSpec
 import androidx.appactions.interaction.capabilities.core.values.SearchAction
 import androidx.appactions.interaction.capabilities.core.values.Timer
+import java.util.Objects
 
 class TimerValue private constructor(
     val asTimer: Timer?,
@@ -31,6 +32,19 @@
     // TODO(b/268071906) add TimerFilter type to SearchAction
     constructor(timerFilter: SearchAction<Timer>) : this(null, timerFilter)
 
+    override fun equals(other: Any?): Boolean {
+        if (this === other) return true
+        if (javaClass != other?.javaClass) return false
+
+        other as TimerValue
+
+        return asTimer == other.asTimer && asTimerFilter == other.asTimerFilter
+    }
+
+    override fun hashCode(): Int {
+        return Objects.hash(asTimer, asTimerFilter)
+    }
+
     companion object {
         private val TYPE_SPEC = UnionTypeSpec.Builder<TimerValue>()
             .bindMemberType(
diff --git a/appcompat/appcompat/build.gradle b/appcompat/appcompat/build.gradle
index aea54f9..86dddcc 100644
--- a/appcompat/appcompat/build.gradle
+++ b/appcompat/appcompat/build.gradle
@@ -15,7 +15,7 @@
     implementation("androidx.core:core-ktx:1.8.0")
     implementation(libs.kotlinStdlib)
 
-    implementation("androidx.emoji2:emoji2:1.2.0")
+    implementation("androidx.emoji2:emoji2:1.3.0")
     implementation("androidx.emoji2:emoji2-views-helper:1.2.0")
     implementation("androidx.collection:collection:1.0.0")
     api("androidx.cursoradapter:cursoradapter:1.0.0")
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
index b162842..2d2bb9e 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt
@@ -946,6 +946,35 @@
                     dependencyConstraint
                 )
             }
+
+            // disallow duplicate constraints
+            project.configurations.all { config ->
+                // find all constraints contributed by this Configuration and its ancestors
+                val configurationConstraints: MutableSet<String> = mutableSetOf()
+                config.hierarchy.forEach { parentConfig ->
+                    parentConfig.dependencyConstraints.configureEach { dependencyConstraint ->
+                        dependencyConstraint.apply {
+                            if (
+                                versionConstraint.requiredVersion != "" &&
+                                versionConstraint.requiredVersion != "unspecified"
+                            ) {
+                                val key =
+                                    "${dependencyConstraint.group}:${dependencyConstraint.name}"
+                                if (configurationConstraints.contains(key)) {
+                                    throw GradleException(
+                                        "Constraint on $key was added multiple times in " +
+                                        "$config (version = " +
+                                        "${versionConstraint.requiredVersion}).\n\n" +
+                                        "This is unnecessary and can also trigger " +
+                                        "https://github.com/gradle/gradle/issues/24037 in " +
+                                        "builds trying to use the resulting artifacts.")
+                                }
+                                configurationConstraints.add(key)
+                            }
+                        }
+                    }
+                }
+            }
         }
     }
 
diff --git a/buildSrc/private/src/main/kotlin/androidx/build/Ktlint.kt b/buildSrc/private/src/main/kotlin/androidx/build/Ktlint.kt
index b878c8b..3290247 100644
--- a/buildSrc/private/src/main/kotlin/androidx/build/Ktlint.kt
+++ b/buildSrc/private/src/main/kotlin/androidx/build/Ktlint.kt
@@ -233,6 +233,7 @@
             javaExecSpec.mainClass.set(MainClass)
             javaExecSpec.classpath = ktlintClasspath
             javaExecSpec.args = getArgsList(shouldFormat = true)
+            javaExecSpec.jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED")
             overrideDirectory?.let { javaExecSpec.workingDir = it }
         }
     }
diff --git a/camera/camera-core/api/current.txt b/camera/camera-core/api/current.txt
index 2f9f00d..1f0d922 100644
--- a/camera/camera-core/api/current.txt
+++ b/camera/camera-core/api/current.txt
@@ -401,7 +401,7 @@
     ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
   }
 
-  public interface SurfaceOutput {
+  public interface SurfaceOutput extends java.io.Closeable {
     method public void close();
     method public android.util.Size getSize();
     method public android.view.Surface getSurface(java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceOutput.Event!>);
@@ -410,7 +410,6 @@
   }
 
   @com.google.auto.value.AutoValue public abstract static class SurfaceOutput.Event {
-    ctor public SurfaceOutput.Event();
     method public abstract int getEventCode();
     method public abstract androidx.camera.core.SurfaceOutput getSurfaceOutput();
     field public static final int EVENT_REQUEST_CLOSE = 0; // 0x0
diff --git a/camera/camera-core/api/public_plus_experimental_current.txt b/camera/camera-core/api/public_plus_experimental_current.txt
index 7f210f6..38b65a3 100644
--- a/camera/camera-core/api/public_plus_experimental_current.txt
+++ b/camera/camera-core/api/public_plus_experimental_current.txt
@@ -418,7 +418,7 @@
     ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
   }
 
-  public interface SurfaceOutput {
+  public interface SurfaceOutput extends java.io.Closeable {
     method public void close();
     method public android.util.Size getSize();
     method public android.view.Surface getSurface(java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceOutput.Event!>);
@@ -427,7 +427,6 @@
   }
 
   @com.google.auto.value.AutoValue public abstract static class SurfaceOutput.Event {
-    ctor public SurfaceOutput.Event();
     method public abstract int getEventCode();
     method public abstract androidx.camera.core.SurfaceOutput getSurfaceOutput();
     field public static final int EVENT_REQUEST_CLOSE = 0; // 0x0
diff --git a/camera/camera-core/api/restricted_current.txt b/camera/camera-core/api/restricted_current.txt
index 2f9f00d..1f0d922 100644
--- a/camera/camera-core/api/restricted_current.txt
+++ b/camera/camera-core/api/restricted_current.txt
@@ -401,7 +401,7 @@
     ctor public SurfaceOrientedMeteringPointFactory(float, float, androidx.camera.core.UseCase);
   }
 
-  public interface SurfaceOutput {
+  public interface SurfaceOutput extends java.io.Closeable {
     method public void close();
     method public android.util.Size getSize();
     method public android.view.Surface getSurface(java.util.concurrent.Executor, androidx.core.util.Consumer<androidx.camera.core.SurfaceOutput.Event!>);
@@ -410,7 +410,6 @@
   }
 
   @com.google.auto.value.AutoValue public abstract static class SurfaceOutput.Event {
-    ctor public SurfaceOutput.Event();
     method public abstract int getEventCode();
     method public abstract androidx.camera.core.SurfaceOutput getSurfaceOutput();
     field public static final int EVENT_REQUEST_CLOSE = 0; // 0x0
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/ProcessingNodeDeviceTest.kt b/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/ProcessingNodeDeviceTest.kt
index 72bc72c9..c6c231e 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/ProcessingNodeDeviceTest.kt
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/imagecapture/ProcessingNodeDeviceTest.kt
@@ -148,7 +148,7 @@
             takePictureCallback,
             Futures.immediateFuture(null)
         )
-        val input = ProcessingNode.InputPacket.of(processingRequest, imageIn)
+        val input = ProcessingNode.InputPacket.of(processingRequest, imageIn, false)
         // Act and return.
         nodeIn.edge.accept(input)
         return if (outputFileOptions == null) {
@@ -184,7 +184,7 @@
             CameraCaptureResultImageInfo(CAMERA_CAPTURE_RESULT),
             createJpegBytes(WIDTH, HEIGHT)
         )
-        val input = ProcessingNode.InputPacket.of(processingRequest, imageIn)
+        val input = ProcessingNode.InputPacket.of(processingRequest, imageIn, false)
         // Act and return.
         nodeIn.edge.accept(input)
         val filePath = takePictureCallback.getOnDiskResult().savedUri!!.path!!
@@ -223,7 +223,7 @@
             createJpegBytes(WIDTH, HEIGHT)
         )
         // Act.
-        val input = ProcessingNode.InputPacket.of(processingRequest, imageIn)
+        val input = ProcessingNode.InputPacket.of(processingRequest, imageIn, false)
         // Act and return.
         nodeIn.edge.accept(input)
         // Assert: the output image is identical to the input.
@@ -257,7 +257,7 @@
             takePictureCallback,
             Futures.immediateFuture(null)
         )
-        val input = ProcessingNode.InputPacket.of(processingRequest, imageIn)
+        val input = ProcessingNode.InputPacket.of(processingRequest, imageIn, false)
 
         // Act: send input to the edge and wait for the saved URI
         nodeIn.edge.accept(input)
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
index 159f7ff..0c7ebbf 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
@@ -247,20 +247,17 @@
 
     /**
      * When flash is required for taking a picture, a normal one shot flash will be used.
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     public static final int FLASH_TYPE_ONE_SHOT_FLASH = 0;
     /**
      * When flash is required for taking a picture, torch will be used as flash.
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     public static final int FLASH_TYPE_USE_TORCH_AS_FLASH = 1;
 
     /**
      * Provides a static configuration with implementation-agnostic options.
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     public static final Defaults DEFAULT_CONFIG = new Defaults();
@@ -506,7 +503,6 @@
 
     /**
      * {@inheritDoc}
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @Override
@@ -527,7 +523,6 @@
 
     /**
      * {@inheritDoc}
-     *
      */
     @NonNull
     @RestrictTo(Scope.LIBRARY_GROUP)
@@ -538,7 +533,6 @@
 
     /**
      * {@inheritDoc}
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @NonNull
@@ -611,7 +605,6 @@
 
     /**
      * Configures flash mode to CameraControlInternal once it is ready.
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @Override
@@ -905,7 +898,6 @@
 
     /**
      * {@inheritDoc}
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @Nullable
@@ -1100,7 +1092,6 @@
 
     /**
      * {@inheritDoc}
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @UiThread
@@ -1567,7 +1558,6 @@
 
     /**
      * {@inheritDoc}
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     @Override
@@ -1579,7 +1569,6 @@
 
     /**
      * {@inheritDoc}
-     *
      */
     @Override
     @RestrictTo(Scope.LIBRARY_GROUP)
@@ -1599,7 +1588,6 @@
 
     /**
      * {@inheritDoc}
-     *
      */
     @NonNull
     @Override
@@ -1739,7 +1727,8 @@
         Size resolution = streamSpec.getResolution();
 
         checkState(mImagePipeline == null);
-        mImagePipeline = new ImagePipeline(config, resolution, getEffect());
+        mImagePipeline = new ImagePipeline(config, resolution, getEffect(),
+                !requireNonNull(getCamera()).getHasTransform());
 
         if (mTakePictureManager == null) {
             // mTakePictureManager is reused when the Surface is reset.
@@ -1907,7 +1896,6 @@
      *
      * <p>This is a parameter sent to the error callback functions set in listeners such as {@link
      * ImageCapture.OnImageSavedCallback#onError(ImageCaptureException)}.
-     *
      */
     @IntDef({ERROR_UNKNOWN, ERROR_FILE_IO, ERROR_CAPTURE_FAILED, ERROR_CAMERA_CLOSED,
             ERROR_INVALID_CAMERA})
@@ -1919,7 +1907,6 @@
     /**
      * Capture mode options for ImageCapture. A picture will always be taken regardless of
      * mode, and the mode will be used on devices that support it.
-     *
      */
     @IntDef({CAPTURE_MODE_MAXIMIZE_QUALITY, CAPTURE_MODE_MINIMIZE_LATENCY,
             CAPTURE_MODE_ZERO_SHUTTER_LAG})
@@ -1940,7 +1927,6 @@
      * will remain enabled during photo capture regardless of flash mode setting. When
      * the torch is disabled, flash will function as specified by
      * {@link #setFlashMode(int)}.
-     *
      */
     @IntDef({FLASH_MODE_UNKNOWN, FLASH_MODE_AUTO, FLASH_MODE_ON, FLASH_MODE_OFF})
     @Retention(RetentionPolicy.SOURCE)
@@ -1950,7 +1936,6 @@
 
     /**
      * The flash type options when flash is required for taking a picture.
-     *
      */
     @IntDef({FLASH_TYPE_ONE_SHOT_FLASH, FLASH_TYPE_USE_TORCH_AS_FLASH})
     @Retention(RetentionPolicy.SOURCE)
@@ -2024,7 +2009,6 @@
      *
      * <p>These values may be overridden by the implementation. They only provide a minimum set of
      * defaults that are implementation independent.
-     *
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
     public static final class Defaults
@@ -2092,6 +2076,7 @@
         }
 
         /**
+         *
          */
         @Nullable
         @RestrictTo(Scope.LIBRARY_GROUP)
@@ -2100,6 +2085,7 @@
         }
 
         /**
+         *
          */
         @Nullable
         @RestrictTo(Scope.LIBRARY_GROUP)
@@ -2108,6 +2094,7 @@
         }
 
         /**
+         *
          */
         @Nullable
         @RestrictTo(Scope.LIBRARY_GROUP)
@@ -2116,6 +2103,7 @@
         }
 
         /**
+         *
          */
         @Nullable
         @RestrictTo(Scope.LIBRARY_GROUP)
@@ -2124,6 +2112,7 @@
         }
 
         /**
+         *
          */
         @Nullable
         @RestrictTo(Scope.LIBRARY_GROUP)
@@ -2135,7 +2124,6 @@
          * Exposed internally so that CameraController can overwrite the flip horizontal flag for
          * front camera. External core API users shouldn't need this because they are the ones who
          * created the {@link Metadata}.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -2254,6 +2242,7 @@
         private final Uri mSavedUri;
 
         /**
+         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         public OutputFileResults(@Nullable Uri savedUri) {
@@ -2316,7 +2305,6 @@
          *
          * <p> CameraController's default behavior is mirroring the picture when front camera is
          * used. This method is used to check if reverseHorizontal is set explicitly by the app.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         public boolean isReversedHorizontalSet() {
@@ -2576,7 +2564,6 @@
 
         /**
          * {@inheritDoc}
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @Override
@@ -2587,7 +2574,6 @@
 
         /**
          * {@inheritDoc}
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -2824,7 +2810,6 @@
 
         /**
          * setMirrorMode is not supported on ImageCapture.
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -3072,7 +3057,6 @@
 
         /**
          * {@inheritDoc}
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
@@ -3084,7 +3068,6 @@
 
         /**
          * {@inheritDoc}
-         *
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/SurfaceOutput.java b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceOutput.java
index be20322..0cde5ad 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/SurfaceOutput.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/SurfaceOutput.java
@@ -16,6 +16,8 @@
 
 package androidx.camera.core;
 
+import static androidx.camera.core.impl.ImageFormatConstants.INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE;
+
 import android.graphics.SurfaceTexture;
 import android.util.Size;
 import android.view.Surface;
@@ -27,6 +29,7 @@
 
 import com.google.auto.value.AutoValue;
 
+import java.io.Closeable;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.concurrent.Executor;
@@ -39,7 +42,7 @@
  *
  * @see SurfaceProcessor#onOutputSurface(SurfaceOutput)
  */
-public interface SurfaceOutput {
+public interface SurfaceOutput extends Closeable {
 
     /**
      * Gets the {@link Surface} for drawing processed frames.
@@ -67,11 +70,12 @@
 
     /**
      * This field indicates the format of the {@link Surface}.
-     *
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
     @CameraEffect.Formats
-    int getFormat();
+    default int getFormat() {
+        return INTERNAL_DEFINED_IMAGE_FORMAT_PRIVATE;
+    }
 
     /**
      * Gets the size of the {@link Surface}.
@@ -87,16 +91,10 @@
      * {@link Surface}. Writing to the {@link Surface} after calling this method might cause
      * errors.
      */
+    @Override
     void close();
 
     /**
-     * Asks the {@link SurfaceProcessor} implementation to stopping writing to the {@link Surface}.
-     *
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-    void requestClose();
-
-    /**
      * Applies an additional 4x4 transformation on the original matrix.
      *
      * <p>When the input {@link Surface} of {@link SurfaceProcessor} is backed by a
@@ -158,9 +156,11 @@
     @AutoValue
     abstract class Event {
 
+        Event() {
+        }
+
         /**
          * Possible event codes.
-         *
          */
         @IntDef({EVENT_REQUEST_CLOSE})
         @Retention(RetentionPolicy.SOURCE)
@@ -195,7 +195,6 @@
 
         /**
          * Creates a {@link Event} for sending to the implementation.
-         *
          */
         @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
         @NonNull
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/CaptureNode.java b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/CaptureNode.java
index 3cdb6fe..1f59ef1 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/CaptureNode.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/CaptureNode.java
@@ -120,7 +120,7 @@
         inputEdge.getRequestEdge().setListener(this::onRequestAvailable);
         inputEdge.getErrorEdge().setListener(this::sendCaptureError);
 
-        mOutputEdge = Out.of(inputEdge.getFormat());
+        mOutputEdge = Out.of(inputEdge.getFormat(), inputEdge.isVirtualCamera());
         return mOutputEdge;
     }
 
@@ -257,6 +257,11 @@
         abstract int getFormat();
 
         /**
+         * Whether the pipeline is connected to a virtual camera.
+         */
+        abstract boolean isVirtualCamera();
+
+        /**
          * Edge that accepts {@link ProcessingRequest}.
          */
         @NonNull
@@ -297,8 +302,9 @@
         }
 
         @NonNull
-        static In of(Size size, int format) {
-            return new AutoValue_CaptureNode_In(size, format, new Edge<>(), new Edge<>());
+        static In of(Size size, int format, boolean isVirtualCamera) {
+            return new AutoValue_CaptureNode_In(size, format, isVirtualCamera,
+                    new Edge<>(), new Edge<>());
         }
     }
 
@@ -325,8 +331,14 @@
          */
         abstract int getFormat();
 
-        static Out of(int format) {
-            return new AutoValue_CaptureNode_Out(new Edge<>(), new Edge<>(), format);
+        /**
+         * Whether the pipeline is connected to a virtual camera.
+         */
+        abstract boolean isVirtualCamera();
+
+        static Out of(int format, boolean isVirtualCamera) {
+            return new AutoValue_CaptureNode_Out(new Edge<>(), new Edge<>(), format,
+                    isVirtualCamera);
         }
     }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ImagePipeline.java b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ImagePipeline.java
index fc8a4af..6c28158 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ImagePipeline.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ImagePipeline.java
@@ -88,14 +88,16 @@
     public ImagePipeline(
             @NonNull ImageCaptureConfig useCaseConfig,
             @NonNull Size cameraSurfaceSize) {
-        this(useCaseConfig, cameraSurfaceSize, /*cameraEffect=*/ null);
+        this(useCaseConfig, cameraSurfaceSize, /*cameraEffect=*/ null,
+                /*isVirtualCamera=*/ false);
     }
 
     @MainThread
     public ImagePipeline(
             @NonNull ImageCaptureConfig useCaseConfig,
             @NonNull Size cameraSurfaceSize,
-            @Nullable CameraEffect cameraEffect) {
+            @Nullable CameraEffect cameraEffect,
+            boolean isVirtualCamera) {
         checkMainThread();
         mUseCaseConfig = useCaseConfig;
         mCaptureConfig = CaptureConfig.Builder.createFrom(useCaseConfig).build();
@@ -108,7 +110,8 @@
                 cameraEffect != null ? new InternalImageProcessor(cameraEffect) : null);
 
         // Connect nodes
-        mPipelineIn = CaptureNode.In.of(cameraSurfaceSize, mUseCaseConfig.getInputFormat());
+        mPipelineIn = CaptureNode.In.of(cameraSurfaceSize, mUseCaseConfig.getInputFormat(),
+                isVirtualCamera);
         CaptureNode.Out captureOut = mCaptureNode.transform(mPipelineIn);
         ProcessingNode.In processingIn = mBundlingNode.transform(captureOut);
         mProcessingNode.transform(processingIn);
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingInput2Packet.java b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingInput2Packet.java
index 4109418..318f126 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingInput2Packet.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingInput2Packet.java
@@ -74,7 +74,9 @@
                 throw new ImageCaptureException(ERROR_FILE_IO, "Failed to extract EXIF data.", e);
             }
         }
-        if (EXIF_ROTATION_AVAILABILITY.shouldUseExifOrientation(image)) {
+        if (EXIF_ROTATION_AVAILABILITY.shouldUseExifOrientation(image)
+                && !inputPacket.isVirtualCamera()) {
+            // Virtual camera doesn't respect the CaptureRequest rotation degrees.
             checkNotNull(exif, "JPEG image must have exif.");
             return createPacketWithHalRotation(request, exif, image);
         }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingNode.java b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingNode.java
index b4e15fc..f53cae3 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingNode.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/ProcessingNode.java
@@ -225,9 +225,15 @@
         @NonNull
         abstract ImageProxy getImageProxy();
 
+        /**
+         * Whether the pipeline is connected to a virtual camera.
+         */
+        abstract boolean isVirtualCamera();
+
         static InputPacket of(@NonNull ProcessingRequest processingRequest,
-                @NonNull ImageProxy imageProxy) {
-            return new AutoValue_ProcessingNode_InputPacket(processingRequest, imageProxy);
+                @NonNull ImageProxy imageProxy, boolean isVirtualCamera) {
+            return new AutoValue_ProcessingNode_InputPacket(processingRequest, imageProxy,
+                    isVirtualCamera);
         }
     }
 
@@ -253,8 +259,8 @@
     }
 
     @VisibleForTesting
-    void injectJpegBytes2CroppedBitmapForTesting(
-            @NonNull Operation<Packet<byte[]>, Packet<Bitmap>> operation) {
-        mJpegBytes2CroppedBitmap = operation;
+    void injectProcessingInput2Packet(
+            @NonNull Operation<InputPacket, Packet<ImageProxy>> input2Packet) {
+        mInput2Packet = input2Packet;
     }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/SingleBundlingNode.java b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/SingleBundlingNode.java
index 3cb95720..1af04d6 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/SingleBundlingNode.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/imagecapture/SingleBundlingNode.java
@@ -43,10 +43,12 @@
 
     ProcessingRequest mPendingRequest;
     private ProcessingNode.In mOutputEdge;
+    private boolean mIsVirtualCamera;
 
     @NonNull
     @Override
     public ProcessingNode.In transform(@NonNull CaptureNode.Out captureNodeOut) {
+        mIsVirtualCamera = captureNodeOut.isVirtualCamera();
         // Listen to input edges.
         captureNodeOut.getImageEdge().setListener(this::matchImageWithRequest);
         captureNodeOut.getRequestEdge().setListener(this::trackIncomingRequest);
@@ -95,7 +97,7 @@
         checkState(stageId == mPendingRequest.getStageIds().get(0));
 
         mOutputEdge.getEdge().accept(
-                ProcessingNode.InputPacket.of(mPendingRequest, imageProxy));
+                ProcessingNode.InputPacket.of(mPendingRequest, imageProxy, mIsVirtualCamera));
         mPendingRequest = null;
     }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOutputImpl.java b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOutputImpl.java
index 17715d6..64a682b 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOutputImpl.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/processing/SurfaceOutputImpl.java
@@ -39,6 +39,7 @@
 import androidx.camera.core.CameraEffect;
 import androidx.camera.core.Logger;
 import androidx.camera.core.SurfaceOutput;
+import androidx.camera.core.SurfaceProcessor;
 import androidx.camera.core.impl.CameraInternal;
 import androidx.concurrent.futures.CallbackToFutureAdapter;
 import androidx.core.util.Consumer;
@@ -142,9 +143,8 @@
     }
 
     /**
-     * @inheritDoc
+     * Asks the {@link SurfaceProcessor} implementation to stopping writing to the {@link Surface}.
      */
-    @Override
     public void requestClose() {
         AtomicReference<Consumer<Event>> eventListenerRef = new AtomicReference<>();
         Executor executor = null;
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/CaptureNodeTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/CaptureNodeTest.kt
index c904b5d..acc1781 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/CaptureNodeTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/CaptureNodeTest.kt
@@ -52,7 +52,7 @@
 
     @Before
     fun setUp() {
-        captureNodeIn = CaptureNode.In.of(Size(10, 10), ImageFormat.JPEG)
+        captureNodeIn = CaptureNode.In.of(Size(10, 10), ImageFormat.JPEG, false)
         captureNodeOut = captureNode.transform(captureNodeIn)
         captureNodeOut.imageEdge.setListener {
             imagePropagated.add(it)
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ImagePipelineTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ImagePipelineTest.kt
index 9d65a9e0..eeb5846 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ImagePipelineTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ImagePipelineTest.kt
@@ -17,6 +17,7 @@
 package androidx.camera.core.imagecapture
 
 import android.graphics.ImageFormat
+import android.graphics.Matrix
 import android.graphics.Rect
 import android.hardware.camera2.CameraDevice
 import android.os.Build
@@ -49,8 +50,10 @@
 import androidx.camera.core.impl.utils.executor.CameraXExecutors.mainThreadExecutor
 import androidx.camera.core.impl.utils.futures.Futures
 import androidx.camera.core.internal.IoConfig.OPTION_IO_EXECUTOR
+import androidx.camera.core.processing.Packet
 import androidx.camera.testing.TestImageUtil.createJpegBytes
 import androidx.camera.testing.TestImageUtil.createJpegFakeImageProxy
+import androidx.camera.testing.fakes.FakeCameraCaptureResult
 import androidx.camera.testing.fakes.FakeImageInfo
 import androidx.camera.testing.fakes.FakeImageReaderProxy
 import androidx.camera.testing.fakes.GrayscaleImageEffect
@@ -111,12 +114,44 @@
             ImagePipeline(
                 imageCaptureConfig,
                 SIZE,
-                GrayscaleImageEffect()
+                GrayscaleImageEffect(),
+                false
             ).processingNode.mImageProcessor
         ).isNotNull()
     }
 
     @Test
+    fun createPipelineWithVirtualCamera_plumbedToProcessingInput2PacketOperation() {
+        // Arrange: create a pipeline with a virtual camera.
+        val pipeline = ImagePipeline(
+            imageCaptureConfig,
+            SIZE,
+            GrayscaleImageEffect(),
+            true
+        )
+        // Listen to the input to packet operation.
+        var isVirtualCamera = false
+        pipeline.processingNode.injectProcessingInput2Packet {
+            isVirtualCamera = it.isVirtualCamera
+            return@injectProcessingInput2Packet Packet.of(
+                it.imageProxy,
+                null,
+                it.imageProxy.cropRect,
+                it.imageProxy.format,
+                Matrix(),
+                FakeCameraCaptureResult()
+            )
+        }
+
+        // Act: send in-memory request.
+        sendInMemoryRequest(pipeline)
+
+        // Assert: the input packet is marked as from a virtual camera.
+        assertThat(isVirtualCamera).isTrue()
+        pipeline.close()
+    }
+
+    @Test
     fun createRequests_verifyCameraRequest() {
         // Arrange.
         val captureInput = imagePipeline.captureNode.inputEdge
@@ -264,6 +299,17 @@
 
     @Test
     fun sendInMemoryRequest_receivesImageProxy() {
+        // Arrange & act.
+        val image = sendInMemoryRequest(imagePipeline)
+
+        // Assert: the image is received by TakePictureCallback.
+        assertThat(CALLBACK.inMemoryResult!!.planes).isEqualTo(image.planes)
+    }
+
+    /**
+     * Creates a ImageProxy and sends it to the pipeline.
+     */
+    private fun sendInMemoryRequest(pipeline: ImagePipeline): ImageProxy {
         // Arrange.
         val processingRequest = imagePipeline.createRequests(
             IN_MEMORY_REQUEST, CALLBACK, Futures.immediateFuture(null)
@@ -276,12 +322,11 @@
         val image = createJpegFakeImageProxy(imageInfo, jpegBytes)
 
         // Act: send processing request and the image.
-        imagePipeline.submitProcessingRequest(processingRequest)
-        imagePipeline.captureNode.onImageProxyAvailable(image)
+        pipeline.submitProcessingRequest(processingRequest)
+        pipeline.captureNode.onImageProxyAvailable(image)
         shadowOf(getMainLooper()).idle()
 
-        // Assert: the image is received by TakePictureCallback.
-        assertThat(CALLBACK.inMemoryResult!!.planes).isEqualTo(image.planes)
+        return image
     }
 
     @Test
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingInput2PacketTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingInput2PacketTest.kt
index 4d024c5..096fea8 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingInput2PacketTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingInput2PacketTest.kt
@@ -65,7 +65,7 @@
             HEIGHT
         )
         val processingRequest = createProcessingRequest()
-        val input = ProcessingNode.InputPacket.of(processingRequest, image)
+        val input = ProcessingNode.InputPacket.of(processingRequest, image, false)
 
         // Act.
         val output = operation.apply(input)
@@ -89,7 +89,7 @@
         }
         val image = createJpegFakeImageProxy(jpegBytes)
         val processingRequest = createProcessingRequest()
-        val input = ProcessingNode.InputPacket.of(processingRequest, image)
+        val input = ProcessingNode.InputPacket.of(processingRequest, image, false)
 
         // Act.
         val output = operation.apply(input)
@@ -121,7 +121,7 @@
             FakeTakePictureCallback(),
             Futures.immediateFuture(null)
         )
-        val input = ProcessingNode.InputPacket.of(processingRequest, image)
+        val input = ProcessingNode.InputPacket.of(processingRequest, image, false)
 
         // Act.
         val output = operation.apply(input)
@@ -146,7 +146,25 @@
         injectRotationOptionQuirk()
         val image = createJpegFakeImageProxy(createJpegBytes(WIDTH, HEIGHT))
         val processingRequest = createProcessingRequest()
-        val input = ProcessingNode.InputPacket.of(processingRequest, image)
+        val input = ProcessingNode.InputPacket.of(processingRequest, image, false)
+
+        // Act.
+        val output = operation.apply(input)
+
+        // Assert: the metadata are based on Packet only.
+        assertThat(output.cropRect).isEqualTo(CROP_RECT)
+        assertThat(output.rotationDegrees).isEqualTo(ROTATION_DEGREES)
+        assertThat(output.format).isEqualTo(ImageFormat.JPEG)
+        assertThat(output.size).isEqualTo(Size(WIDTH, HEIGHT))
+        assertThat(output.sensorToBufferTransform).isEqualTo(SENSOR_TO_BUFFER)
+    }
+
+    @Test
+    fun isVirtualCamera_outputIgnoresExifRotation() {
+        // Arrange: create input
+        val image = createJpegFakeImageProxy(createJpegBytes(WIDTH, HEIGHT))
+        val processingRequest = createProcessingRequest()
+        val input = ProcessingNode.InputPacket.of(processingRequest, image, true)
 
         // Act.
         val output = operation.apply(input)
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingNodeTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingNodeTest.kt
index b16a6b2..0234bed8 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingNodeTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/ProcessingNodeTest.kt
@@ -81,7 +81,7 @@
         // Act: process the request.
         val jpegBytes = createJpegBytes(WIDTH, HEIGHT)
         val image = createJpegFakeImageProxy(jpegBytes)
-        processingNodeIn.edge.accept(ProcessingNode.InputPacket.of(request, image))
+        processingNodeIn.edge.accept(ProcessingNode.InputPacket.of(request, image, false))
         shadowOf(getMainLooper()).idle()
 
         // Assert: the image is not saved.
@@ -94,7 +94,7 @@
         val takePictureCallback = FakeTakePictureCallback()
         val image = FakeImageProxy(FakeImageInfo())
         val processingRequest = createProcessingRequest(takePictureCallback)
-        val input = ProcessingNode.InputPacket.of(processingRequest, image)
+        val input = ProcessingNode.InputPacket.of(processingRequest, image, false)
 
         // Act: send input to the edge and wait for callback
         processingNodeIn.edge.accept(input)
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/SingleBundlingNodeTest.kt b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/SingleBundlingNodeTest.kt
index 56db6a2b..e04e4c4 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/SingleBundlingNodeTest.kt
+++ b/camera/camera-core/src/test/java/androidx/camera/core/imagecapture/SingleBundlingNodeTest.kt
@@ -44,7 +44,7 @@
 
     @Before
     fun setUp() {
-        captureNodeOut = CaptureNode.Out.of(ImageFormat.JPEG)
+        captureNodeOut = CaptureNode.Out.of(ImageFormat.JPEG, false)
         matchingNodeOut = node.transform(captureNodeOut)
         matchingNodeOut.edge.setListener {
             packetPropagated.add(it)
diff --git a/car/app/app/api/public_plus_experimental_current.txt b/car/app/app/api/public_plus_experimental_current.txt
index 5b45600..984fdf6 100644
--- a/car/app/app/api/public_plus_experimental_current.txt
+++ b/car/app/app/api/public_plus_experimental_current.txt
@@ -994,13 +994,17 @@
   }
 
   @androidx.car.app.annotations.CarProtocol @androidx.car.app.annotations.ExperimentalCarApi @androidx.car.app.annotations.RequiresCarApi(7) public class Badge {
+    method public androidx.car.app.model.CarColor? getBackgroundColor();
+    method public androidx.car.app.model.CarIcon? getIcon();
     method public boolean hasDot();
   }
 
   public static final class Badge.Builder {
     ctor public Badge.Builder();
     method public androidx.car.app.model.Badge build();
+    method public androidx.car.app.model.Badge.Builder setBackgroundColor(androidx.car.app.model.CarColor);
     method public androidx.car.app.model.Badge.Builder setHasDot(boolean);
+    method public androidx.car.app.model.Badge.Builder setIcon(androidx.car.app.model.CarIcon);
   }
 
   @androidx.car.app.annotations.CarProtocol public final class CarColor {
diff --git a/car/app/app/src/main/java/androidx/car/app/model/Badge.java b/car/app/app/src/main/java/androidx/car/app/model/Badge.java
index 7d799df..ade526c 100644
--- a/car/app/app/src/main/java/androidx/car/app/model/Badge.java
+++ b/car/app/app/src/main/java/androidx/car/app/model/Badge.java
@@ -39,27 +39,49 @@
 public class Badge {
 
     private final boolean mHasDot;
+    @Nullable
+    private final CarColor mBackgroundColor;
+    @Nullable
+    private final CarIcon mIcon;
 
     /**
      * Returns whether the badge has a dot.
      *
-     * @see Builder#setHasDot()
+     * @see Builder#setHasDot(boolean)
      */
     public boolean hasDot() {
         return mHasDot;
     }
 
+    /**
+     * Returns the dot background color.
+     */
+    @Nullable
+    public CarColor getBackgroundColor() {
+        return mBackgroundColor;
+    }
+
+    /**
+     * Returns the badge icon.
+     *
+     * @see Builder#setIcon(CarIcon)
+     */
+    @Nullable
+    public CarIcon getIcon() {
+        return mIcon;
+    }
+
     @Override
     @NonNull
     public String toString() {
-        return "[hasDot: "
-                + mHasDot
-                + "]";
+        return "[hasDot: " + mHasDot
+                + ", backgroundColor: " + mBackgroundColor
+                + ", icon: " + mIcon + "]";
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mHasDot);
+        return Objects.hash(mHasDot, mBackgroundColor, mIcon);
     }
 
     @Override
@@ -72,21 +94,31 @@
         }
         Badge otherBadge = (Badge) other;
 
-        return mHasDot == otherBadge.mHasDot;
+        return mHasDot == otherBadge.mHasDot
+                && Objects.equals(mBackgroundColor, otherBadge.mBackgroundColor)
+                && Objects.equals(mIcon, otherBadge.mIcon);
     }
 
     Badge(Builder builder) {
         mHasDot = builder.mHasDot;
+        mBackgroundColor = builder.mBackgroundColor;
+        mIcon = builder.mIcon;
     }
 
     /** Constructs an empty instance, used by serialization code. */
     private Badge() {
         mHasDot = false;
+        mBackgroundColor = null;
+        mIcon = null;
     }
 
     /** A builder of {@link Badge}. */
     public static final class Builder {
         boolean mHasDot;
+        @Nullable
+        CarColor mBackgroundColor;
+        @Nullable
+        CarIcon mIcon;
 
         /**
          * Enables a circular dot that denotes some sort of alert, notification, etc.
@@ -98,14 +130,40 @@
         }
 
         /**
+         * Sets the color of the dot to the given {@code backgroundColor}.
+         */
+        @NonNull
+        public Builder setBackgroundColor(@NonNull CarColor backgroundColor) {
+            mBackgroundColor = backgroundColor;
+            return this;
+        }
+
+        /**
+         * Sets an icon to be displayed as a badge.
+         *
+         * <p>An icon badge gives context about the associated element on which it is displayed. For
+         * example, a work profile icon badge is displayed with an app icon to indicate that
+         * it is a work app.
+         */
+        @NonNull
+        public Builder setIcon(@NonNull CarIcon icon) {
+            mIcon = icon;
+            return this;
+        }
+
+        /**
          * Constructs the {@link Badge} defined by this builder.
          *
-         * @throws IllegalStateException if no property is set on the badge.
+         * @throws IllegalStateException if the badge doesn't have a dot or an icon.
          */
         @NonNull
         public Badge build() {
-            if (!mHasDot) {
-                throw new IllegalStateException("At least one property must be set on the badge");
+            if (!mHasDot && mIcon == null) {
+                throw new IllegalStateException("A badge must have a dot or an icon set");
+            }
+            if (!mHasDot && mBackgroundColor != null) {
+                throw new IllegalStateException("The dot must be enabled to set the background "
+                        + "color.");
             }
             return new Badge(this);
         }
diff --git a/car/app/app/src/test/java/androidx/car/app/model/BadgeTest.java b/car/app/app/src/test/java/androidx/car/app/model/BadgeTest.java
index d6655c0..96b1797 100644
--- a/car/app/app/src/test/java/androidx/car/app/model/BadgeTest.java
+++ b/car/app/app/src/test/java/androidx/car/app/model/BadgeTest.java
@@ -27,10 +27,25 @@
 @RunWith(RobolectricTestRunner.class)
 public class BadgeTest {
     @Test
-    public void build_withDot() {
-        Badge b = new Badge.Builder().setHasDot(true).build();
+    public void build_withDotAndIcon() {
+        Badge b = new Badge.Builder().setHasDot(true).setIcon(CarIcon.ALERT).build();
 
         assertThat(b.hasDot()).isEqualTo(true);
+        assertThat(b.getIcon()).isEqualTo(CarIcon.ALERT);
+    }
+
+    @Test
+    public void build_withIcon() {
+        Badge b = new Badge.Builder().setIcon(CarIcon.ALERT).build();
+
+        assertThat(b.getIcon()).isEqualTo(CarIcon.ALERT);
+    }
+
+    public void build_withDotAndBackgroundColor() {
+        Badge b = new Badge.Builder().setHasDot(true).setBackgroundColor(CarColor.PRIMARY).build();
+
+        assertThat(b.hasDot()).isEqualTo(true);
+        assertThat(b.getBackgroundColor()).isEqualTo(CarColor.PRIMARY);
     }
 
     @Test
@@ -45,26 +60,55 @@
     }
 
     @Test
-    public void equals() {
-        Badge b1 = new Badge.Builder().setHasDot(true).build();
-        Badge b2 = new Badge.Builder().setHasDot(true).build();
+    public void build_setBackgroundColorWithoutDot_ThrowsException() {
+        assertThrows(IllegalStateException.class,
+                () -> new Badge.Builder()
+                        .setIcon(CarIcon.ALERT)
+                        .setBackgroundColor(CarColor.PRIMARY).build());
+    }
 
-        assertThat(b1.equals(b1)).isTrue();
+    @Test
+    public void equals() {
+        Badge b1 = new Badge.Builder()
+                .setHasDot(true)
+                .setBackgroundColor(CarColor.PRIMARY)
+                .setIcon(CarIcon.ALERT).build();
+        Badge b2 = new Badge.Builder()
+                .setHasDot(true)
+                .setBackgroundColor(CarColor.PRIMARY)
+                .setIcon(CarIcon.ALERT).build();
+
         assertThat(b1.equals(b2)).isTrue();
     }
 
     @Test
-    public void notEquals() {
-        Badge b = new Badge.Builder().setHasDot(true).build();
-        Object o = new Object();
+    public void notEquals_differentProperty() {
+        Badge b1 = new Badge.Builder().setHasDot(true).build();
+        Badge b2 = new Badge.Builder().setIcon(CarIcon.ALERT).build();
 
-        assertThat(b.equals(o)).isFalse();
+        assertThat(b1.equals(b2)).isFalse();
+    }
+
+    @Test
+    public void notEquals_differentBackgroundColor() {
+        Badge b1 = new Badge.Builder().setHasDot(true).setBackgroundColor(CarColor.BLUE).build();
+        Badge b2 = new Badge.Builder().setHasDot(true).setBackgroundColor(CarColor.RED).build();
+
+        assertThat(b1.equals(b2)).isFalse();
+    }
+
+    @Test
+    public void notEquals_differentIcons() {
+        Badge b1 = new Badge.Builder().setIcon(CarIcon.ALERT).build();
+        Badge b2 = new Badge.Builder().setIcon(CarIcon.ERROR).build();
+
+        assertThat(b1.equals(b2)).isFalse();
     }
 
     @Test
     public void string() {
         Badge b = new Badge.Builder().setHasDot(true).build();
 
-        assertThat(b.toString()).isEqualTo("[hasDot: true]");
+        assertThat(b.toString()).isEqualTo("[hasDot: true, backgroundColor: null, icon: null]");
     }
 }
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/MultiParagraphLayoutCacheTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/MultiParagraphLayoutCacheTest.kt
index b411547..605f1bf 100644
--- a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/MultiParagraphLayoutCacheTest.kt
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/MultiParagraphLayoutCacheTest.kt
@@ -19,8 +19,10 @@
 import androidx.compose.foundation.text.TEST_FONT_FAMILY
 import androidx.compose.foundation.text.toIntPx
 import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.Paragraph
 import androidx.compose.ui.text.SpanStyle
 import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.buildAnnotatedString
 import androidx.compose.ui.text.font.createFontFamilyResolver
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.Constraints
@@ -213,4 +215,39 @@
 
         assertThat(layoutResultLtr.size.width).isEqualTo(layoutResultRtl.size.width)
     }
+
+    @Test
+    fun maxHeight_hasSameHeight_asParagraph() {
+        val text = buildAnnotatedString {
+            for (i in 1..100 step 10) {
+                pushStyle(SpanStyle(fontSize = i.sp))
+                append("$i.sp\n")
+                pop()
+            }
+        }
+
+        val textDelegate = MultiParagraphLayoutCache(
+            text = text,
+            style = TextStyle(fontSize = 1.sp),
+            fontFamilyResolver = fontFamilyResolver,
+            overflow = TextOverflow.Ellipsis,
+            maxLines = 5
+        ).also {
+            it.density = density
+        }
+        textDelegate.layoutWithConstraints(Constraints(), LayoutDirection.Ltr)
+        val actual = textDelegate.textLayoutResult.multiParagraph
+
+        val expected = Paragraph(
+            text.text,
+            TextStyle(fontSize = 1.sp),
+            Constraints(),
+            density,
+            fontFamilyResolver,
+            text.spanStyles,
+            maxLines = 5,
+            ellipsis = true
+        )
+        assertThat(actual.height).isEqualTo(expected.height)
+    }
 }
diff --git a/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/ParagraphLayoutCacheTest.kt b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/ParagraphLayoutCacheTest.kt
new file mode 100644
index 0000000..a7cb8c6
--- /dev/null
+++ b/compose/foundation/foundation/src/androidAndroidTest/kotlin/androidx/compose/foundation/text/modifiers/ParagraphLayoutCacheTest.kt
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.modifiers
+
+import androidx.compose.foundation.text.TEST_FONT_FAMILY
+import androidx.compose.foundation.text.toIntPx
+import androidx.compose.ui.text.Paragraph
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.createFontFamilyResolver
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.sp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.google.common.truth.Truth.assertThat
+import kotlin.math.roundToInt
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class ParagraphLayoutCacheTest {
+
+    private val fontFamily = TEST_FONT_FAMILY
+    private val density = Density(density = 1f)
+    private val context = InstrumentationRegistry.getInstrumentation().context
+    private val fontFamilyResolver = createFontFamilyResolver(context)
+
+    @Test
+    fun minIntrinsicWidth_getter() {
+        with(density) {
+            val fontSize = 20.sp
+            val text = "Hello"
+            val textDelegate = ParagraphLayoutCache(
+                text = text,
+                style = TextStyle(fontSize = fontSize, fontFamily = fontFamily),
+                fontFamilyResolver = fontFamilyResolver,
+            ).also {
+                it.density = this
+            }
+
+            assertThat(textDelegate.minIntrinsicWidth(LayoutDirection.Ltr))
+                .isEqualTo((fontSize.toPx() * text.length).toIntPx())
+        }
+    }
+
+    @Test
+    fun maxIntrinsicWidth_getter() {
+        with(density) {
+            val fontSize = 20.sp
+            val text = "Hello"
+            val textDelegate = ParagraphLayoutCache(
+                text = text,
+                style = TextStyle(fontSize = fontSize, fontFamily = fontFamily),
+                fontFamilyResolver = fontFamilyResolver,
+            ).also {
+                it.density = this
+            }
+
+            assertThat(textDelegate.maxIntrinsicWidth(LayoutDirection.Ltr))
+                .isEqualTo((fontSize.toPx() * text.length).toIntPx())
+        }
+    }
+
+    @Test
+    fun TextLayoutInput_reLayout_withDifferentHeight() {
+        val textDelegate = ParagraphLayoutCache(
+            text = "Hello World",
+            style = TextStyle.Default,
+            fontFamilyResolver = fontFamilyResolver,
+        ).also {
+            it.density = density
+        }
+        val width = 200
+        val heightFirstLayout = 100
+        val heightSecondLayout = 200
+
+        val constraintsFirstLayout = Constraints.fixed(width, heightFirstLayout)
+        textDelegate.layoutWithConstraints(constraintsFirstLayout, LayoutDirection.Ltr)
+        val resultFirstLayout = textDelegate.layoutSize
+
+        val constraintsSecondLayout = Constraints.fixed(width, heightSecondLayout)
+        textDelegate.layoutWithConstraints(
+            constraintsSecondLayout,
+            LayoutDirection.Ltr
+        )
+        val resultSecondLayout = textDelegate.layoutSize
+
+        assertThat(resultFirstLayout.height).isLessThan(resultSecondLayout.height)
+    }
+
+    @Test
+    fun TextLayoutResult_reLayout_withDifferentHeight() {
+        val textDelegate = ParagraphLayoutCache(
+            text = "Hello World",
+            style = TextStyle.Default,
+            fontFamilyResolver = fontFamilyResolver,
+        ).also {
+            it.density = density
+        }
+        val width = 200
+        val heightFirstLayout = 100
+        val heightSecondLayout = 200
+
+        val constraintsFirstLayout = Constraints.fixed(width, heightFirstLayout)
+        textDelegate.layoutWithConstraints(constraintsFirstLayout, LayoutDirection.Ltr)
+        val resultFirstLayout = textDelegate.layoutSize
+        assertThat(resultFirstLayout.height).isEqualTo(heightFirstLayout)
+
+        val constraintsSecondLayout = Constraints.fixed(width, heightSecondLayout)
+        textDelegate.layoutWithConstraints(
+            constraintsSecondLayout,
+            LayoutDirection.Ltr
+        )
+        val resultSecondLayout = textDelegate.layoutSize
+        assertThat(resultSecondLayout.height).isEqualTo(heightSecondLayout)
+    }
+
+    @Test
+    fun TextLayoutResult_layout_withEllipsis_withoutSoftWrap() {
+        val fontSize = 20f
+        val textDelegate = ParagraphLayoutCache(
+            text = "Hello World! Hello World! Hello World! Hello World!",
+            style = TextStyle(fontSize = fontSize.sp),
+            fontFamilyResolver = fontFamilyResolver,
+            softWrap = false,
+            overflow = TextOverflow.Ellipsis,
+        ).also {
+            it.density = density
+        }
+
+        textDelegate.layoutWithConstraints(Constraints.fixed(0, 0), LayoutDirection.Ltr)
+        // Makes width smaller than needed.
+        val width = textDelegate.maxIntrinsicWidth(LayoutDirection.Ltr) / 2
+        val constraints = Constraints(maxWidth = width)
+        textDelegate.layoutWithConstraints(constraints, LayoutDirection.Ltr)
+        val layoutResult = textDelegate.paragraph!!
+
+        assertThat(layoutResult.lineCount).isEqualTo(1)
+        assertThat(layoutResult.isLineEllipsized(0)).isTrue()
+    }
+
+    @Test
+    fun TextLayoutResult_layoutWithLimitedHeight_withEllipsis() {
+        val fontSize = 20f
+
+        val textDelegate = ParagraphLayoutCache(
+            text = "Hello World! Hello World! Hello World! Hello World!",
+            style = TextStyle(fontSize = fontSize.sp),
+            fontFamilyResolver = fontFamilyResolver,
+            overflow = TextOverflow.Ellipsis,
+        ).also {
+            it.density = density
+        }
+        textDelegate.layoutWithConstraints(Constraints.fixed(0, 0), LayoutDirection.Ltr)
+        val constraints = Constraints(
+            maxWidth = textDelegate.maxIntrinsicWidth(LayoutDirection.Ltr) / 4,
+            maxHeight = (fontSize * 2.7).roundToInt() // fully fits at most 2 lines
+        )
+        textDelegate.layoutWithConstraints(constraints, LayoutDirection.Ltr)
+        val layoutResult = textDelegate.paragraph!!
+
+        assertThat(layoutResult.lineCount).isEqualTo(2)
+        assertThat(layoutResult.isLineEllipsized(1)).isTrue()
+    }
+
+    @Test
+    fun TextLayoutResult_sameWidth_inRtlAndLtr_withLetterSpacing() {
+        val fontSize = 20f
+
+        val textDelegate = ParagraphLayoutCache(
+            text = "Hello World",
+            style = TextStyle(fontSize = fontSize.sp, letterSpacing = 0.5.sp),
+            fontFamilyResolver = fontFamilyResolver,
+            overflow = TextOverflow.Ellipsis,
+        ).also {
+            it.density = density
+        }
+
+        textDelegate.layoutWithConstraints(Constraints(), LayoutDirection.Ltr)
+        val layoutResultLtr = textDelegate.layoutSize
+        textDelegate.layoutWithConstraints(Constraints(), LayoutDirection.Rtl)
+        val layoutResultRtl = textDelegate.layoutSize
+
+        assertThat(layoutResultLtr.width).isEqualTo(layoutResultRtl.width)
+    }
+
+    @Test
+    fun maxHeight_hasSameHeight_asParagraph() {
+        val text = "a\n".repeat(20)
+        val textDelegate = ParagraphLayoutCache(
+            text = text,
+            style = TextStyle(fontSize = 1.sp),
+            fontFamilyResolver = fontFamilyResolver,
+            overflow = TextOverflow.Ellipsis,
+            maxLines = 5
+        ).also {
+            it.density = density
+        }
+        textDelegate.layoutWithConstraints(Constraints(), LayoutDirection.Ltr)
+        val actual = textDelegate.paragraph!!
+
+        val expected = Paragraph(
+            text,
+            TextStyle(fontSize = 1.sp),
+            Constraints(),
+            density,
+            fontFamilyResolver,
+            emptyList(),
+            maxLines = 5,
+            ellipsis = true
+        )
+        assertThat(actual.height).isEqualTo(expected.height)
+    }
+}
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicText.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicText.kt
index ae0cf5c..070b437 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicText.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/BasicText.kt
@@ -360,7 +360,7 @@
     replaceWith = ReplaceWith(""),
     level = DeprecationLevel.WARNING
 )
-var NewTextRendering1_5: Boolean by mutableStateOf(false)
+var NewTextRendering1_5: Boolean by mutableStateOf(true)
 
 /**
  * A custom saver that won't save if no selection is active.
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/MinMaxLinesCoercer.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/MinLinesConstrainer.kt
similarity index 88%
rename from compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/MinMaxLinesCoercer.kt
rename to compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/MinLinesConstrainer.kt
index 8ab511d..02d1f32 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/MinMaxLinesCoercer.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/MinLinesConstrainer.kt
@@ -30,7 +30,7 @@
  *
  * Results are cached with the assumption that there is typically N=1 style being coerced at once.
  */
-internal class MinMaxLinesCoercer private constructor(
+internal class MinLinesConstrainer private constructor(
     val layoutDirection: LayoutDirection,
     val inputTextStyle: TextStyle,
     val density: Density,
@@ -43,18 +43,18 @@
     companion object {
         // LRU cache of one since this tends to be used for similar styles
         // ... it may be useful to increase this cache if requested by some dev use case
-        private var last: MinMaxLinesCoercer? = null
+        private var last: MinLinesConstrainer? = null
 
         /**
          * Returns a coercer (possibly cached) with these parameters
          */
         fun from(
-            minMaxUtil: MinMaxLinesCoercer?,
+            minMaxUtil: MinLinesConstrainer?,
             layoutDirection: LayoutDirection,
             paramStyle: TextStyle,
             density: Density,
             fontFamilyResolver: FontFamily.Resolver
-        ): MinMaxLinesCoercer {
+        ): MinLinesConstrainer {
             minMaxUtil?.let {
                 if (layoutDirection == it.layoutDirection &&
                     paramStyle == it.inputTextStyle &&
@@ -71,7 +71,7 @@
                     return it
                 }
             }
-            return MinMaxLinesCoercer(
+            return MinLinesConstrainer(
                 layoutDirection,
                 resolveDefaults(paramStyle, layoutDirection),
                 density,
@@ -87,10 +87,9 @@
      *
      * On first invocation this will cause (2) Paragraph measurements.
      */
-    internal fun coerceMaxMinLines(
+    internal fun coerceMinLines(
         inConstraints: Constraints,
-        minLines: Int,
-        maxLines: Int,
+        minLines: Int
     ): Constraints {
         var oneLineHeight = oneLineHeightCache
         var lineHeight = lineHeightCache
@@ -119,24 +118,17 @@
             oneLineHeightCache = oneLineHeight
             lineHeightCache = lineHeight
         }
-        val maxHeight = if (maxLines != Int.MAX_VALUE) {
-            (oneLineHeight + (lineHeight * (maxLines - 1)))
-                .roundToInt()
-                .coerceAtLeast(0)
-        } else {
-            inConstraints.maxHeight
-        }
         val minHeight = if (minLines != 1) {
             (oneLineHeight + (lineHeight * (minLines - 1)))
                 .roundToInt()
                 .coerceAtLeast(0)
-                .coerceAtMost(maxHeight)
+                .coerceAtMost(inConstraints.maxHeight)
         } else {
             inConstraints.minHeight
         }
         return Constraints(
             minHeight = minHeight,
-            maxHeight = maxHeight,
+            maxHeight = inConstraints.maxHeight,
             minWidth = inConstraints.minWidth,
             maxWidth = inConstraints.maxWidth,
         )
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/MultiParagraphLayoutCache.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/MultiParagraphLayoutCache.kt
index fc4e604..b2d6ffe 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/MultiParagraphLayoutCache.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/MultiParagraphLayoutCache.kt
@@ -55,7 +55,7 @@
     /**
      * Convert min max lines into actual constraints
      */
-    private var minMaxLinesCoercer: MinMaxLinesCoercer? = null
+    private var mMinLinesConstrainer: MinLinesConstrainer? = null
 
     /**
      * Density that text layout is performed in
@@ -128,20 +128,19 @@
         constraints: Constraints,
         layoutDirection: LayoutDirection
     ): Boolean {
-        val finalConstraints = if (maxLines != Int.MAX_VALUE || minLines > 1) {
-            val localMinMax = MinMaxLinesCoercer.from(
-                minMaxLinesCoercer,
+        val finalConstraints = if (minLines > 1) {
+            val localMin = MinLinesConstrainer.from(
+                mMinLinesConstrainer,
                 layoutDirection,
                 style,
                 density!!,
                 fontFamilyResolver
             ).also {
-                minMaxLinesCoercer = it
+                mMinLinesConstrainer = it
             }
-            localMinMax.coerceMaxMinLines(
+            localMin.coerceMinLines(
                 inConstraints = constraints,
-                minLines = minLines,
-                maxLines = maxLines
+                minLines = minLines
             )
         } else {
             constraints
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/ParagraphLayoutCache.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/ParagraphLayoutCache.kt
index b724079..988d0c7 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/ParagraphLayoutCache.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/text/modifiers/ParagraphLayoutCache.kt
@@ -102,7 +102,7 @@
     /**
      * Convert min max lines into actual constraints
      */
-    private var minMaxLinesCoercer: MinMaxLinesCoercer? = null
+    private var mMinLinesConstrainer: MinLinesConstrainer? = null
 
     /**
      * [ParagraphIntrinsics] will be initialized lazily
@@ -138,20 +138,19 @@
         constraints: Constraints,
         layoutDirection: LayoutDirection
     ): Boolean {
-        val finalConstraints = if (maxLines != Int.MAX_VALUE || minLines > 1) {
-            val localMinMax = MinMaxLinesCoercer.from(
-                minMaxLinesCoercer,
+        val finalConstraints = if (minLines > 1) {
+            val localMin = MinLinesConstrainer.from(
+                mMinLinesConstrainer,
                 layoutDirection,
                 style,
                 density!!,
                 fontFamilyResolver
             ).also {
-                minMaxLinesCoercer = it
+                mMinLinesConstrainer = it
             }
-            localMinMax.coerceMaxMinLines(
+            localMin.coerceMinLines(
                 inConstraints = constraints,
-                minLines = minLines,
-                maxLines = maxLines
+                minLines = minLines
             )
         } else {
             constraints
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 c26a84dc..a24934d 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
@@ -670,13 +670,18 @@
         builder.hideSystemNodes = false
         val nodes = builder.convert(composeView)
         dumpNodes(nodes, composeView, builder)
-        val androidView = nodes.flatMap { flatten(it) }.single { it.name == "AndroidView" }
+        val androidView = nodes.flatMap { flatten(it) }.first { it.name == "AndroidView" }
         assertThat(androidView.viewId).isEqualTo(0)
 
         validate(listOf(androidView), builder) {
             node(
                 name = "AndroidView",
                 fileName = "LayoutInspectorTreeTest.kt",
+                children = listOf("AndroidView")
+            )
+            node(
+                name = "AndroidView",
+                fileName = "AndroidView.android.kt",
                 children = listOf("ComposeNode")
             )
             node(
@@ -689,6 +694,51 @@
     }
 
     @Test
+    fun testAndroidViewWithOnResetOverload() {
+        val slotTableRecord = CompositionDataRecord.create()
+
+        show {
+            Inspectable(slotTableRecord) {
+                Column {
+                    Text("Compose Text")
+                    AndroidView(
+                        factory = { context ->
+                            TextView(context).apply {
+                                text = "AndroidView"
+                            }
+                        },
+                        onReset = {
+                            // Do nothing, just use the overload.
+                        }
+                    )
+                }
+            }
+        }
+        val composeView = findAndroidComposeView() as ViewGroup
+        composeView.setTag(R.id.inspection_slot_table_set, slotTableRecord.store)
+        val builder = LayoutInspectorTree()
+        builder.hideSystemNodes = false
+        val nodes = builder.convert(composeView)
+        dumpNodes(nodes, composeView, builder)
+        val androidView = nodes.flatMap { flatten(it) }.first { it.name == "AndroidView" }
+        assertThat(androidView.viewId).isEqualTo(0)
+
+        validate(listOf(androidView), builder) {
+            node(
+                name = "AndroidView",
+                fileName = "LayoutInspectorTreeTest.kt",
+                children = listOf("ReusableComposeNode")
+            )
+            node(
+                name = "ReusableComposeNode",
+                fileName = "AndroidView.android.kt",
+                hasViewIdUnder = composeView,
+                inlined = true,
+            )
+        }
+    }
+
+    @Test
     fun testDoubleAndroidView() {
         val slotTableRecord = CompositionDataRecord.create()
 
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index cab650d..5a1455d 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -3110,8 +3110,8 @@
 package androidx.compose.ui.viewinterop {
 
   public final class AndroidView_androidKt {
+    method @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public static <T extends android.view.View> void AndroidView(kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> factory, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super T,kotlin.Unit> update);
     method @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public static <T extends android.view.View> void AndroidView(kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> factory, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super T,kotlin.Unit>? onReset, optional kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onRelease, optional kotlin.jvm.functions.Function1<? super T,kotlin.Unit> update);
-    method @Deprecated @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public static <T extends android.view.View> void AndroidView(kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> factory, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> update);
     method public static kotlin.jvm.functions.Function1<android.view.View,kotlin.Unit> getNoOpUpdate();
     property public static final kotlin.jvm.functions.Function1<android.view.View,kotlin.Unit> NoOpUpdate;
   }
diff --git a/compose/ui/ui/api/public_plus_experimental_current.txt b/compose/ui/ui/api/public_plus_experimental_current.txt
index 3d089cf..fa8d56d 100644
--- a/compose/ui/ui/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui/api/public_plus_experimental_current.txt
@@ -3375,8 +3375,8 @@
 package androidx.compose.ui.viewinterop {
 
   public final class AndroidView_androidKt {
+    method @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public static <T extends android.view.View> void AndroidView(kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> factory, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super T,kotlin.Unit> update);
     method @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public static <T extends android.view.View> void AndroidView(kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> factory, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super T,kotlin.Unit>? onReset, optional kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onRelease, optional kotlin.jvm.functions.Function1<? super T,kotlin.Unit> update);
-    method @Deprecated @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public static <T extends android.view.View> void AndroidView(kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> factory, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> update);
     method public static kotlin.jvm.functions.Function1<android.view.View,kotlin.Unit> getNoOpUpdate();
     property public static final kotlin.jvm.functions.Function1<android.view.View,kotlin.Unit> NoOpUpdate;
   }
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index 272ecd7..c8fa151 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -3158,8 +3158,8 @@
 package androidx.compose.ui.viewinterop {
 
   public final class AndroidView_androidKt {
+    method @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public static <T extends android.view.View> void AndroidView(kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> factory, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super T,kotlin.Unit> update);
     method @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public static <T extends android.view.View> void AndroidView(kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> factory, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super T,kotlin.Unit>? onReset, optional kotlin.jvm.functions.Function1<? super T,kotlin.Unit> onRelease, optional kotlin.jvm.functions.Function1<? super T,kotlin.Unit> update);
-    method @Deprecated @androidx.compose.runtime.Composable @androidx.compose.ui.UiComposable public static <T extends android.view.View> void AndroidView(kotlin.jvm.functions.Function1<? super android.content.Context,? extends T> factory, optional androidx.compose.ui.Modifier modifier, optional kotlin.jvm.functions.Function1<? super T,? extends kotlin.Unit> update);
     method public static kotlin.jvm.functions.Function1<android.view.View,kotlin.Unit> getNoOpUpdate();
     property public static final kotlin.jvm.functions.Function1<android.view.View,kotlin.Unit> NoOpUpdate;
   }
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusEventCountTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusEventCountTest.kt
index 7c6cc56..7d49b02 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusEventCountTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusEventCountTest.kt
@@ -172,6 +172,34 @@
     }
 
     @Test
+    fun removingActiveComposable_onFocusEventIsCalledWithDefaultValue() {
+        // Arrange.
+        val focusStates = mutableListOf<FocusState>()
+        val focusRequester = FocusRequester()
+        var showBox by mutableStateOf(true)
+        rule.setFocusableContent {
+            if (showBox) {
+                Box(
+                    modifier = Modifier
+                        .onFocusEvent { focusStates.add(it) }
+                        .focusRequester(focusRequester)
+                        .focusTarget()
+                )
+            }
+        }
+        rule.runOnIdle {
+            focusRequester.requestFocus()
+            focusStates.clear()
+        }
+
+        // Act.
+        rule.runOnIdle { showBox = false }
+
+        // Assert.
+        rule.runOnIdle { assertThat(focusStates).isExactly(Inactive) }
+    }
+
+    @Test
     fun removingActiveFocusNode_onFocusEventIsCalledTwice() {
         // Arrange.
         val focusStates = mutableListOf<FocusState>()
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusTargetAttachDetachTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusTargetAttachDetachTest.kt
index 10b7e0e..525d640 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusTargetAttachDetachTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/focus/FocusTargetAttachDetachTest.kt
@@ -165,6 +165,67 @@
     }
 
     @Test
+    fun removedActiveFocusTargetAndFocusChanged_triggersOnFocusEvent() {
+        // Arrange.
+        lateinit var focusState: FocusState
+        val focusRequester = FocusRequester()
+        var optionalModifiers by mutableStateOf(true)
+        rule.setFocusableContent {
+            Box(
+                modifier = Modifier
+                    .focusRequester(focusRequester)
+                    .then(
+                        if (optionalModifiers) {
+                            Modifier
+                                .onFocusEvent { focusState = it }
+                                .focusTarget()
+                        } else {
+                            Modifier
+                        }
+                    )
+            )
+        }
+        rule.runOnIdle {
+            focusRequester.requestFocus()
+            assertThat(focusState.isFocused).isTrue()
+        }
+
+        // Act.
+        rule.runOnIdle { optionalModifiers = false }
+
+        // Assert.
+        rule.runOnIdle { assertThat(focusState.isFocused).isFalse() }
+    }
+
+    @Test
+    fun removedActiveComposable_doesNotTriggerOnFocusEvent() {
+        // Arrange.
+        lateinit var focusState: FocusState
+        val focusRequester = FocusRequester()
+        var optionalBox by mutableStateOf(true)
+        rule.setFocusableContent {
+            if (optionalBox) {
+                Box(
+                    modifier = Modifier
+                        .focusRequester(focusRequester)
+                        .onFocusEvent { focusState = it }
+                        .focusTarget()
+                )
+            }
+        }
+        rule.runOnIdle {
+            focusRequester.requestFocus()
+            assertThat(focusState.isFocused).isTrue()
+        }
+
+        // Act.
+        rule.runOnIdle { optionalBox = false }
+
+        // Assert.
+        rule.runOnIdle { assertThat(focusState.isFocused).isFalse() }
+    }
+
+    @Test
     fun removedCapturedFocusTarget_pointsToNextFocusTarget() {
         // Arrange.
         lateinit var focusState: FocusState
@@ -308,6 +369,45 @@
     }
 
     @Test
+    fun removedActiveComposable_clearsFocusFromAllParents() {
+        // Arrange.
+        lateinit var focusState: FocusState
+        lateinit var parentFocusState: FocusState
+        val focusRequester = FocusRequester()
+        var optionalBox by mutableStateOf(true)
+        rule.setFocusableContent {
+            Box(
+                modifier = Modifier
+                    .onFocusChanged { parentFocusState = it }
+                    .focusTarget()
+            ) {
+                if (optionalBox) {
+                    Box(
+                        modifier = Modifier
+                            .onFocusChanged { focusState = it }
+                            .focusRequester(focusRequester)
+                            .focusTarget()
+                    )
+                }
+            }
+        }
+        rule.runOnIdle {
+            focusRequester.requestFocus()
+            assertThat(focusState.hasFocus).isTrue()
+            assertThat(parentFocusState.hasFocus).isTrue()
+        }
+
+        // Act.
+        rule.runOnIdle { optionalBox = false }
+
+        // Assert.
+        rule.runOnIdle {
+            assertThat(focusState.isFocused).isFalse()
+            assertThat(parentFocusState.isFocused).isFalse()
+        }
+    }
+
+    @Test
     fun removedDeactivatedParentFocusTarget_pointsToNextFocusTarget() {
         // Arrange.
         lateinit var focusState: FocusState
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt
index 1c9c17a..ef4a0f4 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/viewinterop/AndroidView.android.kt
@@ -49,11 +49,48 @@
 import androidx.lifecycle.findViewTreeLifecycleOwner
 import androidx.savedstate.SavedStateRegistryOwner
 
-@Deprecated(
-    message = "AndroidView now has arguments for onReset and onRelease callbacks. This original " +
-        "overload is retained for binary compatibility only.",
-    level = DeprecationLevel.HIDDEN
-)
+/**
+ * Composes an Android [View] obtained from [factory]. The [factory] block will be called exactly
+ * once to obtain the [View] being composed, and it is also guaranteed to be invoked on the UI
+ * thread. Therefore, in addition to creating the [View], the [factory] block can also be used to
+ * perform one-off initializations and [View] constant properties' setting. The [update] block can
+ * run multiple times (on the UI thread as well) due to recomposition, and it is the right place to
+ * set the new properties. Note that the block will also run once right after the [factory] block
+ * completes.
+ *
+ * [AndroidView] is commonly needed for using Views that are infeasible to be reimplemented in
+ * Compose and there is no corresponding Compose API. Common examples for the moment are
+ * WebView, SurfaceView, AdView, etc.
+ *
+ * This overload of [AndroidView] does not automatically pool or reuse Views. If placed inside of a
+ * reusable container (including inside a [LazyRow][androidx.compose.foundation.lazy.LazyRow] or
+ * [LazyColumn][androidx.compose.foundation.lazy.LazyColumn]), the View instances will always be
+ * discarded and recreated if the composition hierarchy containing the AndroidView changes, even
+ * if its group structure did not change and the View could have conceivably been reused.
+ *
+ * To opt-in for View reuse, call the overload of [AndroidView] that accepts an `onReset` callback,
+ * and provide a non-null implementation for this callback. Since it is expensive to discard and
+ * recreate View instances, reusing Views can lead to noticeable performance improvements —
+ * especially when building a scrolling list of [AndroidViews][AndroidView]. It is highly
+ * recommended to opt-in to View reuse when possible.
+ *
+ * [AndroidView] will not clip its content to the layout bounds. Use [View.setClipToOutline] on
+ * the child View to clip the contents, if desired. Developers will likely want to do this with
+ * all subclasses of SurfaceView to keep its contents contained.
+ *
+ * [AndroidView] has nested scroll interop capabilities if the containing view has nested scroll
+ * enabled. This means this Composable can dispatch scroll deltas if it is placed inside a
+ * container that participates in nested scroll. For more information on how to enable
+ * nested scroll interop:
+ * @sample androidx.compose.ui.samples.ViewInComposeNestedScrollInteropSample
+ *
+ * @sample androidx.compose.ui.samples.AndroidViewSample
+ *
+ * @param factory The block creating the [View] to be composed.
+ * @param modifier The modifier to be applied to the layout.
+ * @param update A callback to be invoked after the layout is inflated and upon recomposition to
+ * update the information and state of the view.
+ */
 @Composable
 @UiComposable
 fun <T : View> AndroidView(
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusInvalidationManager.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusInvalidationManager.kt
index 8421e1b..6217e96 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusInvalidationManager.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/focus/FocusInvalidationManager.kt
@@ -73,7 +73,13 @@
         focusEventNodes.forEach { focusEventNode ->
             // When focus nodes are removed, the corresponding focus events are scheduled for
             // invalidation. If the focus event was also removed, we don't need to invalidate it.
-            if (!focusEventNode.node.isAttached) return@forEach
+            // We call onFocusEvent with the default value, just to make it easier for the user,
+            // so that they don't have to keep track of whether they caused a focused item to be
+            // removed (Which would cause it to lose focus).
+            if (!focusEventNode.node.isAttached) {
+                focusEventNode.onFocusEvent(Inactive)
+                return@forEach
+            }
 
             var requiresUpdate = true
             var aggregatedNode = false
diff --git a/core/core/build.gradle b/core/core/build.gradle
index ecf22c1..d5fc97b 100644
--- a/core/core/build.gradle
+++ b/core/core/build.gradle
@@ -34,6 +34,7 @@
     androidTestImplementation(libs.espressoCore, excludes.espresso)
     androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it"s own MockMaker
     androidTestImplementation(libs.multidex)
+    androidTestImplementation(libs.testUiautomator)
 
     androidTestImplementation("androidx.lifecycle:lifecycle-runtime-testing:2.3.1")
 
diff --git a/core/core/src/androidTest/AndroidManifest.xml b/core/core/src/androidTest/AndroidManifest.xml
index 41caed87..87ce490 100644
--- a/core/core/src/androidTest/AndroidManifest.xml
+++ b/core/core/src/androidTest/AndroidManifest.xml
@@ -14,7 +14,10 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <uses-sdk tools:overrideLibrary="android_libs.ub_uiautomator, androidx.test.uiautomator" />
 
     <application
         android:name="androidx.multidex.MultiDexApplication"
@@ -123,6 +126,14 @@
             android:name="androidx.core.app.GetSystemLocalesActivity"
             android:exported="true" />
 
+        <activity
+            android:name="androidx.core.view.inputmethod.ImeBaseSplitTestActivity"
+            android:exported="true" />
+
+        <activity
+            android:name="androidx.core.view.inputmethod.ImeSecondarySplitTestActivity"
+            android:exported="true" />
+
         <activity-alias
             android:name="androidx.core.app.NavUtilsAliasActivity"
             android:targetActivity="androidx.core.app.NavUtilsActivity">
diff --git a/core/core/src/androidTest/java/androidx/core/view/inputmethod/ImeBaseSplitTestActivity.java b/core/core/src/androidTest/java/androidx/core/view/inputmethod/ImeBaseSplitTestActivity.java
new file mode 100644
index 0000000..279d763
--- /dev/null
+++ b/core/core/src/androidTest/java/androidx/core/view/inputmethod/ImeBaseSplitTestActivity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.view.inputmethod;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.core.R;
+
+@RequiresApi(30)
+public class ImeBaseSplitTestActivity extends Activity {
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.ime_base_split_test_activity);
+    }
+}
diff --git a/core/core/src/androidTest/java/androidx/core/view/inputmethod/ImeMultiWindowTest.java b/core/core/src/androidTest/java/androidx/core/view/inputmethod/ImeMultiWindowTest.java
new file mode 100644
index 0000000..1076dfd
--- /dev/null
+++ b/core/core/src/androidTest/java/androidx/core/view/inputmethod/ImeMultiWindowTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.view.inputmethod;
+
+import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Build;
+import android.os.RemoteException;
+import android.support.v4.BaseInstrumentationTestCase;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+
+import androidx.core.view.WindowInsetsCompat;
+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.test.uiautomator.By;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
+import androidx.testutils.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+@SdkSuppress(minSdkVersion = 30)
+public class ImeMultiWindowTest extends BaseInstrumentationTestCase<ImeBaseSplitTestActivity> {
+
+    private static final long ACTIVITY_LAUNCH_TIMEOUT_MS = 10000;
+    private static final long VISIBILITY_TIMEOUT_MS = 2000;
+    private static final long FIND_OBJECT_TIMEOUT_MS = 5000;
+    private static final long CLICK_DURATION_MS = 200;
+
+    private static final String TEST_APP = "androidx.core.test";
+
+    private Activity mActivity;
+
+    private UiDevice mDevice;
+
+    public ImeMultiWindowTest() {
+        super(ImeBaseSplitTestActivity.class);
+    }
+
+    @Before
+    public void setup() throws RemoteException {
+        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        mDevice.wakeUp();
+        mActivity = mActivityTestRule.getActivity();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 30)
+    public void testImeShowAndHide_splitScreen() {
+        if (Build.VERSION.SDK_INT < 32) {
+            // FLAG_ACTIVITY_LAUNCH_ADJACENT is not support before Sdk 32, using the
+            // GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN instead.
+            InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                    .performGlobalAction(GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN);
+        }
+
+        // Launch ime test activity in secondary split.
+        Intent intent = new Intent(mActivity, ImeSecondarySplitTestActivity.class)
+                .addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+        mActivity.startActivity(intent);
+
+        assertTrue("Test app is not visible after launching activity",
+                mDevice.wait(Until.hasObject(By.pkg(TEST_APP)), ACTIVITY_LAUNCH_TIMEOUT_MS));
+
+        UiObject2 editText = waitForFindObject("edit_text_id");
+        editText.click(CLICK_DURATION_MS);
+
+        WindowManager wm = mActivity.getSystemService(WindowManager.class);
+        PollingCheck.waitFor(VISIBILITY_TIMEOUT_MS, () -> {
+            WindowInsets insets = wm.getCurrentWindowMetrics().getWindowInsets();
+            return insets.isVisible(WindowInsetsCompat.Type.ime());
+        });
+
+        UiObject2 hideImeButton = waitForFindObject("hide_ime_id");
+        hideImeButton.click();
+
+        PollingCheck.waitFor(VISIBILITY_TIMEOUT_MS, () -> {
+            WindowInsets insets = wm.getCurrentWindowMetrics().getWindowInsets();
+            return !insets.isVisible(WindowInsetsCompat.Type.ime());
+        });
+    }
+
+    private UiObject2 waitForFindObject(String resId) {
+        final UiObject2 object =
+                mDevice.wait(Until.findObject(By.res(TEST_APP, resId)), FIND_OBJECT_TIMEOUT_MS);
+        assertNotNull("Find object fail", object);
+        return object;
+    }
+}
diff --git a/core/core/src/androidTest/java/androidx/core/view/inputmethod/ImeSecondarySplitTestActivity.java b/core/core/src/androidTest/java/androidx/core/view/inputmethod/ImeSecondarySplitTestActivity.java
new file mode 100644
index 0000000..1820e0e
--- /dev/null
+++ b/core/core/src/androidTest/java/androidx/core/view/inputmethod/ImeSecondarySplitTestActivity.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.view.inputmethod;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.EditText;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+import androidx.core.R;
+import androidx.core.view.WindowCompat;
+import androidx.core.view.WindowInsetsCompat;
+import androidx.core.view.WindowInsetsControllerCompat;
+
+@RequiresApi(30)
+public class ImeSecondarySplitTestActivity extends Activity {
+
+    EditText mEditText;
+
+    Button mHideImeButton;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.ime_secondary_split_test_activity);
+        mEditText = findViewById(R.id.edit_text_id);
+        mHideImeButton = findViewById(R.id.hide_ime_id);
+        mHideImeButton.setOnClickListener(view -> hideIme());
+    }
+
+    private void hideIme() {
+        // Use WindowInsetsControllerCompat to hide ime.
+        WindowInsetsControllerCompat insetsController =
+                WindowCompat.getInsetsController(getWindow(), mEditText);
+        insetsController.hide(WindowInsetsCompat.Type.ime());
+    }
+}
diff --git a/core/core/src/main/java/androidx/core/view/WindowInsetsControllerCompat.java b/core/core/src/main/java/androidx/core/view/WindowInsetsControllerCompat.java
index 733521d..6dae4cb 100644
--- a/core/core/src/main/java/androidx/core/view/WindowInsetsControllerCompat.java
+++ b/core/core/src/main/java/androidx/core/view/WindowInsetsControllerCompat.java
@@ -44,6 +44,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Provide simple controls of windows that generate insets.
@@ -660,6 +661,24 @@
 
         @Override
         void hide(@InsetsType int types) {
+            if (mWindow != null && (types & WindowInsetsCompat.Type.IME) != 0 && SDK_INT <= 33) {
+                final AtomicBoolean isImeInsetsControllable = new AtomicBoolean(false);
+                final WindowInsetsController.OnControllableInsetsChangedListener listener =
+                        (windowInsetsController, typeMask) -> isImeInsetsControllable.set(
+                                (typeMask & WindowInsetsCompat.Type.IME) != 0);
+                // Register the OnControllableInsetsChangedListener would synchronously callback
+                // current controllable insets. Adding the listener here to check if ime inset is
+                // controllable.
+                mInsetsController.addOnControllableInsetsChangedListener(listener);
+                if (!isImeInsetsControllable.get()) {
+                    final InputMethodManager imm = (InputMethodManager) mWindow.getContext()
+                                    .getSystemService(Context.INPUT_METHOD_SERVICE);
+                    // This is a backport when the app is in multi-windowing mode, it cannot control
+                    // the ime insets. Use the InputMethodManager instead.
+                    imm.hideSoftInputFromWindow(mWindow.getDecorView().getWindowToken(), 0);
+                }
+                mInsetsController.removeOnControllableInsetsChangedListener(listener);
+            }
             mInsetsController.hide(types);
         }
 
diff --git a/ads/ads-identifier-provider/src/androidTest/AndroidManifest.xml b/core/core/src/main/res/layout/ime_base_split_test_activity.xml
similarity index 60%
rename from ads/ads-identifier-provider/src/androidTest/AndroidManifest.xml
rename to core/core/src/main/res/layout/ime_base_split_test_activity.xml
index 7c37821..43d4d7c 100644
--- a/ads/ads-identifier-provider/src/androidTest/AndroidManifest.xml
+++ b/core/core/src/main/res/layout/ime_base_split_test_activity.xml
@@ -1,5 +1,5 @@
-<!--
-  Copyright (C) 2019 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!--
+  Copyright 2023 The Android Open Source Project
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -11,8 +11,12 @@
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
-  limitations under the License
+  limitations under the License.
   -->
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android">
-</manifest>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+</LinearLayout>
\ No newline at end of file
diff --git a/ads/ads-identifier-provider/integration-tests/testapp/src/main/res/layout/provider_info.xml b/core/core/src/main/res/layout/ime_secondary_split_test_activity.xml
similarity index 62%
rename from ads/ads-identifier-provider/integration-tests/testapp/src/main/res/layout/provider_info.xml
rename to core/core/src/main/res/layout/ime_secondary_split_test_activity.xml
index 1f433ae..8aeaae7 100644
--- a/ads/ads-identifier-provider/integration-tests/testapp/src/main/res/layout/provider_info.xml
+++ b/core/core/src/main/res/layout/ime_secondary_split_test_activity.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?><!--
-  Copyright 2019 The Android Open Source Project
+  Copyright 2023 The Android Open Source Project
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -15,20 +15,23 @@
   -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:orientation="horizontal">
+    android:layout_height="match_parent">
 
-    <TextView
-        android:id="@+id/text"
-        android:layout_width="0dp"
+    <EditText
+        android:id="@+id/edit_text_id"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_weight="1" />
+        android:minHeight="200px"
+        android:gravity="center"
+        android:text="EditText"/>
 
     <Button
-        android:id="@+id/button"
-        android:layout_width="100dp"
+        android:id="@+id/hide_ime_id"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:text="@string/settings" />
+        android:textAllCaps="false"
+        android:text="Hide Ime"/>
+
 </LinearLayout>
\ No newline at end of file
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index 08d11c4..43473b5 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -12,10 +12,6 @@
     docs(project(":activity:activity-compose"))
     samples(project(":activity:activity-compose:activity-compose-samples"))
     docs(project(":activity:activity-ktx"))
-    docs(project(":ads:ads-identifier"))
-    docs(project(":ads:ads-identifier-common"))
-    docs(project(":ads:ads-identifier-provider"))
-    docs(project(":ads:ads-identifier-testing"))
     kmpDocs(project(":annotation:annotation"))
     docs(project(":annotation:annotation-experimental"))
     docs(project(":appactions:interaction:interaction-capabilities-communication"))
diff --git a/fragment/fragment/api/current.txt b/fragment/fragment/api/current.txt
index e3f2954..2f167cf 100644
--- a/fragment/fragment/api/current.txt
+++ b/fragment/fragment/api/current.txt
@@ -14,6 +14,7 @@
     method public void onCancel(android.content.DialogInterface);
     method @MainThread public android.app.Dialog onCreateDialog(android.os.Bundle?);
     method @CallSuper public void onDismiss(android.content.DialogInterface);
+    method public final androidx.activity.ComponentDialog requireComponentDialog();
     method public final android.app.Dialog requireDialog();
     method public void setCancelable(boolean);
     method public void setShowsDialog(boolean);
diff --git a/fragment/fragment/api/public_plus_experimental_current.txt b/fragment/fragment/api/public_plus_experimental_current.txt
index e3f2954..2f167cf 100644
--- a/fragment/fragment/api/public_plus_experimental_current.txt
+++ b/fragment/fragment/api/public_plus_experimental_current.txt
@@ -14,6 +14,7 @@
     method public void onCancel(android.content.DialogInterface);
     method @MainThread public android.app.Dialog onCreateDialog(android.os.Bundle?);
     method @CallSuper public void onDismiss(android.content.DialogInterface);
+    method public final androidx.activity.ComponentDialog requireComponentDialog();
     method public final android.app.Dialog requireDialog();
     method public void setCancelable(boolean);
     method public void setShowsDialog(boolean);
diff --git a/fragment/fragment/api/restricted_current.txt b/fragment/fragment/api/restricted_current.txt
index 8251d12..83801ad 100644
--- a/fragment/fragment/api/restricted_current.txt
+++ b/fragment/fragment/api/restricted_current.txt
@@ -14,6 +14,7 @@
     method public void onCancel(android.content.DialogInterface);
     method @MainThread public android.app.Dialog onCreateDialog(android.os.Bundle?);
     method @CallSuper public void onDismiss(android.content.DialogInterface);
+    method public final androidx.activity.ComponentDialog requireComponentDialog();
     method public final android.app.Dialog requireDialog();
     method public void setCancelable(boolean);
     method public void setShowsDialog(boolean);
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.kt
index 3e1efd5..b08ff70 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/DialogFragmentTest.kt
@@ -27,6 +27,7 @@
 import android.widget.EditText
 import android.widget.FrameLayout
 import android.widget.TextView
+import androidx.activity.ComponentDialog
 import androidx.fragment.app.test.EmptyFragmentTestActivity
 import androidx.fragment.test.R
 import androidx.lifecycle.ViewModelStore
@@ -38,6 +39,7 @@
 import androidx.testutils.withUse
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Assert.assertThrows
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -532,6 +534,86 @@
         fc2.shutdown(viewModelStore)
     }
 
+    @Test
+    fun testRequireDialog() {
+        val dialogFragment = TestDialogFragment()
+        val fm = activityTestRule.activity.supportFragmentManager
+
+        activityTestRule.runOnUiThread {
+            fm.beginTransaction()
+                .add(dialogFragment, null)
+                .commitNow()
+        }
+
+        val dialog = dialogFragment.requireDialog()
+        activityTestRule.runOnUiThread {
+            assertWithMessage("requireDialog() should return")
+                .that(dialogFragment.requireDialog())
+                .isNotNull()
+        }
+
+        activityTestRule.runOnUiThread {
+            dialog.cancel()
+            fm.beginTransaction()
+                .remove(dialogFragment)
+                .commitNow()
+            assertThrows(IllegalStateException::class.java) {
+                dialogFragment.requireDialog()
+            }
+        }
+    }
+
+    @Test
+    fun testRequireComponentDialog() {
+        val dialogFragment = DialogFragment()
+        val fm = activityTestRule.activity.supportFragmentManager
+
+        lateinit var componentDialog: ComponentDialog
+        activityTestRule.runOnUiThread {
+            componentDialog = ComponentDialog(activityTestRule.activity)
+            dialogFragment.setupDialog(componentDialog, 1)
+            fm.beginTransaction()
+                .add(dialogFragment, null)
+                .commitNow()
+        }
+
+        activityTestRule.runOnUiThread {
+            assertWithMessage("requireComponentDialog() should return")
+                .that(dialogFragment.requireComponentDialog())
+                .isNotNull()
+        }
+
+        activityTestRule.runOnUiThread {
+            componentDialog.cancel()
+            fm.beginTransaction()
+                .remove(dialogFragment)
+                .commitNow()
+            assertThrows(IllegalStateException::class.java) {
+                dialogFragment.requireComponentDialog()
+            }
+        }
+    }
+
+    @Test
+    fun testRequireComponentDialog_notComponentDialog() {
+        val dialogFragment = TestDialogFragment()
+        val fm = activityTestRule.activity.supportFragmentManager
+
+        activityTestRule.runOnUiThread {
+            val componentDialog = ComponentDialog(activityTestRule.activity)
+            dialogFragment.setupDialog(componentDialog, 1)
+            fm.beginTransaction()
+                .add(dialogFragment, null)
+                .commitNow()
+        }
+
+        activityTestRule.runOnUiThread {
+            assertThrows(IllegalStateException::class.java) {
+                dialogFragment.requireComponentDialog()
+            }
+        }
+    }
+
     class TestDialogFragment(val setShowsDialog: Boolean = false) : DialogFragment() {
         var onCancelCalled = false
 
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/DialogFragment.java b/fragment/fragment/src/main/java/androidx/fragment/app/DialogFragment.java
index 7f942ad..2ff6f45 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/DialogFragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/DialogFragment.java
@@ -649,6 +649,26 @@
         return dialog;
     }
 
+    /**
+     * Return the {@link ComponentDialog} this fragment is currently controlling.
+     *
+     * @throws IllegalStateException if the Dialog found is not a ComponentDialog or
+     * if Dialog has not yet been created (before {@link #onCreateDialog(Bundle)})
+     * or has been destroyed (after {@link #onDestroyView()}.
+     *
+     * @see #requireDialog()
+     */
+    @NonNull
+    public final ComponentDialog requireComponentDialog() {
+        Dialog dialog = requireDialog();
+        if (!(dialog instanceof ComponentDialog)) {
+            throw new IllegalStateException("DialogFragment " + this
+                    + " did not return a ComponentDialog instance from "
+                    + "requireDialog(). The actual Dialog is " + dialog);
+        }
+        return (ComponentDialog) dialog;
+    }
+
     @StyleRes
     public int getTheme() {
         return mTheme;
diff --git a/glance/glance-appwidget-preview/src/androidAndroidTest/kotlin/androidx/glance/appwidget/preview/GlanceAppWidgetViewAdapterTest.kt b/glance/glance-appwidget-preview/src/androidAndroidTest/kotlin/androidx/glance/appwidget/preview/GlanceAppWidgetViewAdapterTest.kt
index d851096..92d17b07 100644
--- a/glance/glance-appwidget-preview/src/androidAndroidTest/kotlin/androidx/glance/appwidget/preview/GlanceAppWidgetViewAdapterTest.kt
+++ b/glance/glance-appwidget-preview/src/androidAndroidTest/kotlin/androidx/glance/appwidget/preview/GlanceAppWidgetViewAdapterTest.kt
@@ -21,6 +21,7 @@
 import android.os.Bundle
 import android.view.View
 import android.view.ViewGroup
+import android.widget.Button
 import android.widget.FrameLayout
 import android.widget.LinearLayout
 import android.widget.RelativeLayout
@@ -110,10 +111,11 @@
             assertNotNull(viewNotFoundMsg("TextView", "Text"), textView)
             val linearLayoutRow = linearLayoutColumn.getChildOfType<LinearLayout>()
             assertNotNull(viewNotFoundMsg("LinearLayout", "Row"), linearLayoutRow)
-            // Depending on the API version Button might be wrapped in the RelativeLayout
-            val button1 = linearLayoutRow!!.getChildOfType<FrameLayout>()
+            // Backport button are implemented using FrameLayout and depending on the API version
+            // Button might be wrapped in the RelativeLayout.
+            val button1 = linearLayoutRow!!.getChildOfType<Button>()
                 ?: linearLayoutRow.getChildOfType<RelativeLayout>()!!.getChildOfType<FrameLayout>()
-            val button2 = linearLayoutRow.getChildOfType<FrameLayout>(1)
+            val button2 = linearLayoutRow.getChildOfType<Button>(1)
                 ?: linearLayoutRow.getChildOfType<RelativeLayout>(1)!!.getChildOfType<FrameLayout>()
             assertNotNull(viewNotFoundMsg("FrameLayout", "Button"), button1)
             assertNotNull(viewNotFoundMsg("FrameLayout", "Button"), button2)
diff --git a/glance/glance-appwidget/api/current.txt b/glance/glance-appwidget/api/current.txt
index fbdf3cf..a0ce5f3 100644
--- a/glance/glance-appwidget/api/current.txt
+++ b/glance/glance-appwidget/api/current.txt
@@ -2,8 +2,8 @@
 package androidx.glance.appwidget {
 
   public final class AndroidRemoteViewsKt {
-    method @androidx.compose.runtime.Composable public static void AndroidRemoteViews(android.widget.RemoteViews remoteViews);
-    method @androidx.compose.runtime.Composable public static void AndroidRemoteViews(android.widget.RemoteViews remoteViews, @IdRes int containerViewId, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void AndroidRemoteViews(android.widget.RemoteViews remoteViews, optional androidx.glance.GlanceModifier modifier);
+    method @androidx.compose.runtime.Composable public static void AndroidRemoteViews(android.widget.RemoteViews remoteViews, @IdRes int containerViewId, optional androidx.glance.GlanceModifier modifier, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   public final class AppWidgetBackgroundKt {
diff --git a/glance/glance-appwidget/api/public_plus_experimental_current.txt b/glance/glance-appwidget/api/public_plus_experimental_current.txt
index 041c8e4..2d5f4c8 100644
--- a/glance/glance-appwidget/api/public_plus_experimental_current.txt
+++ b/glance/glance-appwidget/api/public_plus_experimental_current.txt
@@ -2,8 +2,8 @@
 package androidx.glance.appwidget {
 
   public final class AndroidRemoteViewsKt {
-    method @androidx.compose.runtime.Composable public static void AndroidRemoteViews(android.widget.RemoteViews remoteViews);
-    method @androidx.compose.runtime.Composable public static void AndroidRemoteViews(android.widget.RemoteViews remoteViews, @IdRes int containerViewId, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void AndroidRemoteViews(android.widget.RemoteViews remoteViews, optional androidx.glance.GlanceModifier modifier);
+    method @androidx.compose.runtime.Composable public static void AndroidRemoteViews(android.widget.RemoteViews remoteViews, @IdRes int containerViewId, optional androidx.glance.GlanceModifier modifier, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   public final class AppWidgetBackgroundKt {
diff --git a/glance/glance-appwidget/api/restricted_current.txt b/glance/glance-appwidget/api/restricted_current.txt
index fbdf3cf..a0ce5f3 100644
--- a/glance/glance-appwidget/api/restricted_current.txt
+++ b/glance/glance-appwidget/api/restricted_current.txt
@@ -2,8 +2,8 @@
 package androidx.glance.appwidget {
 
   public final class AndroidRemoteViewsKt {
-    method @androidx.compose.runtime.Composable public static void AndroidRemoteViews(android.widget.RemoteViews remoteViews);
-    method @androidx.compose.runtime.Composable public static void AndroidRemoteViews(android.widget.RemoteViews remoteViews, @IdRes int containerViewId, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @androidx.compose.runtime.Composable public static void AndroidRemoteViews(android.widget.RemoteViews remoteViews, optional androidx.glance.GlanceModifier modifier);
+    method @androidx.compose.runtime.Composable public static void AndroidRemoteViews(android.widget.RemoteViews remoteViews, @IdRes int containerViewId, optional androidx.glance.GlanceModifier modifier, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
   public final class AppWidgetBackgroundKt {
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml b/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
index 149bfbb..27cc5b3 100644
--- a/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/AndroidManifest.xml
@@ -164,6 +164,19 @@
         </receiver>
 
         <receiver
+            android:name="androidx.glance.appwidget.demos.RemoteViewsWidgetReceiver"
+            android:label="@string/remote_views_widget_name"
+            android:enabled="@bool/glance_appwidget_available"
+            android:exported="false">
+            <intent-filter>
+                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+            </intent-filter>
+            <meta-data
+                android:name="android.appwidget.provider"
+                android:resource="@xml/default_app_widget_info" />
+        </receiver>
+
+        <receiver
             android:name="androidx.glance.appwidget.demos.VerticalGridAppWidgetReceiver"
             android:label="@string/grid_widget_name"
             android:enabled="@bool/glance_appwidget_available"
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/RemoteViewsWidget.kt b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/RemoteViewsWidget.kt
new file mode 100644
index 0000000..5797cff5
--- /dev/null
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/RemoteViewsWidget.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.glance.appwidget.demos
+
+import android.content.Context
+import android.widget.RemoteViews
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
+import androidx.glance.GlanceId
+import androidx.glance.GlanceModifier
+import androidx.glance.LocalContext
+import androidx.glance.appwidget.AndroidRemoteViews
+import androidx.glance.appwidget.GlanceAppWidget
+import androidx.glance.appwidget.GlanceAppWidgetReceiver
+import androidx.glance.appwidget.SizeMode
+import androidx.glance.appwidget.cornerRadius
+import androidx.glance.appwidget.provideContent
+import androidx.glance.background
+import androidx.glance.layout.Alignment
+import androidx.glance.layout.Box
+import androidx.glance.layout.Column
+import androidx.glance.layout.fillMaxSize
+import androidx.glance.layout.fillMaxWidth
+import androidx.glance.layout.wrapContentHeight
+import androidx.glance.layout.wrapContentSize
+import androidx.glance.text.Text
+
+/**
+ * Sample AppWidget that showcase the [AndroidRemoteViews] fallback composable.
+ */
+class RemoteViewsWidget : GlanceAppWidget() {
+    override val sizeMode: SizeMode = SizeMode.Exact
+
+    override suspend fun provideGlance(
+        context: Context,
+        id: GlanceId
+    ) = provideContent {
+        Column(
+            modifier = GlanceModifier.fillMaxSize().background(Color.White),
+            horizontalAlignment = Alignment.Horizontal.CenterHorizontally
+        ) {
+            // Demonstrates a single item remote view layout
+            val remoteViews =
+                RemoteViews(LocalContext.current.packageName, R.layout.test_remote_views_single)
+            AndroidRemoteViews(
+                remoteViews = remoteViews,
+                modifier = GlanceModifier
+                    .fillMaxWidth()
+                    .wrapContentHeight()
+                    .cornerRadius(16.dp)
+                    .background(Color.Red)
+            )
+
+            // Demonstrates a remote view layout being used as a container for regular glance
+            // composables
+            val flipper =
+                RemoteViews(LocalContext.current.packageName, R.layout.test_remote_views_multiple)
+            Text(text = "Container RemoteViews")
+            Box(
+                modifier = GlanceModifier.fillMaxWidth().defaultWeight(),
+                contentAlignment = Alignment.Center
+            ) {
+                AndroidRemoteViews(
+                    remoteViews = flipper,
+                    containerViewId = R.id.test_flipper_root,
+                    modifier = GlanceModifier.wrapContentSize()
+                ) {
+                    Text(text = "First")
+                    Text(text = "Second")
+                }
+            }
+        }
+    }
+}
+
+class RemoteViewsWidgetReceiver : GlanceAppWidgetReceiver() {
+    override val glanceAppWidget: GlanceAppWidget = RemoteViewsWidget()
+}
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/RippleAppWidget.kt b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/RippleAppWidget.kt
index 8202282..c84c97f 100644
--- a/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/RippleAppWidget.kt
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/java/androidx/glance/appwidget/demos/RippleAppWidget.kt
@@ -24,8 +24,10 @@
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
+import androidx.glance.ColorFilter
 import androidx.glance.GlanceId
 import androidx.glance.GlanceModifier
+import androidx.glance.GlanceTheme
 import androidx.glance.Image
 import androidx.glance.ImageProvider
 import androidx.glance.action.clickable
@@ -39,6 +41,7 @@
 import androidx.glance.layout.Box
 import androidx.glance.layout.Column
 import androidx.glance.layout.ContentScale
+import androidx.glance.layout.Row
 import androidx.glance.layout.Spacer
 import androidx.glance.layout.fillMaxSize
 import androidx.glance.layout.fillMaxWidth
@@ -84,10 +87,24 @@
                     }
                 }
         ) {
-            Text(
-                text = "Content Scale: ${type.asString()}, Image / Box click count: $count",
-                modifier = GlanceModifier.padding(5.dp)
-            )
+            Row(verticalAlignment = Alignment.CenterVertically) {
+                Text(
+                    text = "Content Scale: ${type.asString()}, Image / Box click count: $count",
+                    modifier = GlanceModifier.padding(5.dp).defaultWeight()
+                )
+                // Demonstrates an icon button with circular ripple.
+                Image(
+                    provider = ImageProvider(R.drawable.ic_color_reset),
+                    contentDescription = "Remove background color",
+                    colorFilter = ColorFilter.tint(GlanceTheme.colors.secondary),
+                    modifier = GlanceModifier
+                        .padding(5.dp)
+                        .cornerRadius(24.dp) // To get a rounded ripple
+                        .clickable {
+                            columnBgColors = listOf(Color.Transparent, Color.Transparent)
+                        }
+                )
+            }
             // A drawable image with rounded corners and a click modifier.
             OutlinedButtonUsingImage(text = "Toggle content scale", onClick = {
                 type = when (type) {
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/res/drawable/ic_color_reset.xml b/glance/glance-appwidget/integration-tests/demos/src/main/res/drawable/ic_color_reset.xml
new file mode 100644
index 0000000..27def3a
--- /dev/null
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/res/drawable/ic_color_reset.xml
@@ -0,0 +1,21 @@
+<!--
+  Copyright 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<vector android:height="24dp" android:tint="#6A8AF5"
+    android:viewportHeight="24" android:viewportWidth="24"
+    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="@android:color/white" android:pathData="M18,14c0,-4 -6,-10.8 -6,-10.8s-1.33,1.51 -2.73,3.52l8.59,8.59c0.09,-0.42 0.14,-0.86 0.14,-1.31zM17.12,17.12L12.5,12.5 5.27,5.27 4,6.55l3.32,3.32C6.55,11.32 6,12.79 6,14c0,3.31 2.69,6 6,6 1.52,0 2.9,-0.57 3.96,-1.5l2.63,2.63 1.27,-1.27 -2.74,-2.74z"/>
+</vector>
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/res/layout/test_remote_views_multiple.xml b/glance/glance-appwidget/integration-tests/demos/src/main/res/layout/test_remote_views_multiple.xml
new file mode 100644
index 0000000..257a250
--- /dev/null
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/res/layout/test_remote_views_multiple.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  Copyright 2023 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/test_flipper_root"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:autoStart="true"
+    android:flipInterval="2000">
+</ViewFlipper>
diff --git a/ads/ads-identifier/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml b/glance/glance-appwidget/integration-tests/demos/src/main/res/layout/test_remote_views_single.xml
similarity index 62%
rename from ads/ads-identifier/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
rename to glance/glance-appwidget/integration-tests/demos/src/main/res/layout/test_remote_views_single.xml
index 4d7dca0..e2004b8 100644
--- a/ads/ads-identifier/integration-tests/testapp/src/main/res/values/donottranslate-strings.xml
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/res/layout/test_remote_views_single.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  Copyright 2019 The Android Open Source Project
+  Copyright 2023 The Android Open Source Project
 
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
@@ -15,10 +15,9 @@
   limitations under the License.
   -->
 
-<resources>
-    <string name="app_name">Ad ID</string>
-    <string name="get_ad_id">Get Ad ID</string>
-    <string name="get_ad_id_sync">Get Ad ID (Sync)</string>
-    <string name="list_provider">List Providers</string>
-    <string name="is_provider_available">Is Provider Available</string>
-</resources>
\ No newline at end of file
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="48dp"
+    android:gravity="center"
+    android:text="Single RemoteView">
+</TextView>
diff --git a/glance/glance-appwidget/integration-tests/demos/src/main/res/values/strings.xml b/glance/glance-appwidget/integration-tests/demos/src/main/res/values/strings.xml
index 1bf0d9a..0076752 100644
--- a/glance/glance-appwidget/integration-tests/demos/src/main/res/values/strings.xml
+++ b/glance/glance-appwidget/integration-tests/demos/src/main/res/values/strings.xml
@@ -30,6 +30,7 @@
     <string name="scrollable_widget_name">Scrollable Widget</string>
     <string name="image_widget_name">Image Widget</string>
     <string name="ripple_widget_name">Ripple Widget</string>
+    <string name="remote_views_widget_name">Android Remote Views Widget</string>
     <string name="grid_widget_name">Vertical Grid Widget</string>
     <string name="default_state_widget_name">Default State Widget</string>
     <string name="progress_indicator_widget_name">ProgressBar Widget</string>
diff --git a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverScreenshotTest.kt b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverScreenshotTest.kt
index 3a4ec0e..b0897e3 100644
--- a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverScreenshotTest.kt
+++ b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverScreenshotTest.kt
@@ -38,6 +38,7 @@
 import androidx.glance.layout.Column
 import androidx.glance.layout.ContentScale
 import androidx.glance.layout.Row
+import androidx.glance.layout.Spacer
 import androidx.glance.layout.fillMaxHeight
 import androidx.glance.layout.fillMaxSize
 import androidx.glance.layout.fillMaxWidth
@@ -224,6 +225,25 @@
     }
 
     @Test
+    fun checkButtonRoundedCorners_light() {
+        TestGlanceAppWidget.uiDefinition = { RoundedButtonScreenshotTest() }
+
+        mHostRule.startHost()
+
+        mScreenshotRule.checkScreenshot(mHostRule.mHostView, "roundedButton_light")
+    }
+
+    @Test
+    @WithNightMode
+    fun checkButtonRoundedCorners_dark() {
+        TestGlanceAppWidget.uiDefinition = { RoundedButtonScreenshotTest() }
+
+        mHostRule.startHost()
+
+        mScreenshotRule.checkScreenshot(mHostRule.mHostView, "roundedButton_dark")
+    }
+
+    @Test
     fun checkButtonTextAlignment() {
         TestGlanceAppWidget.uiDefinition = {
             Column(modifier = GlanceModifier.fillMaxSize()) {
@@ -624,6 +644,49 @@
 }
 
 @Composable
+private fun RoundedButtonScreenshotTest() {
+    val columnColors = listOf(Color(0xffffdbcd), Color(0xff7d2d00))
+    val buttonBgColors = listOf(Color(0xffa33e00), Color(0xffffb596))
+    val buttonTextColors = listOf(Color(0xffffffff), Color(0xff581e00))
+
+    Column(
+        modifier = GlanceModifier.padding(10.dp)
+            .background(day = columnColors[0], night = columnColors[1])
+    ) {
+        Button(
+            "Button with textAlign = Start",
+            onClick = actionStartActivity<Activity>(),
+            colors = ButtonColors(
+                backgroundColor = ColorProvider(day = buttonBgColors[0], night = buttonBgColors[1]),
+                contentColor = ColorProvider(day = buttonTextColors[0], night = buttonTextColors[1])
+            ),
+            style = TextStyle(textAlign = TextAlign.Start)
+        )
+        Spacer(modifier = GlanceModifier.height(5.dp).fillMaxWidth())
+        Button(
+            "Button with textAlign = Center and padding (30dp, 30dp)",
+            onClick = actionStartActivity<Activity>(),
+            modifier = GlanceModifier.padding(horizontal = 30.dp, vertical = 30.dp),
+            colors = ButtonColors(
+                backgroundColor = ColorProvider(day = buttonBgColors[0], night = buttonBgColors[1]),
+                contentColor = ColorProvider(day = buttonTextColors[0], night = buttonTextColors[1])
+            ),
+            style = TextStyle(textAlign = TextAlign.Center)
+        )
+        Spacer(modifier = GlanceModifier.height(5.dp).fillMaxWidth())
+        Button(
+            "Button with textAlign = End",
+            onClick = actionStartActivity<Activity>(),
+            colors = ButtonColors(
+                backgroundColor = ColorProvider(day = buttonBgColors[0], night = buttonBgColors[1]),
+                contentColor = ColorProvider(day = buttonTextColors[0], night = buttonTextColors[1])
+            ),
+            style = TextStyle(textAlign = TextAlign.End)
+        )
+    }
+}
+
+@Composable
 private fun CheckBoxScreenshotTest() {
     Column(modifier = GlanceModifier.background(day = Color.White, night = Color.Black)) {
         CheckBox(
diff --git a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverTest.kt b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverTest.kt
index 818ac07..274f935 100644
--- a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverTest.kt
+++ b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/GlanceAppWidgetReceiverTest.kt
@@ -29,6 +29,7 @@
 import android.util.Log
 import android.view.View
 import android.view.ViewGroup
+import android.widget.Button
 import android.widget.CompoundButton
 import android.widget.FrameLayout
 import android.widget.ImageView
@@ -437,6 +438,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 31)
     fun createButton() {
         TestGlanceAppWidget.uiDefinition = {
             Button(
@@ -452,6 +454,33 @@
 
         mHostRule.startHost()
 
+        mHostRule.onUnboxedHostView<Button> { button ->
+            checkNotNull(button.text.toString() == "Button") {
+                "Couldn't find 'Button'"
+            }
+
+            assertThat(button.isEnabled).isFalse()
+            assertThat(button.hasOnClickListeners()).isFalse()
+        }
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 29, maxSdkVersion = 30)
+    fun createButtonBackport() {
+        TestGlanceAppWidget.uiDefinition = {
+            Button(
+                text = "Button",
+                onClick = actionStartActivity<Activity>(),
+                colors = ButtonColors(
+                    backgroundColor = ColorProvider(Color.Transparent),
+                    contentColor = ColorProvider(Color.DarkGray)
+                ),
+                enabled = false
+            )
+        }
+
+        mHostRule.startHost()
+
         mHostRule.onUnboxedHostView<FrameLayout> { button ->
             checkNotNull(button.findChild<TextView> { it.text.toString() == "Button" }) {
                 "Couldn't find TextView 'Button'"
@@ -909,6 +938,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 31)
     fun lambdaActionCallback() = runTest {
         TestGlanceAppWidget.uiDefinition = {
             val text = remember { mutableStateOf("initial") }
@@ -922,6 +952,34 @@
 
         mHostRule.startHost()
         var button: View? = null
+        mHostRule.onUnboxedHostView<Button> { buttonView ->
+            assertThat(buttonView.text.toString()).isEqualTo("initial")
+            button = buttonView
+        }
+        mHostRule.runAndWaitForUpdate {
+            button!!.performClick()
+        }
+
+        mHostRule.onUnboxedHostView<Button> { buttonView ->
+            assertThat(buttonView.text.toString()).isEqualTo("clicked")
+        }
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 29, maxSdkVersion = 30)
+    fun lambdaActionCallback_backportButton() = runTest {
+        TestGlanceAppWidget.uiDefinition = {
+            val text = remember { mutableStateOf("initial") }
+            Button(
+                text = text.value,
+                onClick = {
+                    text.value = "clicked"
+                }
+            )
+        }
+
+        mHostRule.startHost()
+        var button: View? = null
         mHostRule.onUnboxedHostView<ViewGroup> { root ->
             val text = checkNotNull(root.findChild<TextView> { it.text.toString() == "initial" })
             button = text.parent as View
diff --git a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/LazyColumnTest.kt b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/LazyColumnTest.kt
index 4d75f81..ea13a13 100644
--- a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/LazyColumnTest.kt
+++ b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/LazyColumnTest.kt
@@ -20,6 +20,7 @@
 import android.os.Build
 import android.view.Gravity
 import android.view.View
+import android.widget.Button
 import android.widget.FrameLayout
 import android.widget.ListView
 import android.widget.TextView
@@ -323,6 +324,7 @@
     }
 
     @Test
+    @SdkSuppress(minSdkVersion = 31)
     fun clickable_addsClickHandlers() {
         TestGlanceAppWidget.uiDefinition = {
             LazyColumn {
@@ -344,8 +346,40 @@
         mHostRule.waitForListViewChildren { list ->
             val row = list.getUnboxedListItem<FrameLayout>(0)
             val (rowItem0, rowItem1) = row.notGoneChildren.toList()
-            // All items with actions are wrapped in FrameLayout
+            // Clickable text items are wrapped in a FrameLayout.
             assertIs<FrameLayout>(rowItem0)
+            assertIs<Button>(rowItem1)
+            assertThat(rowItem0.hasOnClickListeners()).isTrue()
+            assertThat(rowItem1.hasOnClickListeners()).isTrue()
+        }
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 29, maxSdkVersion = 30)
+    fun clickable_backportButton_addsClickHandlers() {
+        TestGlanceAppWidget.uiDefinition = {
+            LazyColumn {
+                item {
+                    Text(
+                        "Text",
+                        modifier = GlanceModifier.clickable(actionStartActivity<Activity>())
+                    )
+                    Button(
+                        "Button",
+                        onClick = actionStartActivity<Activity>()
+                    )
+                }
+            }
+        }
+
+        mHostRule.startHost()
+
+        mHostRule.waitForListViewChildren { list ->
+            val row = list.getUnboxedListItem<FrameLayout>(0)
+            val (rowItem0, rowItem1) = row.notGoneChildren.toList()
+            // Clickable text items are wrapped in a FrameLayout.
+            assertIs<FrameLayout>(rowItem0)
+            // backport buttons are implemented using FrameLayout.
             assertIs<FrameLayout>(rowItem1)
             assertThat(rowItem0.hasOnClickListeners()).isTrue()
             assertThat(rowItem1.hasOnClickListeners()).isTrue()
@@ -354,6 +388,7 @@
 
     @OptIn(FlowPreview::class)
     @Test
+    @SdkSuppress(minSdkVersion = 31)
     fun clickTriggersOnlyOneLambda() = runBlocking {
         val received = MutableStateFlow(-1)
         TestGlanceAppWidget.uiDefinition = {
@@ -371,6 +406,42 @@
 
         mHostRule.startHost()
 
+        val buttons = arrayOfNulls<Button>(5)
+        mHostRule.waitForListViewChildren { list ->
+            for (it in 0..4) {
+                val button = list.getUnboxedListItem<Button>(it)
+                buttons[it] = button
+            }
+        }
+        (0..4).shuffled().forEach { index ->
+            mHostRule.onHostActivity {
+                buttons[index]!!.performClick()
+            }
+            val lastClicked = received.debounce(500.milliseconds).first()
+            assertThat(lastClicked).isEqualTo(index)
+        }
+    }
+
+    @OptIn(FlowPreview::class)
+    @Test
+    @SdkSuppress(minSdkVersion = 29, maxSdkVersion = 30)
+    fun clickTriggersOnlyOneLambda_backportButton() = runBlocking {
+        val received = MutableStateFlow(-1)
+        TestGlanceAppWidget.uiDefinition = {
+            LazyColumn {
+                items((0..4).toList()) {
+                    Button(
+                        "$it",
+                        onClick = {
+                            launch { received.emit(it) }
+                        }
+                    )
+                }
+            }
+        }
+
+        mHostRule.startHost()
+
         val buttons = arrayOfNulls<FrameLayout>(5)
         mHostRule.waitForListViewChildren { list ->
             for (it in 0..4) {
diff --git a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/StrictModeTest.kt b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/StrictModeTest.kt
index ee9bb39..a4ccfdc 100644
--- a/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/StrictModeTest.kt
+++ b/glance/glance-appwidget/src/androidAndroidTest/kotlin/androidx/glance/appwidget/StrictModeTest.kt
@@ -20,6 +20,7 @@
 import android.os.StrictMode
 import android.util.Log
 import android.view.View
+import android.widget.Button
 import android.widget.FrameLayout
 import android.widget.TextView
 import androidx.annotation.RequiresApi
@@ -156,7 +157,8 @@
         mHostRule.waitForListViewChildren { list ->
             val row = list.getUnboxedListItem<FrameLayout>(0)
             val (_, rowItem1) = row.notGoneChildren.toList()
-            assertIs<FrameLayout>(rowItem1)
+            // S+ buttons are implemented using native buttons.
+            assertIs<Button>(rowItem1)
             Truth.assertThat(rowItem1.hasOnClickListeners()).isTrue()
             allowUnsafeIntentLaunch { rowItem1.performClick() }
         }
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/AndroidRemoteViews.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/AndroidRemoteViews.kt
index 98e7863..f199042 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/AndroidRemoteViews.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/AndroidRemoteViews.kt
@@ -29,10 +29,14 @@
  * Add [RemoteViews] into a glance composition.
  *
  * @param remoteViews the views to add to the composition.
+ * @param modifier modifier used to adjust the layout algorithm or draw decoration content.
  */
 @Composable
-fun AndroidRemoteViews(remoteViews: RemoteViews) {
-    AndroidRemoteViews(remoteViews, View.NO_ID) { }
+fun AndroidRemoteViews(
+    remoteViews: RemoteViews,
+    modifier: GlanceModifier = GlanceModifier
+) {
+    AndroidRemoteViews(remoteViews, View.NO_ID, modifier) { }
 }
 
 /**
@@ -43,11 +47,14 @@
  * pre-existing children of that view will be removed with [RemoteViews.removeAllViews], and
  * any children defined in the [content] block will be added with [RemoteViews.addView] (or
  * [RemoteViews.addStableView] if available on the system).
+ * @param modifier modifier used to adjust the layout algorithm or draw decoration content.
+ * @param content the content that will be added to the provided container.
  */
 @Composable
 fun AndroidRemoteViews(
     remoteViews: RemoteViews,
     @IdRes containerViewId: Int,
+    modifier: GlanceModifier = GlanceModifier,
     content: @Composable () -> Unit,
 ) {
     GlanceNode(
@@ -55,6 +62,7 @@
         update = {
             this.set(remoteViews) { this.remoteViews = it }
             this.set(containerViewId) { this.containerViewId = it }
+            this.set(modifier) { this.modifier = it }
         },
         content = content
     )
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/NormalizeCompositionTree.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/NormalizeCompositionTree.kt
index 40a865e..e4045f7 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/NormalizeCompositionTree.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/NormalizeCompositionTree.kt
@@ -15,6 +15,7 @@
  */
 package androidx.glance.appwidget
 
+import android.os.Build
 import android.util.Log
 import androidx.compose.ui.unit.dp
 import androidx.glance.BackgroundModifier
@@ -28,12 +29,13 @@
 import androidx.glance.action.LambdaAction
 import androidx.glance.appwidget.action.CompoundButtonAction
 import androidx.glance.appwidget.lazy.EmittableLazyListItem
-import androidx.glance.background
 import androidx.glance.extractModifier
 import androidx.glance.findModifier
 import androidx.glance.layout.Alignment
+import androidx.glance.layout.ContentScale
 import androidx.glance.layout.EmittableBox
 import androidx.glance.layout.HeightModifier
+import androidx.glance.layout.PaddingModifier
 import androidx.glance.layout.WidthModifier
 import androidx.glance.layout.fillMaxHeight
 import androidx.glance.layout.fillMaxSize
@@ -192,13 +194,13 @@
     val shouldWrapTargetInABox = target.modifier.any {
         // Background images (i.e. BitMap or drawable resources) are emulated by placing the image
         // before the target in the wrapper box. This allows us to support content scale as well as
-        // additional image features (e.g. color filters) on background images.
+        // can help support additional processing on background images. Note: Button's don't support
+        // bg image modifier.
         (it is BackgroundModifier && it.imageProvider != null) ||
-            // Ripples are implemented by placing a drawable after the target in the wrapper box.
-            (it is ActionModifier && !hasBuiltinRipple()) ||
-            // Buttons are implemented using a background drawable with rounded corners and an
-            // EmittableText.
-            isButton
+        // R- buttons are implemented using box, images and text.
+        (isButton && Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) ||
+         // Ripples are implemented by placing a drawable after the target in the wrapper box.
+        (it is ActionModifier && !hasBuiltinRipple())
     }
     if (!shouldWrapTargetInABox) return target
 
@@ -209,19 +211,39 @@
     var backgroundImage: EmittableImage? = null
     var rippleImage: EmittableImage? = null
 
-    // bgModifier.imageProvider is converted to an actual image but bgModifier.colorProvider is
-    // applied back to the target. Note: We could have hoisted the bg color to box instead of
-    // adding it back to the target, but for buttons, we also add an outline background to the box.
     val (bgModifier, targetModifiersMinusBg) = target.modifier.extractModifier<BackgroundModifier>()
     if (bgModifier != null) {
-        if (bgModifier.imageProvider != null) {
+        if (isButton) {
+            // Emulate rounded corners (fixed radius) using a drawable and apply background colors
+            // to it. Note: Currently, button doesn't support bg image modifier, but only button
+            // colors.
             backgroundImage = EmittableImage().apply {
                 modifier = GlanceModifier.fillMaxSize()
-                provider = bgModifier.imageProvider
-                contentScale = bgModifier.contentScale
+                provider = ImageProvider(R.drawable.glance_button_outline)
+                // Without setting alpha, if this drawable's base was transparent, solid color won't
+                // be applied as the default blending mode uses alpha from base. And if this
+                // drawable's base was white/none, applying transparent tint will lead to black
+                // color. This shouldn't be issue for icon type drawables, but in this case we are
+                // emulating colored outline. So, we apply tint as well as alpha.
+                bgModifier.colorProvider?.let {
+                    colorFilterParams = TintAndAlphaColorFilterParams(it)
+                }
+                contentScale = ContentScale.FillBounds
             }
-        } else { // is a background color modifier
-            targetModifiers += bgModifier
+        } else {
+            // bgModifier.imageProvider is converted to an actual image but bgModifier.colorProvider
+            // is applied back to the target. Note: We could have hoisted the bg color to box
+            // instead of adding it back to the target, but for buttons, we also add an outline
+            // background to the box.
+            if (bgModifier.imageProvider != null) {
+                backgroundImage = EmittableImage().apply {
+                    modifier = GlanceModifier.fillMaxSize()
+                    provider = bgModifier.imageProvider
+                    contentScale = bgModifier.contentScale
+                }
+            } else { // is a background color modifier
+                targetModifiers += bgModifier
+            }
         }
     }
 
@@ -232,9 +254,12 @@
         targetModifiersMinusBg.extractModifier<ActionModifier>()
     boxModifiers += actionModifier
     if (actionModifier != null && !hasBuiltinRipple()) {
+        val rippleImageProvider =
+            if (isButton) ImageProvider(R.drawable.glance_button_ripple)
+            else ImageProvider(R.drawable.glance_ripple)
         rippleImage = EmittableImage().apply {
             modifier = GlanceModifier.fillMaxSize()
-            provider = ImageProvider(R.drawable.glance_ripple)
+            provider = rippleImageProvider
         }
     }
 
@@ -245,14 +270,12 @@
     boxModifiers += sizeAndCornerModifiers
     targetModifiers += targetModifiersMinusSizeAndCornerRadius.fillMaxSize()
 
-    // If this is a button, set the necessary modifiers on the wrapping Box.
     if (target is EmittableButton) {
-        boxModifiers += GlanceModifier
-            .clipToOutline(true)
-            .enabled(target.enabled)
-            .background(ImageProvider(R.drawable.glance_button_outline))
+        boxModifiers += GlanceModifier.enabled(target.enabled)
         target = target.toEmittableText()
-        targetModifiers += GlanceModifier.padding(horizontal = 16.dp, vertical = 8.dp)
+        if (target.modifier.findModifier<PaddingModifier>() == null) {
+            targetModifiers += GlanceModifier.padding(horizontal = 16.dp, vertical = 8.dp)
+        }
     }
 
     return EmittableBox().apply {
@@ -268,7 +291,11 @@
 private fun Emittable.hasBuiltinRipple() =
     this is EmittableSwitch ||
     this is EmittableRadioButton ||
-    this is EmittableCheckBox
+    this is EmittableCheckBox ||
+     // S+ versions use a native button with fixed rounded corners and matching ripple set in
+     // layout xml. In R- versions, buttons are implemented using a background drawable with
+     // rounded corners and an EmittableText in R- versions.
+    (this is EmittableButton && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
 
 private data class ExtractedSizeModifiers(
     val sizeModifiers: GlanceModifier = GlanceModifier,
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/RemoteViewsTranslator.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/RemoteViewsTranslator.kt
index 405ae563..1b50857 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/RemoteViewsTranslator.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/RemoteViewsTranslator.kt
@@ -34,11 +34,11 @@
 import androidx.glance.Emittable
 import androidx.glance.EmittableButton
 import androidx.glance.EmittableImage
-import androidx.glance.GlanceModifier
 import androidx.glance.appwidget.lazy.EmittableLazyColumn
 import androidx.glance.appwidget.lazy.EmittableLazyListItem
 import androidx.glance.appwidget.lazy.EmittableLazyVerticalGrid
 import androidx.glance.appwidget.lazy.EmittableLazyVerticalGridListItem
+import androidx.glance.appwidget.translators.setText
 import androidx.glance.appwidget.translators.translateEmittableCheckBox
 import androidx.glance.appwidget.translators.translateEmittableCircularProgressIndicator
 import androidx.glance.appwidget.translators.translateEmittableImage
@@ -50,12 +50,13 @@
 import androidx.glance.appwidget.translators.translateEmittableRadioButton
 import androidx.glance.appwidget.translators.translateEmittableSwitch
 import androidx.glance.appwidget.translators.translateEmittableText
+import androidx.glance.findModifier
 import androidx.glance.layout.Alignment
 import androidx.glance.layout.EmittableBox
 import androidx.glance.layout.EmittableColumn
 import androidx.glance.layout.EmittableRow
 import androidx.glance.layout.EmittableSpacer
-import androidx.glance.layout.fillMaxSize
+import androidx.glance.layout.PaddingModifier
 import androidx.glance.layout.padding
 import androidx.glance.text.EmittableText
 import java.util.concurrent.atomic.AtomicBoolean
@@ -405,21 +406,28 @@
     translationContext: TranslationContext,
     element: EmittableButton
 ) {
-    // Separate the button into a wrapper and the text, this allows us to set the color of the text
-    // background, while maintaining the ripple for the click indicator.
-    // TODO: add Image button
-    val content = EmittableText().apply {
-        text = element.text
-        style = element.style
-        maxLines = element.maxLines
-        modifier =
-            GlanceModifier
-                .fillMaxSize()
-                .padding(horizontal = 16.dp, vertical = 8.dp)
+    check(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+        "Buttons in Android R and below are emulated using a EmittableBox containing the text."
     }
-    translateEmittableText(translationContext, content)
-}
+    val viewDef = insertView(translationContext, LayoutType.Button, element.modifier)
+    setText(
+        translationContext,
+        viewDef.mainViewId,
+        element.text,
+        element.style,
+        maxLines = element.maxLines,
+        verticalTextGravity = Gravity.CENTER_VERTICAL,
+    )
 
+    // Adjust appWidget specific modifiers.
+    element.modifier = element.modifier
+        .enabled(element.enabled)
+        .cornerRadius(16.dp)
+    if (element.modifier.findModifier<PaddingModifier>() == null) {
+        element.modifier = element.modifier.padding(horizontal = 16.dp, vertical = 8.dp)
+    }
+    applyModifiers(translationContext, this, element.modifier, viewDef)
+}
 private fun RemoteViews.translateEmittableSpacer(
     translationContext: TranslationContext,
     element: EmittableSpacer
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/TintAndAlphaColorFilterParams.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/TintAndAlphaColorFilterParams.kt
new file mode 100644
index 0000000..03a01af
--- /dev/null
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/TintAndAlphaColorFilterParams.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.glance.appwidget
+
+import androidx.glance.ColorFilterParams
+import androidx.glance.unit.ColorProvider
+
+/**
+ * An internal, AppWidget specific colorFilter that applies alpha as well as tint from the provided
+ * color. Helps with changing color of entire drawable and using it as shaped color background.
+ */
+internal class TintAndAlphaColorFilterParams(val colorProvider: ColorProvider) : ColorFilterParams {
+    override fun toString() =
+        "TintAndAlphaColorFilterParams(colorProvider=$colorProvider))"
+}
\ No newline at end of file
diff --git a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/ImageTranslator.kt b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/ImageTranslator.kt
index f012ed0..dd97752 100644
--- a/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/ImageTranslator.kt
+++ b/glance/glance-appwidget/src/androidMain/kotlin/androidx/glance/appwidget/translators/ImageTranslator.kt
@@ -27,6 +27,7 @@
 import androidx.core.widget.RemoteViewsCompat.setImageViewAdjustViewBounds
 import androidx.core.widget.RemoteViewsCompat.setImageViewColorFilter
 import androidx.core.widget.RemoteViewsCompat.setImageViewColorFilterResource
+import androidx.core.widget.RemoteViewsCompat.setImageViewImageAlpha
 import androidx.glance.AndroidResourceImageProvider
 import androidx.glance.BitmapImageProvider
 import androidx.glance.ColorFilterParams
@@ -36,6 +37,7 @@
 import androidx.glance.appwidget.GlanceAppWidgetTag
 import androidx.glance.appwidget.InsertedViewInfo
 import androidx.glance.appwidget.LayoutType
+import androidx.glance.appwidget.TintAndAlphaColorFilterParams
 import androidx.glance.appwidget.TranslationContext
 import androidx.glance.appwidget.UriImageProvider
 import androidx.glance.appwidget.applyModifiers
@@ -110,6 +112,19 @@
             }
         }
 
+        is TintAndAlphaColorFilterParams -> {
+            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
+                val color =
+                    colorFilterParams.colorProvider.getColor(translationContext.context).toArgb()
+                rv.setImageViewColorFilter(viewDef.mainViewId, color)
+                rv.setImageViewImageAlpha(viewDef.mainViewId, android.graphics.Color.alpha(color))
+            } else {
+                throw IllegalStateException(
+                    "The is no use case yet to support this colorFilter in S+ versions."
+                )
+            }
+        }
+
         else -> throw IllegalArgumentException("An unsupported ColorFilter was used.")
     }
 }
diff --git a/glance/glance-appwidget/src/androidMain/res/drawable/glance_button_outline.xml b/glance/glance-appwidget/src/androidMain/res/drawable/glance_button_outline.xml
index 976eaeb..f95a318 100644
--- a/glance/glance-appwidget/src/androidMain/res/drawable/glance_button_outline.xml
+++ b/glance/glance-appwidget/src/androidMain/res/drawable/glance_button_outline.xml
@@ -15,6 +15,5 @@
   -->
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="@android:color/transparent" />
     <corners android:radius="16dp" />
 </shape>
diff --git a/glance/glance-appwidget/src/androidMain/res/drawable/glance_button_ripple.xml b/glance/glance-appwidget/src/androidMain/res/drawable/glance_button_ripple.xml
new file mode 100644
index 0000000..d974ec2
--- /dev/null
+++ b/glance/glance-appwidget/src/androidMain/res/drawable/glance_button_ripple.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!-- Fixed radius ripple matching the button's outline -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="?android:attr/colorControlHighlight">
+    <item android:id="@android:id/mask">
+        <shape android:shape="rectangle">
+            <corners android:radius="16dp"/>
+            <solid android:color="@android:color/white"/>
+        </shape>
+    </item>
+</ripple>
\ No newline at end of file
diff --git a/glance/glance-appwidget/src/androidMain/res/layout/glance_button.xml b/glance/glance-appwidget/src/androidMain/res/layout/glance_button.xml
index 9489e43..2044ad3 100644
--- a/glance/glance-appwidget/src/androidMain/res/layout/glance_button.xml
+++ b/glance/glance-appwidget/src/androidMain/res/layout/glance_button.xml
@@ -14,9 +14,18 @@
   limitations under the License.
   -->
 
+<!--
+Setting stateListAnimator to null to remove default shadows on the button and make it look
+similar to the custom emulated button in backport implementation. The corner radius of the ripple
+matches the one that is applied to the button later.
+ -->
 <Button xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     app:glance_isTopLevelLayout="true"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    style="@style/Glance.AppWidget.Button"/>
+    android:foreground="@drawable/glance_button_ripple"
+    android:minHeight="0dp"
+    android:minWidth="0dp"
+    android:stateListAnimator="@null"
+    style="@style/Glance.AppWidget.Button"/>
\ No newline at end of file
diff --git a/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/RemoteViewsTranslatorKtTest.kt b/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/RemoteViewsTranslatorKtTest.kt
index a8cec419..0545ef1 100644
--- a/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/RemoteViewsTranslatorKtTest.kt
+++ b/glance/glance-appwidget/src/test/kotlin/androidx/glance/appwidget/RemoteViewsTranslatorKtTest.kt
@@ -26,6 +26,7 @@
 import android.text.style.UnderlineSpan
 import android.util.Log
 import android.view.View
+import android.widget.Button
 import android.widget.FrameLayout
 import android.widget.GridView
 import android.widget.ImageView
@@ -726,7 +727,8 @@
     }
 
     @Test
-    fun canTranslateButton() = fakeCoroutineScope.runTest {
+    @Config(maxSdk = 30)
+    fun canTranslateBackportButton_enabled() = fakeCoroutineScope.runTest {
         val rv = context.runAndTranslate {
             Button(
                 "Button",
@@ -735,7 +737,8 @@
             )
         }
 
-        // All items with actions are wrapped in FrameLayout
+        // Backport button is implemented using a FrameLayout containing an outline image, a text
+        // and a ripple image.
         val frame = assertIs<FrameLayout>(context.applyRemoteViews(rv))
         assertThat(frame.hasOnClickListeners()).isTrue()
         assertThat(frame.isEnabled).isTrue()
@@ -743,6 +746,43 @@
     }
 
     @Test
+    @Config(minSdk = 31)
+    fun canTranslateButton_enabled() = fakeCoroutineScope.runTest {
+        val rv = context.runAndTranslate {
+            Button(
+                "Button",
+                onClick = actionStartActivity<Activity>(),
+                enabled = true
+            )
+        }
+
+        val button = assertIs<Button>(context.applyRemoteViews(rv))
+        assertThat(button.hasOnClickListeners()).isTrue()
+        assertThat(button.isEnabled).isTrue()
+        assertThat(button.text.toString()).isEqualTo("Button")
+    }
+
+    @Test
+    @Config(maxSdk = 30)
+    fun canTranslateBackportButton_disabled() = fakeCoroutineScope.runTest {
+        val rv = context.runAndTranslate {
+            Button(
+                "Button",
+                onClick = actionStartActivity<Activity>(),
+                enabled = false
+            )
+        }
+
+        // Backport button is implemented using a FrameLayout containing an outline image, a text
+        // and a ripple image.
+        val frame = assertIs<FrameLayout>(context.applyRemoteViews(rv))
+        assertThat(frame.hasOnClickListeners()).isFalse()
+        assertThat(frame.isEnabled).isFalse()
+        checkNotNull(frame.findView<TextView> { it.text.toString() == "Button" })
+    }
+
+    @Test
+    @Config(minSdk = 31)
     fun canTranslateButton_disabled() = fakeCoroutineScope.runTest {
         val rv = context.runAndTranslate {
             Button(
@@ -752,10 +792,10 @@
             )
         }
 
-        val frame = assertIs<FrameLayout>(context.applyRemoteViews(rv))
-        assertThat(frame.hasOnClickListeners()).isFalse()
-        assertThat(frame.isEnabled).isFalse()
-        checkNotNull(frame.findView<TextView> { it.text.toString() == "Button" })
+        val button = assertIs<Button>(context.applyRemoteViews(rv))
+        assertThat(button.isEnabled).isFalse()
+        assertThat(button.hasOnClickListeners()).isFalse()
+        assertThat(button.text.toString()).isEqualTo("Button")
     }
 
     @Test
diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index 048d8fc..2843f37 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -563,16 +563,6 @@
             <sha256 value="47a89be0fa0fedd476db5fd2c83487654d2a119c391f83a142be876667cf7dab" origin="Generated by Gradle" reason="Artifact is not signed"/>
          </artifact>
       </component>
-      <component group="com.gradle" name="common-custom-user-data-gradle-plugin" version="1.7.2">
-         <artifact name="common-custom-user-data-gradle-plugin-1.7.2.pom">
-            <sha256 value="c70db912c8b127b1b9a6c0cccac1a9353e9fc3b063a3be0114a5208f43c09c31" origin="Generated by Gradle" reason="Artifact is not signed"/>
-         </artifact>
-      </component>
-      <component group="com.gradle" name="gradle-enterprise-gradle-plugin" version="3.10.2">
-         <artifact name="gradle-enterprise-gradle-plugin-3.10.2.pom">
-            <sha256 value="57603c9a75a9ef86ce30b1cb2db728d3cd9caf1be967343f1fc2316c85df5653" origin="Generated by Gradle"/>
-         </artifact>
-      </component>
       <component group="de.undercouch" name="gradle-download-task" version="4.1.1">
          <artifact name="gradle-download-task-4.1.1.jar">
             <ignored-keys>
diff --git a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/common/Utils.java b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/common/Utils.java
index bd8b616..4d59cf6 100644
--- a/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/common/Utils.java
+++ b/javascriptengine/javascriptengine/src/main/java/androidx/javascriptengine/common/Utils.java
@@ -24,6 +24,7 @@
 import androidx.annotation.Nullable;
 
 import java.io.Closeable;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -170,7 +171,12 @@
                 }
             }
             byte[] bytes = new byte[lengthToRead];
-            try (InputStream inputStream = afd.createInputStream()) {
+            // We can use AssetFileDescriptor.createInputStream() to get the InputStream directly
+            // but this API is currently broken while fixing another issue regarding multiple
+            // AssetFileDescriptor pointing to the same file. (b/263325931)
+            // Using ParcelFileDescriptor to read the file is correct as long as the offset is 0.
+            try (ParcelFileDescriptor pfd = afd.getParcelFileDescriptor()) {
+                InputStream inputStream = new FileInputStream(pfd.getFileDescriptor());
                 if (Utils.readNBytes(inputStream, bytes, 0, lengthToRead) != lengthToRead) {
                     throw new IOException("Couldn't read " + lengthToRead + " bytes from the "
                             + "AssetFileDescriptor");
diff --git a/libraryversions.toml b/libraryversions.toml
index 84ff2fa..4736d27 100644
--- a/libraryversions.toml
+++ b/libraryversions.toml
@@ -1,6 +1,5 @@
 [versions]
 ACTIVITY = "1.8.0-alpha02"
-ADS_IDENTIFIER = "1.0.0-alpha06"
 ANNOTATION = "1.7.0-alpha01"
 ANNOTATION_EXPERIMENTAL = "1.4.0-alpha01"
 APPACTIONS_INTERACTION = "1.0.0-alpha01"
@@ -156,7 +155,6 @@
 
 [groups]
 ACTIVITY = { group = "androidx.activity", atomicGroupVersion = "versions.ACTIVITY" }
-ADS = { group = "androidx.ads" }
 ANNOTATION = { group = "androidx.annotation" }
 APPACTIONS_INTERACTION = { group = "androidx.appactions.interaction", atomicGroupVersion = "versions.APPACTIONS_INTERACTION" }
 APPCOMPAT = { group = "androidx.appcompat", atomicGroupVersion = "versions.APPCOMPAT" }
diff --git a/playground-common/playground-plugin/build.gradle b/playground-common/playground-plugin/build.gradle
index b65ae88..6012c6a 100644
--- a/playground-common/playground-plugin/build.gradle
+++ b/playground-common/playground-plugin/build.gradle
@@ -20,8 +20,8 @@
 }
 
 dependencies {
-    implementation("com.gradle:gradle-enterprise-gradle-plugin:3.10.2")
-    implementation("com.gradle:common-custom-user-data-gradle-plugin:1.7.2")
+    implementation("com.gradle:gradle-enterprise-gradle-plugin:3.12.4")
+    implementation("com.gradle:common-custom-user-data-gradle-plugin:1.9")
     testImplementation(libs.junit)
     testImplementation(libs.truth)
 }
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdkTable.xml b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdkTable.xml
index c03e26b..c72c1a2 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdkTable.xml
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/assets/RuntimeEnabledSdkTable.xml
@@ -17,6 +17,7 @@
     <runtime-enabled-sdk>
         <compat-config-path>RuntimeEnabledSdks/V1/CompatSdkConfig.xml</compat-config-path>
         <package-name>androidx.privacysandbox.sdkruntime.test.v1</package-name>
+        <version-major>42</version-major>
     </runtime-enabled-sdk>
     <runtime-enabled-sdk>
         <compat-config-path>RuntimeEnabledSdks/V2/CompatSdkConfig.xml</compat-config-path>
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatTest.kt
index eeeba1c..b0e4474 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatTest.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/SdkSandboxManagerCompatTest.kt
@@ -25,6 +25,7 @@
 import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
 import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException.Companion.LOAD_SDK_INTERNAL_ERROR
 import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException.Companion.LOAD_SDK_SDK_DEFINED_ERROR
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkInfo
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SdkSuppress
@@ -119,6 +120,14 @@
 
         assertThat(result.getInterface()!!.javaClass.classLoader)
             .isNotSameInstanceAs(managerCompat.javaClass.classLoader)
+
+        assertThat(result.getSdkInfo())
+            .isEqualTo(
+                SandboxedSdkInfo(
+                    name = "androidx.privacysandbox.sdkruntime.test.v1",
+                    version = 42
+                )
+            )
     }
 
     @Test
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigParserTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigParserTest.kt
index 541d137..f7e20ea 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigParserTest.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigParserTest.kt
@@ -49,12 +49,13 @@
             </compat-config>
         """.trimIndent()
 
-        val result = tryParse(xml, packageName = "com.test.sdk.package")
+        val result = tryParse(xml, packageName = "com.test.sdk.package", versionMajor = 1)
 
         assertThat(result)
             .isEqualTo(
                 LocalSdkConfig(
                     packageName = "com.test.sdk.package",
+                    versionMajor = 1,
                     dexPaths = listOf("1.dex", "2.dex"),
                     entryPoint = "compat.sdk.provider",
                     javaResourcesRoot = "javaResPath/",
@@ -81,6 +82,7 @@
             .isEqualTo(
                 LocalSdkConfig(
                     packageName = "com.test.sdk.package",
+                    versionMajor = null,
                     dexPaths = listOf("1.dex"),
                     entryPoint = "compat.sdk.provider",
                     javaResourcesRoot = null,
@@ -239,9 +241,13 @@
         )
     }
 
-    private fun tryParse(xml: String, packageName: String = "sdkPackageName"): LocalSdkConfig {
+    private fun tryParse(
+        xml: String,
+        packageName: String = "sdkPackageName",
+        versionMajor: Int? = null
+    ): LocalSdkConfig {
         ByteArrayInputStream(xml.toByteArray()).use { inputStream ->
-            return parse(inputStream, packageName)
+            return parse(inputStream, packageName, versionMajor)
         }
     }
 }
\ No newline at end of file
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigsHolderTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigsHolderTest.kt
index 0b51558..21c0016 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigsHolderTest.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigsHolderTest.kt
@@ -50,6 +50,7 @@
             .isEqualTo(
                 LocalSdkConfig(
                     packageName = "androidx.privacysandbox.sdkruntime.test.v1",
+                    versionMajor = 42,
                     dexPaths = listOf("RuntimeEnabledSdks/V1/classes.dex"),
                     entryPoint = "androidx.privacysandbox.sdkruntime.test.v1.CompatProvider",
                     javaResourcesRoot = "RuntimeEnabledSdks/V1/javaresources"
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/SdkTableConfigParserTest.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/SdkTableConfigParserTest.kt
index e646377..bc2c9d5 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/SdkTableConfigParserTest.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/androidTest/java/androidx/privacysandbox/sdkruntime/client/config/SdkTableConfigParserTest.kt
@@ -45,6 +45,7 @@
                 <runtime-enabled-sdk>
                     <unknown-tag2>new parameter from future library version</unknown-tag2>
                     <package-name>sdk2</package-name>
+                    <version-major>42</version-major>
                     <compat-config-path>config2.xml</compat-config-path>
                 </runtime-enabled-sdk>
             </runtime-enabled-sdk-table>
@@ -54,8 +55,16 @@
 
         assertThat(result)
             .containsExactly(
-                SdkTableEntry("sdk1", "config1.xml"),
-                SdkTableEntry("sdk2", "config2.xml")
+                SdkTableEntry(
+                    packageName = "sdk1",
+                    versionMajor = null,
+                    compatConfigPath = "config1.xml"
+                ),
+                SdkTableEntry(
+                    packageName = "sdk2",
+                    versionMajor = 42,
+                    compatConfigPath = "config2.xml"
+                )
             )
     }
 
@@ -108,6 +117,26 @@
     }
 
     @Test
+    fun parse_whenMultipleVersionMajor_throwsException() {
+        val xml = """
+            <runtime-enabled-sdk-table>
+                <runtime-enabled-sdk>
+                    <package-name>sdk1</package-name>
+                    <version-major>1</version-major>
+                    <version-major>2</version-major>
+                    <compat-config-path>config1.xml</compat-config-path>
+                </runtime-enabled-sdk>
+            </runtime-enabled-sdk-table>
+        """.trimIndent()
+
+        assertThrows<XmlPullParserException> {
+            tryParse(xml)
+        }.hasMessageThat().isEqualTo(
+            "Duplicate version-major tag found"
+        )
+    }
+
+    @Test
     fun parse_whenNoConfigPath_throwsException() {
         val xml = """
             <runtime-enabled-sdk-table>
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfig.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfig.kt
index 081acf5..1276a7e 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfig.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfig.kt
@@ -21,6 +21,7 @@
  */
 internal data class LocalSdkConfig(
     val packageName: String,
+    val versionMajor: Int? = null,
     val dexPaths: List<String>,
     val entryPoint: String,
     val javaResourcesRoot: String? = null,
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigParser.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigParser.kt
index b9f10c2..5558336 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigParser.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigParser.kt
@@ -41,7 +41,10 @@
     private val xmlParser: XmlPullParser
 ) {
 
-    private fun readConfig(packageName: String): LocalSdkConfig {
+    private fun readConfig(
+        packageName: String,
+        versionMajor: Int?
+    ): LocalSdkConfig {
         xmlParser.require(XmlPullParser.START_DOCUMENT, NAMESPACE, null)
         xmlParser.nextTag()
 
@@ -102,6 +105,7 @@
 
         return LocalSdkConfig(
             packageName,
+            versionMajor,
             dexPaths,
             entryPoint,
             javaResourcesRoot,
@@ -166,12 +170,16 @@
         private const val RESOURCE_REMAPPING_CLASS_ELEMENT_NAME = "r-package-class"
         private const val RESOURCE_REMAPPING_ID_ELEMENT_NAME = "resources-package-id"
 
-        fun parse(inputStream: InputStream, packageName: String): LocalSdkConfig {
+        fun parse(
+            inputStream: InputStream,
+            packageName: String,
+            versionMajor: Int?
+        ): LocalSdkConfig {
             val parser = Xml.newPullParser()
             try {
                 parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false)
                 parser.setInput(inputStream, null)
-                return LocalSdkConfigParser(parser).readConfig(packageName)
+                return LocalSdkConfigParser(parser).readConfig(packageName, versionMajor)
             } finally {
                 parser.setInput(null)
             }
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigsHolder.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigsHolder.kt
index 4232878..0db3714e 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigsHolder.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/LocalSdkConfigsHolder.kt
@@ -43,9 +43,13 @@
             val sdkTable = loadSdkTable(context, sdkTableAssetName)
 
             val data = buildMap {
-                for ((packageName, configPath) in sdkTable) {
+                for ((packageName, versionMajor, configPath) in sdkTable) {
                     context.assets.open(configPath).use { sdkConfigAsset ->
-                        val sdkInfo = LocalSdkConfigParser.parse(sdkConfigAsset, packageName)
+                        val sdkInfo = LocalSdkConfigParser.parse(
+                            sdkConfigAsset,
+                            packageName,
+                            versionMajor
+                        )
                         put(packageName, sdkInfo)
                     }
                 }
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/SdkTableConfigParser.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/SdkTableConfigParser.kt
index eea19cc..6bea778 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/SdkTableConfigParser.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/config/SdkTableConfigParser.kt
@@ -30,10 +30,12 @@
  * <runtime-enabled-sdk-table>
  *     <runtime-enabled-sdk>
  *         <package-name>com.sdk1</package-name>
+ *         <version-major>1</version-major>
  *         <compat-config-path>assets/RuntimeEnabledSdk-com.sdk1/CompatSdkConfig.xml</compat-config-path>
  *     </runtime-enabled-sdk>
  *     <runtime-enabled-sdk>
  *         <package-name>com.sdk2</package-name>
+ *         <version-major>42</version-major>
  *         <compat-config-path>assets/RuntimeEnabledSdk-com.sdk2/CompatSdkConfig.xml</compat-config-path>
  *     </runtime-enabled-sdk>
  * </runtime-enabled-sdk-table>
@@ -75,6 +77,7 @@
 
     private fun readSdkEntry(): SdkTableEntry {
         var packageName: String? = null
+        var versionMajor: Int? = null
         var configPath: String? = null
 
         xmlParser.require(START_TAG, NAMESPACE, SDK_ENTRY_ELEMENT_NAME)
@@ -92,6 +95,15 @@
                     packageName = xmlParser.nextText()
                 }
 
+                VERSION_MAJOR_ELEMENT_NAME -> {
+                    if (versionMajor != null) {
+                        throw XmlPullParserException(
+                            "Duplicate $VERSION_MAJOR_ELEMENT_NAME tag found"
+                        )
+                    }
+                    versionMajor = xmlParser.nextText().toInt()
+                }
+
                 COMPAT_CONFIG_PATH_ELEMENT_NAME -> {
                     if (configPath != null) {
                         throw XmlPullParserException(
@@ -117,11 +129,12 @@
             )
         }
 
-        return SdkTableEntry(packageName, configPath)
+        return SdkTableEntry(packageName, versionMajor, configPath)
     }
 
     internal data class SdkTableEntry(
         val packageName: String,
+        val versionMajor: Int?,
         val compatConfigPath: String,
     )
 
@@ -130,6 +143,7 @@
         private const val SDK_TABLE_ELEMENT_NAME = "runtime-enabled-sdk-table"
         private const val SDK_ENTRY_ELEMENT_NAME = "runtime-enabled-sdk"
         private const val SDK_PACKAGE_NAME_ELEMENT_NAME = "package-name"
+        private const val VERSION_MAJOR_ELEMENT_NAME = "version-major"
         private const val COMPAT_CONFIG_PATH_ELEMENT_NAME = "compat-config-path"
 
         fun parse(inputStream: InputStream): Set<SdkTableEntry> {
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/SdkLoader.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/SdkLoader.kt
index 2422d7a..3fcefd8 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/SdkLoader.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/SdkLoader.kt
@@ -86,7 +86,7 @@
         sdkClassLoader: ClassLoader,
         sdkConfig: LocalSdkConfig
     ): LocalSdkProvider {
-        return SdkProviderV1.create(sdkClassLoader, sdkConfig.entryPoint, appContext)
+        return SdkProviderV1.create(sdkClassLoader, sdkConfig, appContext)
     }
 
     private fun createSdkProviderV2(
@@ -94,7 +94,7 @@
         sdkConfig: LocalSdkConfig
     ): LocalSdkProvider {
         SandboxControllerInjector.inject(sdkClassLoader, controller)
-        return SdkProviderV1.create(sdkClassLoader, sdkConfig.entryPoint, appContext)
+        return SdkProviderV1.create(sdkClassLoader, sdkConfig, appContext)
     }
 
     companion object {
diff --git a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SdkProviderV1.kt b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SdkProviderV1.kt
index 2244324..ce51c0ef 100644
--- a/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SdkProviderV1.kt
+++ b/privacysandbox/sdkruntime/sdkruntime-client/src/main/java/androidx/privacysandbox/sdkruntime/client/loader/impl/SdkProviderV1.kt
@@ -20,9 +20,11 @@
 import android.os.Bundle
 import android.os.IBinder
 import androidx.annotation.RestrictTo
+import androidx.privacysandbox.sdkruntime.client.config.LocalSdkConfig
 import androidx.privacysandbox.sdkruntime.client.loader.LocalSdkProvider
 import androidx.privacysandbox.sdkruntime.core.LoadSdkCompatException
 import androidx.privacysandbox.sdkruntime.core.SandboxedSdkCompat
+import androidx.privacysandbox.sdkruntime.core.SandboxedSdkInfo
 import java.lang.reflect.InvocationTargetException
 import java.lang.reflect.Method
 
@@ -64,25 +66,38 @@
     }
 
     internal class SandboxedSdkCompatBuilderV1 private constructor(
+        private val sdkInfo: SandboxedSdkInfo?,
         private val getInterfaceMethod: Method
     ) {
 
         @SuppressLint("BanUncheckedReflection") // calling method on SandboxedSdkCompat class
         fun build(rawObject: Any): SandboxedSdkCompat {
             val binder = getInterfaceMethod.invoke(rawObject) as IBinder
-            return SandboxedSdkCompat(binder)
+            return SandboxedSdkCompat(binder, sdkInfo)
         }
 
         companion object {
 
-            fun create(classLoader: ClassLoader?): SandboxedSdkCompatBuilderV1 {
+            fun create(
+                classLoader: ClassLoader,
+                sdkConfig: LocalSdkConfig
+            ): SandboxedSdkCompatBuilderV1 {
                 val sandboxedSdkCompatClass = Class.forName(
                     SandboxedSdkCompat::class.java.name,
                     /* initialize = */ false,
                     classLoader
                 )
                 val getInterfaceMethod = sandboxedSdkCompatClass.getMethod("getInterface")
-                return SandboxedSdkCompatBuilderV1(getInterfaceMethod)
+                val sdkInfo = sdkInfo(sdkConfig)
+                return SandboxedSdkCompatBuilderV1(sdkInfo, getInterfaceMethod)
+            }
+
+            private fun sdkInfo(sdkConfig: LocalSdkConfig): SandboxedSdkInfo? {
+                return if (sdkConfig.versionMajor == null) {
+                    null
+                } else {
+                    SandboxedSdkInfo(sdkConfig.packageName, sdkConfig.versionMajor.toLong())
+                }
             }
         }
     }
@@ -117,7 +132,7 @@
         }
 
         companion object {
-            fun create(classLoader: ClassLoader?): LoadSdkCompatExceptionBuilderV1 {
+            fun create(classLoader: ClassLoader): LoadSdkCompatExceptionBuilderV1 {
                 val loadSdkCompatExceptionClass = Class.forName(
                     LoadSdkCompatException::class.java.name,
                     /* initialize = */ false,
@@ -141,12 +156,12 @@
 
         @SuppressLint("BanUncheckedReflection") // calling method of SandboxedSdkProviderCompat
         fun create(
-            classLoader: ClassLoader?,
-            sdkProviderClassName: String,
+            classLoader: ClassLoader,
+            sdkConfig: LocalSdkConfig,
             appContext: Context
         ): SdkProviderV1 {
             val sdkProviderClass = Class.forName(
-                sdkProviderClassName,
+                sdkConfig.entryPoint,
                 /* initialize = */ false,
                 classLoader
             )
@@ -154,7 +169,8 @@
                 sdkProviderClass.getMethod("attachContext", Context::class.java)
             val onLoadSdkMethod = sdkProviderClass.getMethod("onLoadSdk", Bundle::class.java)
             val beforeUnloadSdkMethod = sdkProviderClass.getMethod("beforeUnloadSdk")
-            val sandboxedSdkCompatBuilder = SandboxedSdkCompatBuilderV1.create(classLoader)
+            val sandboxedSdkCompatBuilder =
+                SandboxedSdkCompatBuilderV1.create(classLoader, sdkConfig)
             val loadSdkCompatExceptionBuilder =
                 LoadSdkCompatExceptionBuilderV1.create(classLoader)
 
diff --git a/settings.gradle b/settings.gradle
index 10ad43d..4820e0e 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -23,8 +23,8 @@
     repos.addMavenRepositories(repositories)
 
     dependencies {
-        classpath("com.gradle:gradle-enterprise-gradle-plugin:3.12.2")
-        classpath("com.gradle:common-custom-user-data-gradle-plugin:1.7.2")
+        classpath("com.gradle:gradle-enterprise-gradle-plugin:3.12.4")
+        classpath("com.gradle:common-custom-user-data-gradle-plugin:1.9")
         classpath("androidx.build.gradle.gcpbuildcache:gcpbuildcache:1.0.0-alpha06")
     }
 }
@@ -353,13 +353,6 @@
 includeProject(":activity:activity-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
 includeProject(":activity:activity-lint", [BuildType.MAIN, BuildType.FLAN, BuildType.COMPOSE, BuildType.WEAR])
 includeProject(":activity:integration-tests:testapp", [BuildType.MAIN, BuildType.FLAN])
-includeProject(":ads:ads-identifier", [BuildType.MAIN])
-includeProject(":ads:ads-identifier-benchmark", [BuildType.MAIN])
-includeProject(":ads:ads-identifier-common", [BuildType.MAIN])
-includeProject(":ads:ads-identifier-provider", [BuildType.MAIN])
-includeProject(":ads:ads-identifier-provider:integration-tests:testapp", [BuildType.MAIN])
-includeProject(":ads:ads-identifier-testing", [BuildType.MAIN])
-includeProject(":ads:ads-identifier:integration-tests:testapp", [BuildType.MAIN])
 includeProject(":annotation:annotation")
 includeProject(":annotation:annotation-experimental")
 includeProject(":annotation:annotation-experimental-lint")
diff --git a/wear/watchface/watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceControlServiceTest.kt b/wear/watchface/watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceControlServiceTest.kt
index fb730b0..8efea62 100644
--- a/wear/watchface/watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceControlServiceTest.kt
+++ b/wear/watchface/watchface/src/androidTest/java/androidx/wear/watchface/test/WatchFaceControlServiceTest.kt
@@ -538,4 +538,15 @@
 
         assertThat(instance.userStyleSchema.mSchema).isEmpty()
     }
+
+    @Test
+    public fun createWatchFaceService_throwsOnInvalidClass() {
+        assertThat(WatchFaceControlService()
+            .createWatchFaceService(
+                ComponentName(
+                    ApplicationProvider.getApplicationContext(),
+                    WatchFaceControlServiceTest::class.java
+                )
+            )).isNull()
+    }
 }
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFace.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
index 3715ca5..c3c095e 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/WatchFace.kt
@@ -51,6 +51,7 @@
 import androidx.wear.watchface.complications.data.toApiComplicationData
 import androidx.wear.watchface.control.HeadlessWatchFaceImpl
 import androidx.wear.watchface.control.RemoteWatchFaceView
+import androidx.wear.watchface.control.WatchFaceControlService
 import androidx.wear.watchface.control.data.ComplicationRenderParams
 import androidx.wear.watchface.control.data.HeadlessWatchFaceInstanceParams
 import androidx.wear.watchface.control.data.WatchFaceRenderParams
@@ -178,6 +179,57 @@
             return pendingEditorDelegateCB!!
         }
 
+        @UiThread
+        internal fun createWatchFaceServiceOld(
+            componentName: ComponentName
+        ): WatchFaceService {
+            // Attempt to construct the class for the specified watchFaceName, failing if it either
+            // doesn't exist or isn't a [WatchFaceService].
+            val watchFaceServiceClass =
+                Class.forName(componentName.className)
+                    ?: throw IllegalArgumentException("Can't create ${componentName.className}")
+            if (!WatchFaceService::class.java.isAssignableFrom(watchFaceServiceClass)) {
+                throw IllegalArgumentException(
+                    "${componentName.className} is not a WatchFaceService"
+                )
+            } else {
+                return watchFaceServiceClass.getConstructor().newInstance() as WatchFaceService
+            }
+        }
+
+        @SuppressLint("NewApi")
+        @Suppress("DEPRECATION") // queryIntentServices
+        @UiThread
+        internal fun createWatchFaceService(
+            componentName: ComponentName,
+            context: Context
+        ): WatchFaceService {
+            // Resolve the WatchFaceControlService and construct WatchFaceService using its API
+            val services = context.packageManager.queryIntentServices(Intent(
+                WatchFaceControlService.ACTION_WATCHFACE_CONTROL_SERVICE).apply {
+                setPackage(context.packageName)
+            }, 0)
+
+            if (services.size != 1)
+                throw IllegalArgumentException(
+                    "WatchFaceControlService cannot be uniquely resolved (${services.size}) for " +
+                        context.packageName
+                )
+
+            val watchFaceControlServiceClass =
+                Class.forName(services[0].serviceInfo.name)
+                    ?: throw IllegalArgumentException(
+                        "Can't find ${services[0].serviceInfo.name}"
+                    )
+
+            val watchFaceControlService =
+                watchFaceControlServiceClass.getConstructor().newInstance()
+                    as WatchFaceControlService
+
+            return watchFaceControlService.createWatchFaceService(componentName)
+                ?: throw IllegalArgumentException("Can't create ${componentName.className}")
+        }
+
         /**
          * For use by on watch face editors.
          *
@@ -191,24 +243,18 @@
             params: HeadlessWatchFaceInstanceParams,
             context: Context
         ): EditorDelegate {
-            // Attempt to construct the class for the specified watchFaceName, failing if it either
-            // doesn't exist or isn't a [WatchFaceService].
-            val watchFaceServiceClass =
-                Class.forName(componentName.className)
-                    ?: throw IllegalArgumentException("Can't create ${componentName.className}")
-            if (!WatchFaceService::class.java.isAssignableFrom(WatchFaceService::class.java)) {
-                throw IllegalArgumentException(
-                    "${componentName.className} is not a WatchFaceService"
-                )
+            val watchFaceService = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+                createWatchFaceService(componentName, context)
             } else {
-                val watchFaceService =
-                    watchFaceServiceClass.getConstructor().newInstance() as WatchFaceService
-                watchFaceService.setContext(context)
-                val engine =
-                    watchFaceService.createHeadlessEngine() as WatchFaceService.EngineWrapper
-                val headlessWatchFaceImpl = engine.createHeadlessInstance(params)
-                return engine.deferredWatchFaceImpl.await().WFEditorDelegate(headlessWatchFaceImpl)
+                createWatchFaceServiceOld(componentName)
+            }.apply {
+                setContext(context)
             }
+
+            val engine =
+                watchFaceService.createHeadlessEngine() as WatchFaceService.EngineWrapper
+            val headlessWatchFaceImpl = engine.createHeadlessInstance(params)
+            return engine.deferredWatchFaceImpl.await().WFEditorDelegate(headlessWatchFaceImpl)
         }
     }
 
diff --git a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/WatchFaceControlService.kt b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/WatchFaceControlService.kt
index f0d28c5..d16421b 100644
--- a/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/WatchFaceControlService.kt
+++ b/wear/watchface/watchface/src/main/java/androidx/wear/watchface/control/WatchFaceControlService.kt
@@ -54,7 +54,6 @@
  *
  */
 @RequiresApi(27)
-@VisibleForTesting
 @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 public open class WatchFaceControlService : Service() {
     private var watchFaceInstanceServiceStub: IWatchFaceInstanceServiceStub? = null
@@ -79,7 +78,7 @@
     open fun createWatchFaceService(watchFaceName: ComponentName): WatchFaceService? {
         return try {
             val watchFaceServiceClass = Class.forName(watchFaceName.className) ?: return null
-            if (!WatchFaceService::class.java.isAssignableFrom(WatchFaceService::class.java)) {
+            if (!WatchFaceService::class.java.isAssignableFrom(watchFaceServiceClass)) {
                 return null
             }
             watchFaceServiceClass.getConstructor().newInstance() as WatchFaceService
diff --git a/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt b/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
index d6870d7..97ada96 100644
--- a/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
+++ b/wear/watchface/watchface/src/test/java/androidx/wear/watchface/WatchFaceServiceTest.kt
@@ -39,6 +39,8 @@
 import android.provider.Settings
 import android.support.wearable.complications.ComplicationData as WireComplicationData
 import android.support.wearable.complications.ComplicationText as WireComplicationText
+import android.content.IntentFilter
+import android.content.pm.ServiceInfo
 import android.support.wearable.watchface.Constants
 import android.support.wearable.watchface.IWatchFaceService
 import android.support.wearable.watchface.WatchFaceStyle
@@ -74,6 +76,7 @@
 import androidx.wear.watchface.control.IPendingInteractiveWatchFace
 import androidx.wear.watchface.control.IWatchfaceListener
 import androidx.wear.watchface.control.InteractiveInstanceManager
+import androidx.wear.watchface.control.WatchFaceControlService
 import androidx.wear.watchface.control.data.CrashInfoParcel
 import androidx.wear.watchface.control.data.HeadlessWatchFaceInstanceParams
 import androidx.wear.watchface.control.data.WallpaperInteractiveWatchFaceInstanceParams
@@ -6544,6 +6547,59 @@
         assertThat(HeadlessWatchFaceImpl.headlessInstances).isEmpty()
     }
 
+    @Config(minSdk = 30)
+    @SuppressLint("NewApi")
+    @Test
+    public fun createHeadlessSessionDelegate_customControlServiceIsUsed() {
+        val context = ApplicationProvider.getApplicationContext<Context>()
+        val componentName = ComponentName("non existing package", "class")
+        lateinit var delegate: WatchFace.EditorDelegate
+
+        val shadowPackageManager = shadowOf(context.packageManager)
+        val controlServiceComponent = ComponentName(
+            context, TestWatchFaceControlService::class.java
+        )
+        shadowPackageManager.addOrUpdateService(ServiceInfo().apply {
+            packageName = controlServiceComponent.packageName
+            name = controlServiceComponent.className
+        })
+        shadowPackageManager.addIntentFilterForService(
+            controlServiceComponent,
+            IntentFilter(WatchFaceControlService.ACTION_WATCHFACE_CONTROL_SERVICE)
+        )
+        // Remove default WatchFaceControlService
+        shadowPackageManager.removeService(
+            ComponentName(context, WatchFaceControlService::class.java)
+        )
+
+        // Allows us to programmatically control tasks.
+        TestNopCanvasWatchFaceService.handler = this.handler
+
+        CoroutineScope(handler.asCoroutineDispatcher().immediate).launch {
+            delegate =
+                WatchFace.createHeadlessSessionDelegate(
+                    componentName,
+                    HeadlessWatchFaceInstanceParams(
+                        componentName,
+                        DeviceConfig(false, false, 100, 200),
+                        100,
+                        100,
+                        null
+                    ),
+                    context
+                )
+        }
+
+        assertThat(delegate).isNotNull()
+
+        // Run all pending tasks.
+        while (pendingTasks.isNotEmpty()) {
+            pendingTasks.remove().runnable.run()
+        }
+
+        delegate.onDestroy()
+    }
+
     @Test
     public fun attachToExistingParameterlessEngine() {
         // Construct a parameterless engine.
@@ -6604,7 +6660,7 @@
                     ),
                     callback
                 )
-             )
+            )
 
         runBlocking {
             watchFaceImpl = engineWrapper.deferredWatchFaceImpl.awaitWithTimeout()
@@ -6699,3 +6755,10 @@
             override fun getSystemTimeZoneId() = ZoneId.of("UTC")
         }
 }
+
+@RequiresApi(27)
+class TestWatchFaceControlService : WatchFaceControlService() {
+    override fun createWatchFaceService(watchFaceName: ComponentName): WatchFaceService? {
+        return TestNopCanvasWatchFaceService()
+    }
+}