Merge "Create a Factory class for DefaultSurfaceProcessor" into androidx-main
diff --git a/appactions/interaction/interaction-service/api/current.txt b/appactions/interaction/interaction-service/api/current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/appactions/interaction/interaction-service/api/current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/appactions/interaction/interaction-service/api/public_plus_experimental_current.txt b/appactions/interaction/interaction-service/api/public_plus_experimental_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/appactions/interaction/interaction-service/api/public_plus_experimental_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/appactions/interaction/interaction-service/api/res-current.txt b/appactions/interaction/interaction-service/api/res-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/appactions/interaction/interaction-service/api/res-current.txt
diff --git a/appactions/interaction/interaction-service/api/restricted_current.txt b/appactions/interaction/interaction-service/api/restricted_current.txt
new file mode 100644
index 0000000..e6f50d0
--- /dev/null
+++ b/appactions/interaction/interaction-service/api/restricted_current.txt
@@ -0,0 +1 @@
+// Signature format: 4.0
diff --git a/appactions/interaction/interaction-service/build.gradle b/appactions/interaction/interaction-service/build.gradle
new file mode 100644
index 0000000..fa19659
--- /dev/null
+++ b/appactions/interaction/interaction-service/build.gradle
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 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.
+ */
+
+import androidx.build.LibraryType
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+}
+
+dependencies {
+}
+
+android {
+ namespace "androidx.appactions.interaction.service"
+}
+
+androidx {
+ name = "androidx.appactions.interaction:interaction-service"
+ type = LibraryType.PUBLISHED_LIBRARY
+ inceptionYear = "2023"
+ description = "Library for integrating with Google Assistant via GRPC binder channel."
+}
diff --git a/benchmark/integration-tests/baselineprofiles-consumer/build.gradle b/benchmark/integration-tests/baselineprofiles-consumer/build.gradle
new file mode 100644
index 0000000..d3e1e45
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-consumer/build.gradle
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.application")
+ id("kotlin-android")
+ id("androidx.baselineprofiles.consumer")
+ id("androidx.baselineprofiles.buildprovider")
+}
+
+android {
+ buildTypes {
+ release {
+ minifyEnabled true
+ shrinkResources true
+ proguardFiles getDefaultProguardFile("proguard-android-optimize.txt")
+ }
+ }
+ namespace "androidx.benchmark.integration.baselineprofiles.consumer"
+}
+
+dependencies {
+ implementation(libs.kotlinStdlib)
+ implementation(libs.constraintLayout)
+ baselineprofiles(project(":benchmark:integration-tests:baselineprofiles-producer"))
+}
+
+apply(from: "../baselineprofiles-test-utils/utils.gradle")
diff --git a/benchmark/integration-tests/baselineprofiles-consumer/src/main/AndroidManifest.xml b/benchmark/integration-tests/baselineprofiles-consumer/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ca9827a
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-consumer/src/main/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<!--
+ ~ 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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <application
+ android:allowBackup="false"
+ android:label="Jetpack Baselineprofiles Target"
+ android:supportsRtl="true"
+ android:theme="@style/Theme.AppCompat"
+ tools:ignore="MissingApplicationIcon">
+
+ <activity
+ android:name=".EmptyActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="androidx.benchmark.integration.baselineprofiles.consumer.EMPTY_ACTIVITY" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <profileable android:shell="true" />
+ </application>
+</manifest>
diff --git a/benchmark/integration-tests/baselineprofiles-consumer/src/main/expected-baseline-prof.txt b/benchmark/integration-tests/baselineprofiles-consumer/src/main/expected-baseline-prof.txt
new file mode 100644
index 0000000..205f8c9
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-consumer/src/main/expected-baseline-prof.txt
@@ -0,0 +1,172 @@
+HSPLandroidx/appcompat/widget/TintTypedArray;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;)V
+HSPLandroidx/appcompat/widget/TintTypedArray;->measure(Landroidx/constraintlayout/widget/ConstraintLayout$Measurer;Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Z)Z
+HSPLandroidx/appcompat/widget/TintTypedArray;->solveLinearSystem(Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;II)V
+HSPLandroidx/benchmark/integration/baselineprofiles/consumer/EmptyActivity;-><init>()V
+HSPLandroidx/benchmark/integration/baselineprofiles/consumer/EmptyActivity;->onCreate(Landroid/os/Bundle;)V
+HSPLandroidx/collection/ArrayMap$1;-><init>()V
+HSPLandroidx/constraintlayout/solver/ArrayLinkedVariables;-><init>(Landroidx/constraintlayout/solver/ArrayRow;Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;-><init>()V
+HSPLandroidx/constraintlayout/solver/ArrayRow;-><init>(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->addError(Landroidx/constraintlayout/solver/LinearSystem;I)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->createRowGreaterThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->createRowLowerThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->pivot(Landroidx/constraintlayout/solver/SolverVariable;)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->reset()V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->updateFromFinalVariable(Landroidx/constraintlayout/solver/SolverVariable;Z)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->updateFromRow(Landroidx/constraintlayout/solver/ArrayRow;Z)V
+HSPLandroidx/constraintlayout/solver/LinearSystem$ValuesRow;-><init>(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;-><init>()V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->acquireSolverVariable$enumunboxing$(I)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addCentering(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;IFLandroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addConstraint(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addEquality(Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addEquality(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addGreaterThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addLowerThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addRow(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createErrorVariable(I)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createObjectVariable(Ljava/lang/Object;)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createRow()Landroidx/constraintlayout/solver/ArrayRow;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createSlackVariable()Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->getObjectVariableValue(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;)I
+HSPLandroidx/constraintlayout/solver/LinearSystem;->increaseTableSize()V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->optimize(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->releaseRows()V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->reset()V
+HSPLandroidx/constraintlayout/solver/Pools$SimplePool;-><init>()V
+HSPLandroidx/constraintlayout/solver/Pools$SimplePool;->acquire()Ljava/lang/Object;
+HSPLandroidx/constraintlayout/solver/Pools$SimplePool;->release(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow$GoalVariableAccessor;-><init>(Landroidx/constraintlayout/solver/PriorityGoalRow;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;-><init>(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->addToGoal(Landroidx/constraintlayout/solver/SolverVariable;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->getPivotCandidate([Z)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->removeGoal(Landroidx/constraintlayout/solver/SolverVariable;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->updateFromRow(Landroidx/constraintlayout/solver/ArrayRow;Z)V
+HSPLandroidx/constraintlayout/solver/SolverVariable$Type$EnumUnboxingSharedUtility;-><clinit>()V
+HSPLandroidx/constraintlayout/solver/SolverVariable$Type$EnumUnboxingSharedUtility;->ordinal(I)I
+HSPLandroidx/constraintlayout/solver/SolverVariable;-><init>(I)V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->addToRow(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->removeFromRow(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->reset()V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->updateReferencesWithNewDefinition(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;-><init>(Landroidx/constraintlayout/solver/ArrayRow;Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->add(Landroidx/constraintlayout/solver/SolverVariable;FZ)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->addToHashMap(Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->addVariable(ILandroidx/constraintlayout/solver/SolverVariable;F)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->clear()V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->divideByAmount(F)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->get(Landroidx/constraintlayout/solver/SolverVariable;)F
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->getCurrentSize()I
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->getVariable(I)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->getVariableValue(I)F
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->indexOf(Landroidx/constraintlayout/solver/SolverVariable;)I
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->invert()V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->put(Landroidx/constraintlayout/solver/SolverVariable;F)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->remove(Landroidx/constraintlayout/solver/SolverVariable;Z)F
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->use(Landroidx/constraintlayout/solver/ArrayRow;Z)F
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;-><clinit>()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;-><init>(ILjava/lang/String;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->connect(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;II)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->getMargin()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->isConnected()Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->reset()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->resetSolverVariable()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;-><init>()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->addToSolver(Landroidx/constraintlayout/solver/LinearSystem;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->applyConstraints$enumunboxing$(Landroidx/constraintlayout/solver/LinearSystem;ZZZZLandroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;IZLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;IIIIFZZZZIIIIFZ)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->createObjectVariables(Landroidx/constraintlayout/solver/LinearSystem;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getAnchor(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;)Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getDimensionBehaviour$enumunboxing$(I)I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getHeight()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getWidth()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getX()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getY()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->immediateConnect(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;II)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->isChainHead(I)Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->isInHorizontalChain()Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->isInVerticalChain()Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->reset()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->resetSolverVariables(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setHeight(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setHorizontalDimensionBehaviour$enumunboxing$(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setVerticalDimensionBehaviour$enumunboxing$(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setWidth(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->updateFromSolver(Landroidx/constraintlayout/solver/LinearSystem;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;-><init>()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;->addChildrenToSolver(Landroidx/constraintlayout/solver/LinearSystem;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;->layout()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;->resetSolverVariables(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/BasicMeasure$Measure;-><init>()V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/DependencyGraph;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/DependencyNode;-><init>(Landroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/DimensionDependency;-><init>(Landroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/HorizontalWidgetRun;-><clinit>()V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/HorizontalWidgetRun;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/VerticalWidgetRun;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams$Table;-><clinit>()V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;->resolveLayoutDirection(I)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;->validate()V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;-><init>(Landroidx/constraintlayout/widget/ConstraintLayout;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;->measure(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/solver/widgets/analyzer/BasicMeasure$Measure;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->addView(Landroid/view/View;ILandroid/view/ViewGroup$LayoutParams;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->applyConstraintsFromLayoutParams(ZLandroid/view/View;Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;Landroid/util/SparseArray;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->checkLayoutParams(Landroid/view/ViewGroup$LayoutParams;)Z
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->dispatchDraw(Landroid/graphics/Canvas;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->generateLayoutParams(Landroid/util/AttributeSet;)Landroid/view/ViewGroup$LayoutParams;
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->getPaddingWidth()I
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->getViewWidget(Landroid/view/View;)Landroidx/constraintlayout/solver/widgets/ConstraintWidget;
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->isRtl()Z
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->onLayout(ZIIII)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->onMeasure(II)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->onViewAdded(Landroid/view/View;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->requestLayout()V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->updateHierarchy()Z
+HSPLandroidx/constraintlayout/widget/R$styleable;-><clinit>()V
+HSPLandroidx/core/app/CoreComponentFactory;-><init>()V
+HSPLandroidx/core/app/CoreComponentFactory;->instantiateActivity(Ljava/lang/ClassLoader;Ljava/lang/String;Landroid/content/Intent;)Landroid/app/Activity;
+HSPLandroidx/core/app/CoreComponentFactory;->instantiateApplication(Ljava/lang/ClassLoader;Ljava/lang/String;)Landroid/app/Application;
+HSPLandroidx/core/util/ObjectsCompat;-><clinit>()V
+Landroidx/appcompat/widget/TintTypedArray;
+Landroidx/benchmark/integration/baselineprofiles/consumer/EmptyActivity;
+Landroidx/collection/ArrayMap$1;
+Landroidx/constraintlayout/solver/ArrayLinkedVariables;
+Landroidx/constraintlayout/solver/ArrayRow$ArrayRowVariables;
+Landroidx/constraintlayout/solver/ArrayRow;
+Landroidx/constraintlayout/solver/LinearSystem$ValuesRow;
+Landroidx/constraintlayout/solver/LinearSystem;
+Landroidx/constraintlayout/solver/Pools$SimplePool;
+Landroidx/constraintlayout/solver/PriorityGoalRow$GoalVariableAccessor;
+Landroidx/constraintlayout/solver/PriorityGoalRow;
+Landroidx/constraintlayout/solver/SolverVariable$Type$EnumUnboxingSharedUtility;
+Landroidx/constraintlayout/solver/SolverVariable;
+Landroidx/constraintlayout/solver/SolverVariableValues;
+Landroidx/constraintlayout/solver/widgets/Barrier;
+Landroidx/constraintlayout/solver/widgets/ChainHead;
+Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;
+Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;
+Landroidx/constraintlayout/solver/widgets/ConstraintWidget;
+Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;
+Landroidx/constraintlayout/solver/widgets/Guideline;
+Landroidx/constraintlayout/solver/widgets/Helper;
+Landroidx/constraintlayout/solver/widgets/HelperWidget;
+Landroidx/constraintlayout/solver/widgets/analyzer/BasicMeasure$Measure;
+Landroidx/constraintlayout/solver/widgets/analyzer/Dependency;
+Landroidx/constraintlayout/solver/widgets/analyzer/DependencyGraph;
+Landroidx/constraintlayout/solver/widgets/analyzer/DependencyNode;
+Landroidx/constraintlayout/solver/widgets/analyzer/DimensionDependency;
+Landroidx/constraintlayout/solver/widgets/analyzer/HorizontalWidgetRun;
+Landroidx/constraintlayout/solver/widgets/analyzer/VerticalWidgetRun;
+Landroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;
+Landroidx/constraintlayout/widget/ConstraintHelper;
+Landroidx/constraintlayout/widget/ConstraintLayout$LayoutParams$Table;
+Landroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;
+Landroidx/constraintlayout/widget/ConstraintLayout$Measurer;
+Landroidx/constraintlayout/widget/ConstraintLayout;
+Landroidx/constraintlayout/widget/Guideline;
+Landroidx/constraintlayout/widget/R$styleable;
+Landroidx/core/app/CoreComponentFactory;
+Landroidx/core/util/ObjectsCompat;
\ No newline at end of file
diff --git a/benchmark/integration-tests/baselineprofiles-consumer/src/main/java/androidx/benchmark/integration/baselineprofiles/consumer/EmptyActivity.kt b/benchmark/integration-tests/baselineprofiles-consumer/src/main/java/androidx/benchmark/integration/baselineprofiles/consumer/EmptyActivity.kt
new file mode 100644
index 0000000..9a1b40b
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-consumer/src/main/java/androidx/benchmark/integration/baselineprofiles/consumer/EmptyActivity.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.benchmark.integration.baselineprofiles.consumer
+
+import android.app.Activity
+import android.os.Bundle
+import android.widget.TextView
+
+class EmptyActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ findViewById<TextView>(R.id.txtNotice).setText(R.string.app_notice)
+ }
+}
diff --git a/benchmark/integration-tests/baselineprofiles-consumer/src/main/res/layout/activity_main.xml b/benchmark/integration-tests/baselineprofiles-consumer/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..7739482
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-consumer/src/main/res/layout/activity_main.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ 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.
+-->
+
+<androidx.constraintlayout.widget.ConstraintLayout 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">
+
+ <TextView
+ android:id="@+id/txtNotice"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:text="Preview Some Text" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/benchmark/integration-tests/baselineprofiles-consumer/src/main/res/values/donottranslate-strings.xml b/benchmark/integration-tests/baselineprofiles-consumer/src/main/res/values/donottranslate-strings.xml
new file mode 100644
index 0000000..c880dc5
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-consumer/src/main/res/values/donottranslate-strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ 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.
+ -->
+
+<resources>
+ <string name="app_notice">Baseline Profiles Integration Test App.</string>
+</resources>
diff --git a/benchmark/integration-tests/baselineprofiles-flavors-consumer/build.gradle b/benchmark/integration-tests/baselineprofiles-flavors-consumer/build.gradle
new file mode 100644
index 0000000..8ae2e3f
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-flavors-consumer/build.gradle
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.application")
+ id("kotlin-android")
+ id("androidx.baselineprofiles.buildprovider")
+ id("androidx.baselineprofiles.consumer")
+}
+
+android {
+ buildTypes {
+ release {
+ minifyEnabled true
+ shrinkResources true
+ proguardFiles getDefaultProguardFile("proguard-android-optimize.txt")
+ }
+ }
+ productFlavors {
+ flavorDimensions = ["version"]
+ free {
+ dimension "version"
+ applicationIdSuffix ".free"
+ versionNameSuffix "-free"
+ }
+ paid {
+ dimension "version"
+ applicationIdSuffix ".paid"
+ versionNameSuffix "-paid"
+ }
+ }
+ namespace "androidx.benchmark.integration.baselineprofiles.flavors.consumer"
+}
+
+dependencies {
+ implementation(libs.kotlinStdlib)
+ implementation(libs.constraintLayout)
+
+ baselineprofiles(project(":benchmark:integration-tests:baselineprofiles-flavors-producer"))
+}
+
+baselineProfilesProfileConsumer {
+ buildTypeName = "release"
+}
+
+apply(from: "../baselineprofiles-test-utils/utils.gradle")
diff --git a/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/free/AndroidManifest.xml b/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/free/AndroidManifest.xml
new file mode 100644
index 0000000..fb4bcd8
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/free/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<!--
+ ~ 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.
+ -->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:node="merge">
+
+ <application
+ android:allowBackup="false"
+ android:label="Jetpack Baselineprofiles Target"
+ android:supportsRtl="true"
+ android:theme="@style/Theme.AppCompat"
+ tools:ignore="MissingApplicationIcon">
+
+ <activity
+ android:name=".EmptyActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="androidx.benchmark.integration.baselineprofiles.flavors.consumer.free.EMPTY_ACTIVITY" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <profileable android:shell="true" />
+ </application>
+</manifest>
diff --git a/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/main/AndroidManifest.xml b/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..118910a
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ 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.
+ -->
+<manifest
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:node="merge">
+
+ <application />
+</manifest>
diff --git a/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/main/expected-baseline-prof.txt b/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/main/expected-baseline-prof.txt
new file mode 100644
index 0000000..49756602
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/main/expected-baseline-prof.txt
@@ -0,0 +1,172 @@
+HSPLandroidx/appcompat/widget/TintTypedArray;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;)V
+HSPLandroidx/appcompat/widget/TintTypedArray;->measure(Landroidx/constraintlayout/widget/ConstraintLayout$Measurer;Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Z)Z
+HSPLandroidx/appcompat/widget/TintTypedArray;->solveLinearSystem(Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;II)V
+HSPLandroidx/benchmark/integration/baselineprofiles/flavors/consumer/EmptyActivity;-><init>()V
+HSPLandroidx/benchmark/integration/baselineprofiles/flavors/consumer/EmptyActivity;->onCreate(Landroid/os/Bundle;)V
+HSPLandroidx/collection/ArrayMap$1;-><init>()V
+HSPLandroidx/constraintlayout/solver/ArrayLinkedVariables;-><init>(Landroidx/constraintlayout/solver/ArrayRow;Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;-><init>()V
+HSPLandroidx/constraintlayout/solver/ArrayRow;-><init>(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->addError(Landroidx/constraintlayout/solver/LinearSystem;I)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->createRowGreaterThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->createRowLowerThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->pivot(Landroidx/constraintlayout/solver/SolverVariable;)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->reset()V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->updateFromFinalVariable(Landroidx/constraintlayout/solver/SolverVariable;Z)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->updateFromRow(Landroidx/constraintlayout/solver/ArrayRow;Z)V
+HSPLandroidx/constraintlayout/solver/LinearSystem$ValuesRow;-><init>(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;-><init>()V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->acquireSolverVariable$enumunboxing$(I)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addCentering(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;IFLandroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addConstraint(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addEquality(Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addEquality(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addGreaterThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addLowerThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addRow(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createErrorVariable(I)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createObjectVariable(Ljava/lang/Object;)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createRow()Landroidx/constraintlayout/solver/ArrayRow;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createSlackVariable()Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->getObjectVariableValue(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;)I
+HSPLandroidx/constraintlayout/solver/LinearSystem;->increaseTableSize()V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->optimize(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->releaseRows()V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->reset()V
+HSPLandroidx/constraintlayout/solver/Pools$SimplePool;-><init>()V
+HSPLandroidx/constraintlayout/solver/Pools$SimplePool;->acquire()Ljava/lang/Object;
+HSPLandroidx/constraintlayout/solver/Pools$SimplePool;->release(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow$GoalVariableAccessor;-><init>(Landroidx/constraintlayout/solver/PriorityGoalRow;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;-><init>(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->addToGoal(Landroidx/constraintlayout/solver/SolverVariable;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->getPivotCandidate([Z)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->removeGoal(Landroidx/constraintlayout/solver/SolverVariable;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->updateFromRow(Landroidx/constraintlayout/solver/ArrayRow;Z)V
+HSPLandroidx/constraintlayout/solver/SolverVariable$Type$EnumUnboxingSharedUtility;-><clinit>()V
+HSPLandroidx/constraintlayout/solver/SolverVariable$Type$EnumUnboxingSharedUtility;->ordinal(I)I
+HSPLandroidx/constraintlayout/solver/SolverVariable;-><init>(I)V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->addToRow(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->removeFromRow(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->reset()V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->updateReferencesWithNewDefinition(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;-><init>(Landroidx/constraintlayout/solver/ArrayRow;Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->add(Landroidx/constraintlayout/solver/SolverVariable;FZ)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->addToHashMap(Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->addVariable(ILandroidx/constraintlayout/solver/SolverVariable;F)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->clear()V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->divideByAmount(F)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->get(Landroidx/constraintlayout/solver/SolverVariable;)F
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->getCurrentSize()I
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->getVariable(I)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->getVariableValue(I)F
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->indexOf(Landroidx/constraintlayout/solver/SolverVariable;)I
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->invert()V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->put(Landroidx/constraintlayout/solver/SolverVariable;F)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->remove(Landroidx/constraintlayout/solver/SolverVariable;Z)F
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->use(Landroidx/constraintlayout/solver/ArrayRow;Z)F
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;-><clinit>()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;-><init>(ILjava/lang/String;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->connect(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;II)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->getMargin()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->isConnected()Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->reset()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->resetSolverVariable()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;-><init>()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->addToSolver(Landroidx/constraintlayout/solver/LinearSystem;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->applyConstraints$enumunboxing$(Landroidx/constraintlayout/solver/LinearSystem;ZZZZLandroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;IZLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;IIIIFZZZZIIIIFZ)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->createObjectVariables(Landroidx/constraintlayout/solver/LinearSystem;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getAnchor(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;)Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getDimensionBehaviour$enumunboxing$(I)I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getHeight()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getWidth()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getX()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getY()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->immediateConnect(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;II)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->isChainHead(I)Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->isInHorizontalChain()Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->isInVerticalChain()Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->reset()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->resetSolverVariables(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setHeight(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setHorizontalDimensionBehaviour$enumunboxing$(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setVerticalDimensionBehaviour$enumunboxing$(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setWidth(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->updateFromSolver(Landroidx/constraintlayout/solver/LinearSystem;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;-><init>()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;->addChildrenToSolver(Landroidx/constraintlayout/solver/LinearSystem;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;->layout()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;->resetSolverVariables(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/BasicMeasure$Measure;-><init>()V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/DependencyGraph;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/DependencyNode;-><init>(Landroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/DimensionDependency;-><init>(Landroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/HorizontalWidgetRun;-><clinit>()V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/HorizontalWidgetRun;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/VerticalWidgetRun;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams$Table;-><clinit>()V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;->resolveLayoutDirection(I)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;->validate()V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;-><init>(Landroidx/constraintlayout/widget/ConstraintLayout;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;->measure(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/solver/widgets/analyzer/BasicMeasure$Measure;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->addView(Landroid/view/View;ILandroid/view/ViewGroup$LayoutParams;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->applyConstraintsFromLayoutParams(ZLandroid/view/View;Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;Landroid/util/SparseArray;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->checkLayoutParams(Landroid/view/ViewGroup$LayoutParams;)Z
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->dispatchDraw(Landroid/graphics/Canvas;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->generateLayoutParams(Landroid/util/AttributeSet;)Landroid/view/ViewGroup$LayoutParams;
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->getPaddingWidth()I
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->getViewWidget(Landroid/view/View;)Landroidx/constraintlayout/solver/widgets/ConstraintWidget;
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->isRtl()Z
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->onLayout(ZIIII)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->onMeasure(II)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->onViewAdded(Landroid/view/View;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->requestLayout()V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->updateHierarchy()Z
+HSPLandroidx/constraintlayout/widget/R$styleable;-><clinit>()V
+HSPLandroidx/core/app/CoreComponentFactory;-><init>()V
+HSPLandroidx/core/app/CoreComponentFactory;->instantiateActivity(Ljava/lang/ClassLoader;Ljava/lang/String;Landroid/content/Intent;)Landroid/app/Activity;
+HSPLandroidx/core/app/CoreComponentFactory;->instantiateApplication(Ljava/lang/ClassLoader;Ljava/lang/String;)Landroid/app/Application;
+HSPLandroidx/core/util/ObjectsCompat;-><clinit>()V
+Landroidx/appcompat/widget/TintTypedArray;
+Landroidx/benchmark/integration/baselineprofiles/flavors/consumer/EmptyActivity;
+Landroidx/collection/ArrayMap$1;
+Landroidx/constraintlayout/solver/ArrayLinkedVariables;
+Landroidx/constraintlayout/solver/ArrayRow$ArrayRowVariables;
+Landroidx/constraintlayout/solver/ArrayRow;
+Landroidx/constraintlayout/solver/LinearSystem$ValuesRow;
+Landroidx/constraintlayout/solver/LinearSystem;
+Landroidx/constraintlayout/solver/Pools$SimplePool;
+Landroidx/constraintlayout/solver/PriorityGoalRow$GoalVariableAccessor;
+Landroidx/constraintlayout/solver/PriorityGoalRow;
+Landroidx/constraintlayout/solver/SolverVariable$Type$EnumUnboxingSharedUtility;
+Landroidx/constraintlayout/solver/SolverVariable;
+Landroidx/constraintlayout/solver/SolverVariableValues;
+Landroidx/constraintlayout/solver/widgets/Barrier;
+Landroidx/constraintlayout/solver/widgets/ChainHead;
+Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;
+Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;
+Landroidx/constraintlayout/solver/widgets/ConstraintWidget;
+Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;
+Landroidx/constraintlayout/solver/widgets/Guideline;
+Landroidx/constraintlayout/solver/widgets/Helper;
+Landroidx/constraintlayout/solver/widgets/HelperWidget;
+Landroidx/constraintlayout/solver/widgets/analyzer/BasicMeasure$Measure;
+Landroidx/constraintlayout/solver/widgets/analyzer/Dependency;
+Landroidx/constraintlayout/solver/widgets/analyzer/DependencyGraph;
+Landroidx/constraintlayout/solver/widgets/analyzer/DependencyNode;
+Landroidx/constraintlayout/solver/widgets/analyzer/DimensionDependency;
+Landroidx/constraintlayout/solver/widgets/analyzer/HorizontalWidgetRun;
+Landroidx/constraintlayout/solver/widgets/analyzer/VerticalWidgetRun;
+Landroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;
+Landroidx/constraintlayout/widget/ConstraintHelper;
+Landroidx/constraintlayout/widget/ConstraintLayout$LayoutParams$Table;
+Landroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;
+Landroidx/constraintlayout/widget/ConstraintLayout$Measurer;
+Landroidx/constraintlayout/widget/ConstraintLayout;
+Landroidx/constraintlayout/widget/Guideline;
+Landroidx/constraintlayout/widget/R$styleable;
+Landroidx/core/app/CoreComponentFactory;
+Landroidx/core/util/ObjectsCompat;
\ No newline at end of file
diff --git a/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/main/java/androidx/benchmark/integration/baselineprofiles/flavors/consumer/EmptyActivity.kt b/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/main/java/androidx/benchmark/integration/baselineprofiles/flavors/consumer/EmptyActivity.kt
new file mode 100644
index 0000000..5119859
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/main/java/androidx/benchmark/integration/baselineprofiles/flavors/consumer/EmptyActivity.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.benchmark.integration.baselineprofiles.flavors.consumer
+
+import android.app.Activity
+import android.os.Bundle
+import android.widget.TextView
+
+class EmptyActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ findViewById<TextView>(R.id.txtNotice).setText(R.string.app_notice)
+ }
+}
diff --git a/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/main/res/layout/activity_main.xml b/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..7739482
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/main/res/layout/activity_main.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ 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.
+-->
+
+<androidx.constraintlayout.widget.ConstraintLayout 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">
+
+ <TextView
+ android:id="@+id/txtNotice"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:text="Preview Some Text" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/main/res/values/donottranslate-strings.xml b/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/main/res/values/donottranslate-strings.xml
new file mode 100644
index 0000000..c880dc5
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/main/res/values/donottranslate-strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ 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.
+ -->
+
+<resources>
+ <string name="app_notice">Baseline Profiles Integration Test App.</string>
+</resources>
diff --git a/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/paid/AndroidManifest.xml b/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/paid/AndroidManifest.xml
new file mode 100644
index 0000000..514b52c
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-flavors-consumer/src/paid/AndroidManifest.xml
@@ -0,0 +1,43 @@
+<!--
+ ~ 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.
+ -->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:node="merge">
+
+ <application
+ android:allowBackup="false"
+ android:label="Jetpack Baselineprofiles Target"
+ android:supportsRtl="true"
+ android:theme="@style/Theme.AppCompat"
+ tools:ignore="MissingApplicationIcon">
+
+ <activity
+ android:name=".EmptyActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="androidx.benchmark.integration.baselineprofiles.flavors.consumer.paid.EMPTY_ACTIVITY" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <profileable android:shell="true" />
+ </application>
+</manifest>
diff --git a/benchmark/integration-tests/baselineprofiles-flavors-producer/build.gradle b/benchmark/integration-tests/baselineprofiles-flavors-producer/build.gradle
new file mode 100644
index 0000000..d3e6cdb
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-flavors-producer/build.gradle
@@ -0,0 +1,68 @@
+import com.android.build.api.dsl.ManagedVirtualDevice
+
+/*
+ * 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.
+ */
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.test")
+ id("kotlin-android")
+ id("androidx.baselineprofiles.producer")
+}
+
+android {
+ defaultConfig {
+ minSdkVersion 23
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ testOptions.managedDevices.devices {
+ pixel6Api31(ManagedVirtualDevice) {
+ device = "Pixel 6"
+ apiLevel = 31
+ systemImageSource = "aosp"
+ }
+ }
+ buildTypes {
+ release { }
+ }
+ productFlavors {
+ flavorDimensions = ["version"]
+ free { dimension "version" }
+ paid { dimension "version" }
+ }
+ targetProjectPath = ":benchmark:integration-tests:baselineprofiles-flavors-consumer"
+ namespace "androidx.benchmark.integration.baselineprofiles.flavors.producer"
+}
+
+dependencies {
+ implementation(project(":benchmark:benchmark-junit4"))
+ implementation(project(":benchmark:benchmark-macro-junit4"))
+ implementation(libs.testRules)
+ implementation(libs.testExtJunit)
+ implementation(libs.testCore)
+ implementation(libs.testRunner)
+ implementation(libs.testUiautomator)
+ implementation(libs.testExtTruth)
+}
+
+baselineProfilesProfileProducer {
+ managedDevices += "pixel6Api31"
+ useConnectedDevices = false
+}
+
+androidx {
+ disableDeviceTests = true
+}
diff --git a/benchmark/integration-tests/baselineprofiles-flavors-producer/src/free/AndroidManifest.xml b/benchmark/integration-tests/baselineprofiles-flavors-producer/src/free/AndroidManifest.xml
new file mode 100644
index 0000000..bae036b
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-flavors-producer/src/free/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?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.
+ -->
+<manifest />
diff --git a/benchmark/integration-tests/baselineprofiles-flavors-producer/src/free/java/androidx/benchmark/integration/baselineprofiles/flavors/producer/BaselineProfileTest.kt b/benchmark/integration-tests/baselineprofiles-flavors-producer/src/free/java/androidx/benchmark/integration/baselineprofiles/flavors/producer/BaselineProfileTest.kt
new file mode 100644
index 0000000..1fd878f
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-flavors-producer/src/free/java/androidx/benchmark/integration/baselineprofiles/flavors/producer/BaselineProfileTest.kt
@@ -0,0 +1,56 @@
+/*
+ * 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.benchmark.integration.baselineprofiles.flavors.producer
+
+import android.content.Intent
+import android.os.Build
+import androidx.benchmark.DeviceInfo
+import androidx.benchmark.macro.junit4.BaselineProfileRule
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import org.junit.Assume.assumeTrue
+import org.junit.Rule
+import org.junit.Test
+
+@LargeTest
+@SdkSuppress(minSdkVersion = 29)
+class BaselineProfileTest {
+
+ @get:Rule
+ val baselineRule = BaselineProfileRule()
+
+ @Test
+ fun startupBaselineProfile() {
+ assumeTrue(DeviceInfo.isRooted || Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
+
+ // Collects the baseline profile
+ baselineRule.collectBaselineProfile(
+ packageName = PACKAGE_NAME,
+ profileBlock = {
+ startActivityAndWait(Intent(ACTION))
+ device.waitForIdle()
+ }
+ )
+ }
+
+ companion object {
+ private const val PACKAGE_NAME =
+ "androidx.benchmark.integration.baselineprofiles.flavors.consumer.free"
+ private const val ACTION =
+ "androidx.benchmark.integration.baselineprofiles.flavors.consumer.free.EMPTY_ACTIVITY"
+ }
+}
diff --git a/benchmark/integration-tests/baselineprofiles-flavors-producer/src/main/AndroidManifest.xml b/benchmark/integration-tests/baselineprofiles-flavors-producer/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d4c1970
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-flavors-producer/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?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.
+ -->
+<manifest />
diff --git a/benchmark/integration-tests/baselineprofiles-flavors-producer/src/paid/AndroidManifest.xml b/benchmark/integration-tests/baselineprofiles-flavors-producer/src/paid/AndroidManifest.xml
new file mode 100644
index 0000000..bae036b
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-flavors-producer/src/paid/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?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.
+ -->
+<manifest />
diff --git a/benchmark/integration-tests/baselineprofiles-flavors-producer/src/paid/java/androidx/benchmark/integration/baselineprofiles/flavors/producer/BaselineProfileTest.kt b/benchmark/integration-tests/baselineprofiles-flavors-producer/src/paid/java/androidx/benchmark/integration/baselineprofiles/flavors/producer/BaselineProfileTest.kt
new file mode 100644
index 0000000..6a96947
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-flavors-producer/src/paid/java/androidx/benchmark/integration/baselineprofiles/flavors/producer/BaselineProfileTest.kt
@@ -0,0 +1,56 @@
+/*
+ * 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.benchmark.integration.baselineprofiles.flavors.producer
+
+import android.content.Intent
+import android.os.Build
+import androidx.benchmark.DeviceInfo
+import androidx.benchmark.macro.junit4.BaselineProfileRule
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import org.junit.Assume.assumeTrue
+import org.junit.Rule
+import org.junit.Test
+
+@LargeTest
+@SdkSuppress(minSdkVersion = 29)
+class BaselineProfileTest {
+
+ @get:Rule
+ val baselineRule = BaselineProfileRule()
+
+ @Test
+ fun startupBaselineProfile() {
+ assumeTrue(DeviceInfo.isRooted || Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
+
+ // Collects the baseline profile
+ baselineRule.collectBaselineProfile(
+ packageName = PACKAGE_NAME,
+ profileBlock = {
+ startActivityAndWait(Intent(ACTION))
+ device.waitForIdle()
+ }
+ )
+ }
+
+ companion object {
+ private const val PACKAGE_NAME =
+ "androidx.benchmark.integration.baselineprofiles.flavors.consumer.paid"
+ private const val ACTION =
+ "androidx.benchmark.integration.baselineprofiles.flavors.consumer.paid.EMPTY_ACTIVITY"
+ }
+}
diff --git a/benchmark/integration-tests/baselineprofiles-library-build-provider/build.gradle b/benchmark/integration-tests/baselineprofiles-library-build-provider/build.gradle
new file mode 100644
index 0000000..9c8061f
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-library-build-provider/build.gradle
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.application")
+ id("kotlin-android")
+ id("androidx.baselineprofiles.buildprovider")
+}
+
+android {
+ buildTypes {
+ release {
+ minifyEnabled true
+ shrinkResources true
+ proguardFiles getDefaultProguardFile("proguard-android-optimize.txt")
+ }
+ }
+ namespace "androidx.benchmark.integration.baselineprofiles.library.buildprovider"
+}
+
+dependencies {
+ implementation(libs.kotlinStdlib)
+ implementation(libs.constraintLayout)
+}
diff --git a/benchmark/integration-tests/baselineprofiles-library-build-provider/src/main/AndroidManifest.xml b/benchmark/integration-tests/baselineprofiles-library-build-provider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..fbb0bc7
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-library-build-provider/src/main/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<!--
+ ~ 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.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <application
+ android:allowBackup="false"
+ android:label="Jetpack Baselineprofiles Target"
+ android:supportsRtl="true"
+ android:theme="@style/Theme.AppCompat"
+ tools:ignore="MissingApplicationIcon">
+
+ <activity
+ android:name=".EmptyActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="androidx.benchmark.integration.baselineprofiles.EMPTY_ACTIVITY" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <profileable android:shell="true" />
+ </application>
+</manifest>
diff --git a/benchmark/integration-tests/baselineprofiles-library-build-provider/src/main/java/androidx/benchmark/integration/baselineprofiles/library/buildprovider/EmptyActivity.kt b/benchmark/integration-tests/baselineprofiles-library-build-provider/src/main/java/androidx/benchmark/integration/baselineprofiles/library/buildprovider/EmptyActivity.kt
new file mode 100644
index 0000000..64b8ed7
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-library-build-provider/src/main/java/androidx/benchmark/integration/baselineprofiles/library/buildprovider/EmptyActivity.kt
@@ -0,0 +1,29 @@
+/*
+ * 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.benchmark.integration.baselineprofiles.library.buildprovider
+
+import android.app.Activity
+import android.os.Bundle
+import android.widget.TextView
+
+class EmptyActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+ findViewById<TextView>(R.id.txtNotice).setText(R.string.app_notice)
+ }
+}
diff --git a/benchmark/integration-tests/baselineprofiles-library-build-provider/src/main/res/layout/activity_main.xml b/benchmark/integration-tests/baselineprofiles-library-build-provider/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..7739482
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-library-build-provider/src/main/res/layout/activity_main.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ 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.
+-->
+
+<androidx.constraintlayout.widget.ConstraintLayout 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">
+
+ <TextView
+ android:id="@+id/txtNotice"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:text="Preview Some Text" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/benchmark/integration-tests/baselineprofiles-library-build-provider/src/main/res/values/donottranslate-strings.xml b/benchmark/integration-tests/baselineprofiles-library-build-provider/src/main/res/values/donottranslate-strings.xml
new file mode 100644
index 0000000..c880dc5
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-library-build-provider/src/main/res/values/donottranslate-strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ 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.
+ -->
+
+<resources>
+ <string name="app_notice">Baseline Profiles Integration Test App.</string>
+</resources>
diff --git a/benchmark/integration-tests/baselineprofiles-library-consumer/build.gradle b/benchmark/integration-tests/baselineprofiles-library-consumer/build.gradle
new file mode 100644
index 0000000..e314c41
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-library-consumer/build.gradle
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.library")
+ id("kotlin-android")
+ id("androidx.baselineprofiles.consumer")
+}
+
+android {
+ namespace "androidx.benchmark.integration.baselineprofiles.library.consumer"
+}
+
+dependencies {
+ baselineprofiles(project(":benchmark:integration-tests:baselineprofiles-library-producer"))
+}
+
+dependencies {
+ implementation(libs.kotlinStdlib)
+}
+
+apply(from: "../baselineprofiles-test-utils/utils.gradle")
diff --git a/benchmark/integration-tests/baselineprofiles-library-consumer/src/main/AndroidManifest.xml b/benchmark/integration-tests/baselineprofiles-library-consumer/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..7c52910
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-library-consumer/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<!--
+ ~ 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.
+ -->
+<manifest />
diff --git a/benchmark/integration-tests/baselineprofiles-library-consumer/src/main/expected-baseline-prof.txt b/benchmark/integration-tests/baselineprofiles-library-consumer/src/main/expected-baseline-prof.txt
new file mode 100644
index 0000000..29e1de4
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-library-consumer/src/main/expected-baseline-prof.txt
@@ -0,0 +1,172 @@
+HSPLandroidx/appcompat/widget/TintTypedArray;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;)V
+HSPLandroidx/appcompat/widget/TintTypedArray;->measure(Landroidx/constraintlayout/widget/ConstraintLayout$Measurer;Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Z)Z
+HSPLandroidx/appcompat/widget/TintTypedArray;->solveLinearSystem(Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;II)V
+HSPLandroidx/benchmark/integration/baselineprofiles/library/buildprovider/EmptyActivity;-><init>()V
+HSPLandroidx/benchmark/integration/baselineprofiles/library/buildprovider/EmptyActivity;->onCreate(Landroid/os/Bundle;)V
+HSPLandroidx/collection/ArrayMap$1;-><init>()V
+HSPLandroidx/constraintlayout/solver/ArrayLinkedVariables;-><init>(Landroidx/constraintlayout/solver/ArrayRow;Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;-><init>()V
+HSPLandroidx/constraintlayout/solver/ArrayRow;-><init>(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->addError(Landroidx/constraintlayout/solver/LinearSystem;I)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->createRowGreaterThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->createRowLowerThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->pivot(Landroidx/constraintlayout/solver/SolverVariable;)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->reset()V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->updateFromFinalVariable(Landroidx/constraintlayout/solver/SolverVariable;Z)V
+HSPLandroidx/constraintlayout/solver/ArrayRow;->updateFromRow(Landroidx/constraintlayout/solver/ArrayRow;Z)V
+HSPLandroidx/constraintlayout/solver/LinearSystem$ValuesRow;-><init>(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;-><init>()V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->acquireSolverVariable$enumunboxing$(I)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addCentering(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;IFLandroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addConstraint(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addEquality(Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addEquality(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addGreaterThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addLowerThan(Landroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;II)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->addRow(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createErrorVariable(I)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createObjectVariable(Ljava/lang/Object;)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createRow()Landroidx/constraintlayout/solver/ArrayRow;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->createSlackVariable()Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/LinearSystem;->getObjectVariableValue(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;)I
+HSPLandroidx/constraintlayout/solver/LinearSystem;->increaseTableSize()V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->optimize(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->releaseRows()V
+HSPLandroidx/constraintlayout/solver/LinearSystem;->reset()V
+HSPLandroidx/constraintlayout/solver/Pools$SimplePool;-><init>()V
+HSPLandroidx/constraintlayout/solver/Pools$SimplePool;->acquire()Ljava/lang/Object;
+HSPLandroidx/constraintlayout/solver/Pools$SimplePool;->release(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow$GoalVariableAccessor;-><init>(Landroidx/constraintlayout/solver/PriorityGoalRow;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;-><init>(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->addToGoal(Landroidx/constraintlayout/solver/SolverVariable;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->getPivotCandidate([Z)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->removeGoal(Landroidx/constraintlayout/solver/SolverVariable;)V
+HSPLandroidx/constraintlayout/solver/PriorityGoalRow;->updateFromRow(Landroidx/constraintlayout/solver/ArrayRow;Z)V
+HSPLandroidx/constraintlayout/solver/SolverVariable$Type$EnumUnboxingSharedUtility;-><clinit>()V
+HSPLandroidx/constraintlayout/solver/SolverVariable$Type$EnumUnboxingSharedUtility;->ordinal(I)I
+HSPLandroidx/constraintlayout/solver/SolverVariable;-><init>(I)V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->addToRow(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->removeFromRow(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->reset()V
+HSPLandroidx/constraintlayout/solver/SolverVariable;->updateReferencesWithNewDefinition(Landroidx/constraintlayout/solver/ArrayRow;)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;-><init>(Landroidx/constraintlayout/solver/ArrayRow;Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->add(Landroidx/constraintlayout/solver/SolverVariable;FZ)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->addToHashMap(Landroidx/constraintlayout/solver/SolverVariable;I)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->addVariable(ILandroidx/constraintlayout/solver/SolverVariable;F)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->clear()V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->divideByAmount(F)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->get(Landroidx/constraintlayout/solver/SolverVariable;)F
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->getCurrentSize()I
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->getVariable(I)Landroidx/constraintlayout/solver/SolverVariable;
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->getVariableValue(I)F
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->indexOf(Landroidx/constraintlayout/solver/SolverVariable;)I
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->invert()V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->put(Landroidx/constraintlayout/solver/SolverVariable;F)V
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->remove(Landroidx/constraintlayout/solver/SolverVariable;Z)F
+HSPLandroidx/constraintlayout/solver/SolverVariableValues;->use(Landroidx/constraintlayout/solver/ArrayRow;Z)F
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;-><clinit>()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;-><init>(ILjava/lang/String;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->connect(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;II)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->getMargin()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->isConnected()Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->reset()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;->resetSolverVariable()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;-><init>()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->addToSolver(Landroidx/constraintlayout/solver/LinearSystem;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->applyConstraints$enumunboxing$(Landroidx/constraintlayout/solver/LinearSystem;ZZZZLandroidx/constraintlayout/solver/SolverVariable;Landroidx/constraintlayout/solver/SolverVariable;IZLandroidx/constraintlayout/solver/widgets/ConstraintAnchor;Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;IIIIFZZZZIIIIFZ)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->createObjectVariables(Landroidx/constraintlayout/solver/LinearSystem;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getAnchor(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;)Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getDimensionBehaviour$enumunboxing$(I)I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getHeight()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getWidth()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getX()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->getY()I
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->immediateConnect(Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;II)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->isChainHead(I)Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->isInHorizontalChain()Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->isInVerticalChain()Z
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->reset()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->resetSolverVariables(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setHeight(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setHorizontalDimensionBehaviour$enumunboxing$(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setVerticalDimensionBehaviour$enumunboxing$(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->setWidth(I)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidget;->updateFromSolver(Landroidx/constraintlayout/solver/LinearSystem;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;-><init>()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;->addChildrenToSolver(Landroidx/constraintlayout/solver/LinearSystem;)V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;->layout()V
+HSPLandroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;->resetSolverVariables(Landroidx/collection/ArrayMap$1;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/BasicMeasure$Measure;-><init>()V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/DependencyGraph;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/DependencyNode;-><init>(Landroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/DimensionDependency;-><init>(Landroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/HorizontalWidgetRun;-><clinit>()V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/HorizontalWidgetRun;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/VerticalWidgetRun;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;)V
+HSPLandroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;-><init>(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams$Table;-><clinit>()V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;->resolveLayoutDirection(I)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;->validate()V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;-><init>(Landroidx/constraintlayout/widget/ConstraintLayout;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout$Measurer;->measure(Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/solver/widgets/analyzer/BasicMeasure$Measure;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;-><init>(Landroid/content/Context;Landroid/util/AttributeSet;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->addView(Landroid/view/View;ILandroid/view/ViewGroup$LayoutParams;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->applyConstraintsFromLayoutParams(ZLandroid/view/View;Landroidx/constraintlayout/solver/widgets/ConstraintWidget;Landroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;Landroid/util/SparseArray;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->checkLayoutParams(Landroid/view/ViewGroup$LayoutParams;)Z
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->dispatchDraw(Landroid/graphics/Canvas;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->generateLayoutParams(Landroid/util/AttributeSet;)Landroid/view/ViewGroup$LayoutParams;
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->getPaddingWidth()I
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->getViewWidget(Landroid/view/View;)Landroidx/constraintlayout/solver/widgets/ConstraintWidget;
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->isRtl()Z
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->onLayout(ZIIII)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->onMeasure(II)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->onViewAdded(Landroid/view/View;)V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->requestLayout()V
+HSPLandroidx/constraintlayout/widget/ConstraintLayout;->updateHierarchy()Z
+HSPLandroidx/constraintlayout/widget/R$styleable;-><clinit>()V
+HSPLandroidx/core/app/CoreComponentFactory;-><init>()V
+HSPLandroidx/core/app/CoreComponentFactory;->instantiateActivity(Ljava/lang/ClassLoader;Ljava/lang/String;Landroid/content/Intent;)Landroid/app/Activity;
+HSPLandroidx/core/app/CoreComponentFactory;->instantiateApplication(Ljava/lang/ClassLoader;Ljava/lang/String;)Landroid/app/Application;
+HSPLandroidx/core/util/ObjectsCompat;-><clinit>()V
+Landroidx/appcompat/widget/TintTypedArray;
+Landroidx/benchmark/integration/baselineprofiles/library/buildprovider/EmptyActivity;
+Landroidx/collection/ArrayMap$1;
+Landroidx/constraintlayout/solver/ArrayLinkedVariables;
+Landroidx/constraintlayout/solver/ArrayRow$ArrayRowVariables;
+Landroidx/constraintlayout/solver/ArrayRow;
+Landroidx/constraintlayout/solver/LinearSystem$ValuesRow;
+Landroidx/constraintlayout/solver/LinearSystem;
+Landroidx/constraintlayout/solver/Pools$SimplePool;
+Landroidx/constraintlayout/solver/PriorityGoalRow$GoalVariableAccessor;
+Landroidx/constraintlayout/solver/PriorityGoalRow;
+Landroidx/constraintlayout/solver/SolverVariable$Type$EnumUnboxingSharedUtility;
+Landroidx/constraintlayout/solver/SolverVariable;
+Landroidx/constraintlayout/solver/SolverVariableValues;
+Landroidx/constraintlayout/solver/widgets/Barrier;
+Landroidx/constraintlayout/solver/widgets/ChainHead;
+Landroidx/constraintlayout/solver/widgets/ConstraintAnchor$Type;
+Landroidx/constraintlayout/solver/widgets/ConstraintAnchor;
+Landroidx/constraintlayout/solver/widgets/ConstraintWidget;
+Landroidx/constraintlayout/solver/widgets/ConstraintWidgetContainer;
+Landroidx/constraintlayout/solver/widgets/Guideline;
+Landroidx/constraintlayout/solver/widgets/Helper;
+Landroidx/constraintlayout/solver/widgets/HelperWidget;
+Landroidx/constraintlayout/solver/widgets/analyzer/BasicMeasure$Measure;
+Landroidx/constraintlayout/solver/widgets/analyzer/Dependency;
+Landroidx/constraintlayout/solver/widgets/analyzer/DependencyGraph;
+Landroidx/constraintlayout/solver/widgets/analyzer/DependencyNode;
+Landroidx/constraintlayout/solver/widgets/analyzer/DimensionDependency;
+Landroidx/constraintlayout/solver/widgets/analyzer/HorizontalWidgetRun;
+Landroidx/constraintlayout/solver/widgets/analyzer/VerticalWidgetRun;
+Landroidx/constraintlayout/solver/widgets/analyzer/WidgetRun;
+Landroidx/constraintlayout/widget/ConstraintHelper;
+Landroidx/constraintlayout/widget/ConstraintLayout$LayoutParams$Table;
+Landroidx/constraintlayout/widget/ConstraintLayout$LayoutParams;
+Landroidx/constraintlayout/widget/ConstraintLayout$Measurer;
+Landroidx/constraintlayout/widget/ConstraintLayout;
+Landroidx/constraintlayout/widget/Guideline;
+Landroidx/constraintlayout/widget/R$styleable;
+Landroidx/core/app/CoreComponentFactory;
+Landroidx/core/util/ObjectsCompat;
\ No newline at end of file
diff --git a/benchmark/integration-tests/baselineprofiles-library-consumer/src/main/java/androidx/benchmark/integration/baselineprofiles/library/consumer/EmptyClass.kt b/benchmark/integration-tests/baselineprofiles-library-consumer/src/main/java/androidx/benchmark/integration/baselineprofiles/library/consumer/EmptyClass.kt
new file mode 100644
index 0000000..47a198a
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-library-consumer/src/main/java/androidx/benchmark/integration/baselineprofiles/library/consumer/EmptyClass.kt
@@ -0,0 +1,26 @@
+/*
+ * 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.benchmark.integration.baselineprofiles.library.consumer
+
+import android.util.Log
+
+object EmptyClass {
+
+ fun doSomething() {
+ Log.d("EmptyClass", "Done.")
+ }
+}
diff --git a/benchmark/integration-tests/baselineprofiles-library-producer/build.gradle b/benchmark/integration-tests/baselineprofiles-library-producer/build.gradle
new file mode 100644
index 0000000..c797473
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-library-producer/build.gradle
@@ -0,0 +1,60 @@
+import com.android.build.api.dsl.ManagedVirtualDevice
+
+/*
+ * 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.
+ */
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.test")
+ id("kotlin-android")
+ id("androidx.baselineprofiles.producer")
+}
+
+android {
+ defaultConfig {
+ minSdkVersion 23
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ testOptions.managedDevices.devices {
+ pixel6Api31(ManagedVirtualDevice) {
+ device = "Pixel 6"
+ apiLevel = 31
+ systemImageSource = "aosp"
+ }
+ }
+ targetProjectPath = ":benchmark:integration-tests:baselineprofiles-library-build-provider"
+ namespace "androidx.benchmark.integration.baselineprofiles.library.producer"
+}
+
+dependencies {
+ implementation(project(":benchmark:benchmark-junit4"))
+ implementation(project(":benchmark:benchmark-macro-junit4"))
+ implementation(libs.testRules)
+ implementation(libs.testExtJunit)
+ implementation(libs.testCore)
+ implementation(libs.testRunner)
+ implementation(libs.testUiautomator)
+ implementation(libs.testExtTruth)
+}
+
+baselineProfilesProfileProducer {
+ managedDevices += "pixel6Api31"
+ useConnectedDevices = false
+}
+
+androidx {
+ disableDeviceTests = true
+}
diff --git a/benchmark/integration-tests/baselineprofiles-library-producer/src/main/AndroidManifest.xml b/benchmark/integration-tests/baselineprofiles-library-producer/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..bae036b
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-library-producer/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?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.
+ -->
+<manifest />
diff --git a/benchmark/integration-tests/baselineprofiles-library-producer/src/main/java/androidx/benchmark/integration/baselineprofiles/library/producer/BaselineProfileTest.kt b/benchmark/integration-tests/baselineprofiles-library-producer/src/main/java/androidx/benchmark/integration/baselineprofiles/library/producer/BaselineProfileTest.kt
new file mode 100644
index 0000000..1d5cdec
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-library-producer/src/main/java/androidx/benchmark/integration/baselineprofiles/library/producer/BaselineProfileTest.kt
@@ -0,0 +1,56 @@
+/*
+ * 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.benchmark.integration.baselineprofiles.library.producer
+
+import android.content.Intent
+import android.os.Build
+import androidx.benchmark.DeviceInfo
+import androidx.benchmark.macro.junit4.BaselineProfileRule
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import org.junit.Assume.assumeTrue
+import org.junit.Rule
+import org.junit.Test
+
+@LargeTest
+@SdkSuppress(minSdkVersion = 29)
+class BaselineProfileTest {
+
+ @get:Rule
+ val baselineRule = BaselineProfileRule()
+
+ @Test
+ fun startupBaselineProfile() {
+ assumeTrue(DeviceInfo.isRooted || Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
+
+ // Collects the baseline profile
+ baselineRule.collectBaselineProfile(
+ packageName = PACKAGE_NAME,
+ profileBlock = {
+ startActivityAndWait(Intent(ACTION))
+ device.waitForIdle()
+ }
+ )
+ }
+
+ companion object {
+ private const val PACKAGE_NAME =
+ "androidx.benchmark.integration.baselineprofiles.library.buildprovider"
+ private const val ACTION =
+ "androidx.benchmark.integration.baselineprofiles.EMPTY_ACTIVITY"
+ }
+}
diff --git a/benchmark/integration-tests/baselineprofiles-producer/build.gradle b/benchmark/integration-tests/baselineprofiles-producer/build.gradle
new file mode 100644
index 0000000..c49546c
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-producer/build.gradle
@@ -0,0 +1,60 @@
+import com.android.build.api.dsl.ManagedVirtualDevice
+
+/*
+ * 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.
+ */
+
+plugins {
+ id("AndroidXPlugin")
+ id("com.android.test")
+ id("kotlin-android")
+ id("androidx.baselineprofiles.producer")
+}
+
+android {
+ defaultConfig {
+ minSdkVersion 23
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ testOptions.managedDevices.devices {
+ pixel6Api31(ManagedVirtualDevice) {
+ device = "Pixel 6"
+ apiLevel = 31
+ systemImageSource = "aosp"
+ }
+ }
+ targetProjectPath = ":benchmark:integration-tests:baselineprofiles-consumer"
+ namespace "androidx.benchmark.integration.baselineprofiles.producer"
+}
+
+dependencies {
+ implementation(project(":benchmark:benchmark-junit4"))
+ implementation(project(":benchmark:benchmark-macro-junit4"))
+ implementation(libs.testRules)
+ implementation(libs.testExtJunit)
+ implementation(libs.testCore)
+ implementation(libs.testRunner)
+ implementation(libs.testUiautomator)
+ implementation(libs.testExtTruth)
+}
+
+baselineProfilesProfileProducer {
+ managedDevices += "pixel6Api31"
+ useConnectedDevices = false
+}
+
+androidx {
+ disableDeviceTests = true
+}
diff --git a/benchmark/integration-tests/baselineprofiles-producer/src/main/AndroidManifest.xml b/benchmark/integration-tests/baselineprofiles-producer/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..bae036b
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-producer/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?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.
+ -->
+<manifest />
diff --git a/benchmark/integration-tests/baselineprofiles-producer/src/main/java/androidx/benchmark/integration/baselineprofiles/producer/BaselineProfileTest.kt b/benchmark/integration-tests/baselineprofiles-producer/src/main/java/androidx/benchmark/integration/baselineprofiles/producer/BaselineProfileTest.kt
new file mode 100644
index 0000000..3fbcfea
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-producer/src/main/java/androidx/benchmark/integration/baselineprofiles/producer/BaselineProfileTest.kt
@@ -0,0 +1,56 @@
+/*
+ * 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.benchmark.integration.baselineprofiles.producer
+
+import android.content.Intent
+import android.os.Build
+import androidx.benchmark.DeviceInfo
+import androidx.benchmark.macro.junit4.BaselineProfileRule
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import org.junit.Assume.assumeTrue
+import org.junit.Rule
+import org.junit.Test
+
+@LargeTest
+@SdkSuppress(minSdkVersion = 29)
+class BaselineProfileTest {
+
+ @get:Rule
+ val baselineRule = BaselineProfileRule()
+
+ @Test
+ fun startupBaselineProfile() {
+ assumeTrue(DeviceInfo.isRooted || Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
+
+ // Collects the baseline profile
+ baselineRule.collectBaselineProfile(
+ packageName = PACKAGE_NAME,
+ profileBlock = {
+ startActivityAndWait(Intent(ACTION))
+ device.waitForIdle()
+ }
+ )
+ }
+
+ companion object {
+ private const val PACKAGE_NAME =
+ "androidx.benchmark.integration.baselineprofiles.consumer"
+ private const val ACTION =
+ "androidx.benchmark.integration.baselineprofiles.consumer.EMPTY_ACTIVITY"
+ }
+}
diff --git a/benchmark/integration-tests/baselineprofiles-test-utils/utils.gradle b/benchmark/integration-tests/baselineprofiles-test-utils/utils.gradle
new file mode 100644
index 0000000..4a0a8dd
--- /dev/null
+++ b/benchmark/integration-tests/baselineprofiles-test-utils/utils.gradle
@@ -0,0 +1,26 @@
+// To trigger the baseline profile generation using the different modules the test will call
+// the base generation task `generateBaselineProfiles`. The `AssertEqualsAndCleanUpTask` asserts
+// that the final output is the expected one and if there are no failures cleans up the
+// generated baseline-prof.txt.
+@CacheableTask
+abstract class AssertEqualsAndCleanUpTask extends DefaultTask {
+ @InputFile
+ @PathSensitive(PathSensitivity.NONE)
+ abstract RegularFileProperty getExpectedFile()
+
+ @InputFile
+ @PathSensitive(PathSensitivity.NONE)
+ abstract RegularFileProperty getActualFile()
+
+ @TaskAction
+ void exec() {
+ assert getExpectedFile().get().asFile.text == getActualFile().get().asFile.text
+
+ // This deletes the actual file since it's a test artifact
+ getActualFile().get().asFile.delete()
+ }
+}
+tasks.register("testBaselineProfilesGeneration", AssertEqualsAndCleanUpTask).configure {
+ it.expectedFile.set(project.layout.projectDirectory.file("src/main/expected-baseline-prof.txt"))
+ it.actualFile.set(tasks.named("generateBaselineProfiles").flatMap { it.baselineProfileFile })
+}
diff --git a/camera/camera-camera2-pipe-integration/OWNERS b/camera/camera-camera2-pipe-integration/OWNERS
index 871060e..c445688 100644
--- a/camera/camera-camera2-pipe-integration/OWNERS
+++ b/camera/camera-camera2-pipe-integration/OWNERS
@@ -1,3 +1,4 @@
+# Bug component: 575599
codelogic@google.com
sushilnath@google.com
lnishan@google.com
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ApiCompat.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ApiCompat.kt
index edf21f9..40b5167 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ApiCompat.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/ApiCompat.kt
@@ -35,6 +35,7 @@
import androidx.annotation.DoNotInline
import androidx.annotation.RequiresApi
import androidx.annotation.RequiresPermission
+import androidx.camera.camera2.pipe.CameraMetadata
import java.util.concurrent.Executor
@RequiresApi(Build.VERSION_CODES.M)
@@ -322,6 +323,12 @@
@JvmStatic
@DoNotInline
+ fun getAvailableStreamUseCases(cameraMetadata: CameraMetadata): LongArray? {
+ return cameraMetadata[CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES]
+ }
+
+ @JvmStatic
+ @DoNotInline
fun getStreamUseCase(outputConfig: OutputConfiguration): Long {
return outputConfig.streamUseCase
}
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactory.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactory.kt
index 56c25a7..f9767ba 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactory.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactory.kt
@@ -24,6 +24,7 @@
import android.view.Surface
import androidx.annotation.RequiresApi
import androidx.camera.camera2.pipe.CameraGraph
+import androidx.camera.camera2.pipe.CameraId
import androidx.camera.camera2.pipe.StreamId
import androidx.camera.camera2.pipe.compat.OutputConfigurationWrapper.Companion.SURFACE_GROUP_ID_NONE
import androidx.camera.camera2.pipe.config.Camera2ControllerScope
@@ -180,14 +181,21 @@
constructor(
private val threads: Threads,
private val streamGraph: StreamGraphImpl,
- private val graphConfig: CameraGraph.Config
+ private val graphConfig: CameraGraph.Config,
+ private val camera2MetadataProvider: Camera2MetadataProvider
) : CaptureSessionFactory {
override fun create(
cameraDevice: CameraDeviceWrapper,
surfaces: Map<StreamId, Surface>,
captureSessionState: CaptureSessionState
): Map<StreamId, OutputConfigurationWrapper> {
- val outputs = buildOutputConfigurations(graphConfig, streamGraph, surfaces)
+ val outputs = buildOutputConfigurations(
+ graphConfig,
+ streamGraph,
+ surfaces,
+ camera2MetadataProvider,
+ cameraDevice.cameraId
+ )
if (outputs.all.isEmpty()) {
Log.warn { "Failed to create OutputConfigurations for $graphConfig" }
return emptyMap()
@@ -224,7 +232,8 @@
constructor(
private val threads: Threads,
private val graphConfig: CameraGraph.Config,
- private val streamGraph: StreamGraphImpl
+ private val streamGraph: StreamGraphImpl,
+ private val camera2MetadataProvider: Camera2MetadataProvider
) : CaptureSessionFactory {
override fun create(
cameraDevice: CameraDeviceWrapper,
@@ -238,7 +247,13 @@
CameraGraph.OperatingMode.HIGH_SPEED -> SessionConfigData.SESSION_TYPE_HIGH_SPEED
}
- val outputs = buildOutputConfigurations(graphConfig, streamGraph, surfaces)
+ val outputs = buildOutputConfigurations(
+ graphConfig,
+ streamGraph,
+ surfaces,
+ camera2MetadataProvider,
+ cameraDevice.cameraId
+ )
if (outputs.all.isEmpty()) {
Log.warn { "Failed to create OutputConfigurations for $graphConfig" }
return emptyMap()
@@ -277,7 +292,9 @@
internal fun buildOutputConfigurations(
graphConfig: CameraGraph.Config,
streamGraph: StreamGraphImpl,
- surfaces: Map<StreamId, Surface>
+ surfaces: Map<StreamId, Surface>,
+ camera2MetadataProvider: Camera2MetadataProvider,
+ cameraId: CameraId
): OutputConfigurations {
val allOutputs = arrayListOf<OutputConfigurationWrapper>()
val deferredOutputs = mutableMapOf<StreamId, OutputConfigurationWrapper>()
@@ -303,23 +320,24 @@
}
if (outputConfig.deferrable && outputSurfaces.size != outputConfig.streams.size) {
- val output =
- AndroidOutputConfiguration.create(
- null,
- size = outputConfig.size,
- outputType = outputConfig.deferredOutputType!!,
- mirrorMode = outputConfig.mirrorMode,
- timestampBase = outputConfig.timestampBase,
- dynamicRangeProfile = outputConfig.dynamicRangeProfile,
- streamUseCase = outputConfig.streamUseCase,
- surfaceSharing = outputConfig.surfaceSharing,
- surfaceGroupId = outputConfig.groupNumber ?: SURFACE_GROUP_ID_NONE,
- physicalCameraId =
- if (outputConfig.camera != graphConfig.camera) {
- outputConfig.camera
- } else {
- null
- })
+ val output = AndroidOutputConfiguration.create(
+ null,
+ size = outputConfig.size,
+ outputType = outputConfig.deferredOutputType!!,
+ mirrorMode = outputConfig.mirrorMode,
+ timestampBase = outputConfig.timestampBase,
+ dynamicRangeProfile = outputConfig.dynamicRangeProfile,
+ streamUseCase = outputConfig.streamUseCase,
+ surfaceSharing = outputConfig.surfaceSharing,
+ surfaceGroupId = outputConfig.groupNumber ?: SURFACE_GROUP_ID_NONE,
+ physicalCameraId = if (outputConfig.camera != graphConfig.camera) {
+ outputConfig.camera
+ } else {
+ null
+ },
+ cameraId = cameraId,
+ camera2MetadataProvider = camera2MetadataProvider
+ )
if (output == null) {
Log.warn { "Failed to create AndroidOutputConfiguration for $outputConfig" }
continue
@@ -337,22 +355,23 @@
"Surfaces are not yet available for $outputConfig!" +
" Missing surfaces for $missingStreams!"
}
- val output =
- AndroidOutputConfiguration.create(
- outputSurfaces.first(),
- mirrorMode = outputConfig.mirrorMode,
- timestampBase = outputConfig.timestampBase,
- dynamicRangeProfile = outputConfig.dynamicRangeProfile,
- streamUseCase = outputConfig.streamUseCase,
- size = outputConfig.size,
- surfaceSharing = outputConfig.surfaceSharing,
- surfaceGroupId = outputConfig.groupNumber ?: SURFACE_GROUP_ID_NONE,
- physicalCameraId =
- if (outputConfig.camera != graphConfig.camera) {
- outputConfig.camera
- } else {
- null
- })
+ val output = AndroidOutputConfiguration.create(
+ outputSurfaces.first(),
+ mirrorMode = outputConfig.mirrorMode,
+ timestampBase = outputConfig.timestampBase,
+ dynamicRangeProfile = outputConfig.dynamicRangeProfile,
+ streamUseCase = outputConfig.streamUseCase,
+ size = outputConfig.size,
+ surfaceSharing = outputConfig.surfaceSharing,
+ surfaceGroupId = outputConfig.groupNumber ?: SURFACE_GROUP_ID_NONE,
+ physicalCameraId = if (outputConfig.camera != graphConfig.camera) {
+ outputConfig.camera
+ } else {
+ null
+ },
+ cameraId = cameraId,
+ camera2MetadataProvider = camera2MetadataProvider
+ )
if (output == null) {
Log.warn { "Failed to create AndroidOutputConfiguration for $outputConfig" }
continue
diff --git a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Configuration.kt b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Configuration.kt
index 550563a..d5b60d1 100644
--- a/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Configuration.kt
+++ b/camera/camera-camera2-pipe/src/main/java/androidx/camera/camera2/pipe/compat/Configuration.kt
@@ -142,7 +142,9 @@
size: Size? = null,
surfaceSharing: Boolean = false,
surfaceGroupId: Int = SURFACE_GROUP_ID_NONE,
- physicalCameraId: CameraId? = null
+ physicalCameraId: CameraId? = null,
+ cameraId: CameraId? = null,
+ camera2MetadataProvider: Camera2MetadataProvider? = null,
): OutputConfigurationWrapper? {
check(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
@@ -172,7 +174,8 @@
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
throw IllegalStateException(
"Deferred OutputConfigurations are not supported on API " +
- "${Build.VERSION.SDK_INT} (requires API ${Build.VERSION_CODES.O})")
+ "${Build.VERSION.SDK_INT} (requires API ${Build.VERSION_CODES.O})"
+ )
}
check(size != null) {
@@ -241,9 +244,14 @@
}
}
- if (streamUseCase != null) {
+ if (streamUseCase != null && cameraId != null && camera2MetadataProvider != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- Api33Compat.setStreamUseCase(configuration, streamUseCase.value)
+ val cameraMetadata = camera2MetadataProvider.awaitCameraMetadata(cameraId)
+ val availableStreamUseCases =
+ Api33Compat.getAvailableStreamUseCases(cameraMetadata)
+ if (availableStreamUseCases?.contains(streamUseCase.value) == true) {
+ Api33Compat.setStreamUseCase(configuration, streamUseCase.value)
+ }
}
}
@@ -256,7 +264,8 @@
} else {
1
},
- physicalCameraId)
+ physicalCameraId
+ )
}
private fun OutputConfiguration.enableSurfaceSharingCompat() {
diff --git a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactoryTest.kt b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactoryTest.kt
index c418fe9..c2bcc17 100644
--- a/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactoryTest.kt
+++ b/camera/camera-camera2-pipe/src/test/java/androidx/camera/camera2/pipe/compat/CaptureSessionFactoryTest.kt
@@ -23,6 +23,8 @@
import android.util.Size
import android.view.Surface
import androidx.camera.camera2.pipe.CameraGraph
+import androidx.camera.camera2.pipe.CameraId
+import androidx.camera.camera2.pipe.CameraMetadata
import androidx.camera.camera2.pipe.CameraPipe
import androidx.camera.camera2.pipe.CameraStream
import androidx.camera.camera2.pipe.CameraSurfaceManager
@@ -104,22 +106,25 @@
val pendingOutputs =
sessionFactory.create(
AndroidCameraDevice(
- testCamera.metadata, testCamera.cameraDevice, testCamera.cameraId),
+ testCamera.metadata, testCamera.cameraDevice, testCamera.cameraId
+ ),
mapOf(stream1.id to surface),
captureSessionState =
- CaptureSessionState(
- FakeGraphProcessor(),
- sessionFactory,
- object : Camera2CaptureSequenceProcessorFactory {
- override fun create(
- session: CameraCaptureSessionWrapper,
- surfaceMap: Map<StreamId, Surface>
- ): CaptureSequenceProcessor<Request, FakeCaptureSequence> =
- FakeCaptureSequenceProcessor()
- },
- CameraSurfaceManager(),
- SystemTimeSource(),
- this))
+ CaptureSessionState(
+ FakeGraphProcessor(),
+ sessionFactory,
+ object : Camera2CaptureSequenceProcessorFactory {
+ override fun create(
+ session: CameraCaptureSessionWrapper,
+ surfaceMap: Map<StreamId, Surface>
+ ): CaptureSequenceProcessor<Request, FakeCaptureSequence> =
+ FakeCaptureSequenceProcessor()
+ },
+ CameraSurfaceManager(),
+ SystemTimeSource(),
+ this
+ )
+ )
assertThat(pendingOutputs).isNotNull()
assertThat(pendingOutputs).isEmpty()
@@ -132,10 +137,12 @@
@Camera2ControllerScope
@Component(
modules =
- [
- FakeCameraGraphModule::class,
- FakeCameraPipeModule::class,
- Camera2CaptureSessionsModule::class])
+ [
+ FakeCameraGraphModule::class,
+ FakeCameraPipeModule::class,
+ Camera2CaptureSessionsModule::class,
+ FakeCamera2Module::class]
+)
internal interface Camera2CaptureSessionTestComponent {
fun graphConfig(): CameraGraph.Config
fun sessionFactory(): CaptureSessionFactory
@@ -148,9 +155,12 @@
private val context: Context,
private val fakeCamera: RobolectricCameras.FakeCamera
) {
- @Provides fun provideFakeCamera() = fakeCamera
+ @Provides
+ fun provideFakeCamera() = fakeCamera
- @Provides @Singleton fun provideFakeCameraPipeConfig() = CameraPipe.Config(context)
+ @Provides
+ @Singleton
+ fun provideFakeCameraPipeConfig() = CameraPipe.Config(context)
}
@Module(includes = [SharedCameraGraphModules::class])
@@ -169,3 +179,20 @@
)
}
}
+
+@Module
+class FakeCamera2Module {
+ @Provides
+ @Singleton
+ internal fun provideFakeCamera2MetadataProvider(
+ fakeCamera: RobolectricCameras.FakeCamera
+ ): Camera2MetadataProvider = object : Camera2MetadataProvider {
+ override suspend fun getCameraMetadata(cameraId: CameraId): CameraMetadata {
+ return fakeCamera.metadata
+ }
+
+ override fun awaitCameraMetadata(cameraId: CameraId): CameraMetadata {
+ return fakeCamera.metadata
+ }
+ }
+}
\ No newline at end of file
diff --git a/camera/integration-tests/avsynctestapp/build.gradle b/camera/integration-tests/avsynctestapp/build.gradle
index 8612bb7..0f4683f 100644
--- a/camera/integration-tests/avsynctestapp/build.gradle
+++ b/camera/integration-tests/avsynctestapp/build.gradle
@@ -53,6 +53,7 @@
implementation("androidx.compose.ui:ui:$compose_version")
implementation("androidx.compose.ui:ui-tooling-preview:$compose_version")
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.4.1")
+ implementation(project(":lifecycle:lifecycle-viewmodel"))
compileOnly(libs.kotlinCompiler)
@@ -61,6 +62,7 @@
testImplementation(libs.junit)
testImplementation(libs.truth)
androidTestImplementation(project(":camera:camera-testing"))
+ androidTestImplementation(project(":lifecycle:lifecycle-viewmodel"))
androidTestImplementation(libs.kotlinCoroutinesTest)
androidTestImplementation(libs.testExtJunit)
androidTestImplementation(libs.testRules)
diff --git a/camera/integration-tests/avsynctestapp/src/androidTest/java/androidx/camera/integration/avsync/SignalGeneratorViewModelTest.kt b/camera/integration-tests/avsynctestapp/src/androidTest/java/androidx/camera/integration/avsync/SignalGeneratorViewModelTest.kt
index 36b13db..88c8b26 100644
--- a/camera/integration-tests/avsynctestapp/src/androidTest/java/androidx/camera/integration/avsync/SignalGeneratorViewModelTest.kt
+++ b/camera/integration-tests/avsynctestapp/src/androidTest/java/androidx/camera/integration/avsync/SignalGeneratorViewModelTest.kt
@@ -66,12 +66,12 @@
private lateinit var viewModel: SignalGeneratorViewModel
private lateinit var lifecycleOwner: FakeLifecycleOwner
private val fakeViewModelStoreOwner = object : ViewModelStoreOwner {
- private val viewModelStore = ViewModelStore()
+ private val vmStore = ViewModelStore()
- override fun getViewModelStore() = viewModelStore
+ override val viewModelStore = vmStore
fun clear() {
- viewModelStore.clear()
+ vmStore.clear()
}
}
diff --git a/compose/OWNERS b/compose/OWNERS
index 578f153..d441e85 100644
--- a/compose/OWNERS
+++ b/compose/OWNERS
@@ -2,3 +2,6 @@
chuckj@google.com
jsproch@google.com
lelandr@google.com
+aelias@google.com
+malkov@google.com
+clarabayarri@google.com
diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/SystemGestureExclusion.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/SystemGestureExclusion.kt
index df702a8..a62fdb5 100644
--- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/SystemGestureExclusion.kt
+++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/SystemGestureExclusion.kt
@@ -26,7 +26,6 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.geometry.Rect
-import androidx.compose.ui.graphics.toAndroidRect
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.OnGloballyPositionedModifier
import androidx.compose.ui.layout.boundsInRoot
@@ -97,7 +96,13 @@
override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
val newRect = if (exclusion == null) {
- coordinates.boundsInRoot().toAndroidRect()
+ val boundsInRoot = coordinates.boundsInRoot()
+ android.graphics.Rect(
+ boundsInRoot.left.roundToInt(),
+ boundsInRoot.top.roundToInt(),
+ boundsInRoot.right.roundToInt(),
+ boundsInRoot.bottom.roundToInt()
+ )
} else {
calcBounds(coordinates, exclusion.invoke(coordinates))
}
diff --git a/compose/material/material-ripple/src/androidMain/kotlin/androidx/compose/material/ripple/RippleHostView.android.kt b/compose/material/material-ripple/src/androidMain/kotlin/androidx/compose/material/ripple/RippleHostView.android.kt
index ae926e8..c969613 100644
--- a/compose/material/material-ripple/src/androidMain/kotlin/androidx/compose/material/ripple/RippleHostView.android.kt
+++ b/compose/material/material-ripple/src/androidMain/kotlin/androidx/compose/material/ripple/RippleHostView.android.kt
@@ -29,9 +29,7 @@
import androidx.annotation.RequiresApi
import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.geometry.toRect
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.toAndroidRect
import androidx.compose.ui.graphics.toArgb
import java.lang.reflect.Method
@@ -179,7 +177,12 @@
// another invalidation, etc.
ripple.trySetRadius(radius)
ripple.setColor(color, alpha)
- val newBounds = size.toRect().toAndroidRect()
+ val newBounds = Rect(
+ 0,
+ 0,
+ size.width.toInt(),
+ size.height.toInt()
+ )
// Drawing the background causes the view to update the bounds of the drawable
// based on the view's bounds, so we need to adjust the view itself to match the
// canvas' bounds.
diff --git a/compose/ui/ui-graphics/api/current.txt b/compose/ui/ui-graphics/api/current.txt
index fd2b2c0..358b6e6 100644
--- a/compose/ui/ui-graphics/api/current.txt
+++ b/compose/ui/ui-graphics/api/current.txt
@@ -734,7 +734,7 @@
}
public final class RectHelper_androidKt {
- method public static android.graphics.Rect toAndroidRect(androidx.compose.ui.geometry.Rect);
+ method @Deprecated public static android.graphics.Rect toAndroidRect(androidx.compose.ui.geometry.Rect);
method public static android.graphics.Rect toAndroidRect(androidx.compose.ui.unit.IntRect);
method public static android.graphics.RectF toAndroidRectF(androidx.compose.ui.geometry.Rect);
method public static androidx.compose.ui.unit.IntRect toComposeIntRect(android.graphics.Rect);
diff --git a/compose/ui/ui-graphics/api/public_plus_experimental_current.txt b/compose/ui/ui-graphics/api/public_plus_experimental_current.txt
index b9e2ae2..39ec0533 100644
--- a/compose/ui/ui-graphics/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-graphics/api/public_plus_experimental_current.txt
@@ -737,7 +737,7 @@
}
public final class RectHelper_androidKt {
- method public static android.graphics.Rect toAndroidRect(androidx.compose.ui.geometry.Rect);
+ method @Deprecated public static android.graphics.Rect toAndroidRect(androidx.compose.ui.geometry.Rect);
method public static android.graphics.Rect toAndroidRect(androidx.compose.ui.unit.IntRect);
method public static android.graphics.RectF toAndroidRectF(androidx.compose.ui.geometry.Rect);
method public static androidx.compose.ui.unit.IntRect toComposeIntRect(android.graphics.Rect);
diff --git a/compose/ui/ui-graphics/api/restricted_current.txt b/compose/ui/ui-graphics/api/restricted_current.txt
index c59dbea..5dbda20 100644
--- a/compose/ui/ui-graphics/api/restricted_current.txt
+++ b/compose/ui/ui-graphics/api/restricted_current.txt
@@ -766,7 +766,7 @@
}
public final class RectHelper_androidKt {
- method public static android.graphics.Rect toAndroidRect(androidx.compose.ui.geometry.Rect);
+ method @Deprecated public static android.graphics.Rect toAndroidRect(androidx.compose.ui.geometry.Rect);
method public static android.graphics.Rect toAndroidRect(androidx.compose.ui.unit.IntRect);
method public static android.graphics.RectF toAndroidRectF(androidx.compose.ui.geometry.Rect);
method public static androidx.compose.ui.unit.IntRect toComposeIntRect(android.graphics.Rect);
diff --git a/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/RectHelperTest.kt b/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/RectHelperTest.kt
index 248e171..8c20469 100644
--- a/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/RectHelperTest.kt
+++ b/compose/ui/ui-graphics/src/androidAndroidTest/kotlin/androidx/compose/ui/graphics/RectHelperTest.kt
@@ -28,6 +28,7 @@
@RunWith(AndroidJUnit4::class)
class RectHelperTest {
+ @Suppress("DEPRECATION")
@Test
fun rectToAndroidRectTruncates() {
assertEquals(
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.android.kt
index 5e79774..0907e2c 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/AndroidPath.android.kt
@@ -133,12 +133,12 @@
override fun addRect(rect: Rect) {
check(_rectIsValid(rect))
- rectF.set(rect.toAndroidRectF())
+ rectF.set(rect.left, rect.top, rect.right, rect.bottom)
internalPath.addRect(rectF, android.graphics.Path.Direction.CCW)
}
override fun addOval(oval: Rect) {
- rectF.set(oval.toAndroidRect())
+ rectF.set(oval.left, oval.top, oval.right, oval.bottom)
internalPath.addOval(rectF, android.graphics.Path.Direction.CCW)
}
@@ -148,7 +148,7 @@
override fun addArc(oval: Rect, startAngleDegrees: Float, sweepAngleDegrees: Float) {
check(_rectIsValid(oval))
- rectF.set(oval.toAndroidRect())
+ rectF.set(oval.left, oval.top, oval.right, oval.bottom)
internalPath.addArc(rectF, startAngleDegrees, sweepAngleDegrees)
}
diff --git a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/RectHelper.android.kt b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/RectHelper.android.kt
index c926c3c..9537090 100644
--- a/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/RectHelper.android.kt
+++ b/compose/ui/ui-graphics/src/androidMain/kotlin/androidx/compose/ui/graphics/RectHelper.android.kt
@@ -22,6 +22,14 @@
* Creates a new instance of [android.graphics.Rect] with the same bounds
* specified in the given [Rect]
*/
+@Deprecated(
+ "Converting Rect to android.graphics.Rect is lossy, and requires rounding. The " +
+ "behavior of toAndroidRect() truncates to an integral Rect, but you should choose the " +
+ "method of rounding most suitable for your use case.",
+ replaceWith = ReplaceWith(
+ "android.graphics.Rect(left.toInt(), top.toInt(), right.toInt(), bottom.toInt())"
+ )
+)
fun Rect.toAndroidRect(): android.graphics.Rect {
return android.graphics.Rect(
left.toInt(),
diff --git a/compose/ui/ui-test-junit4/api/public_plus_experimental_current.txt b/compose/ui/ui-test-junit4/api/public_plus_experimental_current.txt
index 4d3f223..850087e 100644
--- a/compose/ui/ui-test-junit4/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-test-junit4/api/public_plus_experimental_current.txt
@@ -32,6 +32,10 @@
public final class ComposeUiTestKt {
method @androidx.compose.ui.test.ExperimentalTestApi public static void runComposeUiTest(optional kotlin.coroutines.CoroutineContext effectContext, kotlin.jvm.functions.Function1<? super androidx.compose.ui.test.ComposeUiTest,? extends kotlin.Unit> block);
+ method @androidx.compose.ui.test.ExperimentalTestApi public static void waitUntilAtLeastOneExists(androidx.compose.ui.test.ComposeUiTest, androidx.compose.ui.test.SemanticsMatcher matcher, optional long timeoutMillis);
+ method @androidx.compose.ui.test.ExperimentalTestApi public static void waitUntilDoesNotExist(androidx.compose.ui.test.ComposeUiTest, androidx.compose.ui.test.SemanticsMatcher matcher, optional long timeoutMillis);
+ method @androidx.compose.ui.test.ExperimentalTestApi public static void waitUntilExactlyOneExists(androidx.compose.ui.test.ComposeUiTest, androidx.compose.ui.test.SemanticsMatcher matcher, optional long timeoutMillis);
+ method @androidx.compose.ui.test.ExperimentalTestApi public static void waitUntilNodeCount(androidx.compose.ui.test.ComposeUiTest, androidx.compose.ui.test.SemanticsMatcher matcher, int count, optional long timeoutMillis);
}
public final class ComposeUiTest_androidKt {
@@ -70,6 +74,10 @@
method public void unregisterIdlingResource(androidx.compose.ui.test.IdlingResource idlingResource);
method public void waitForIdle();
method public void waitUntil(long timeoutMillis, kotlin.jvm.functions.Function0<java.lang.Boolean> condition);
+ method @androidx.compose.ui.test.ExperimentalTestApi public void waitUntilAtLeastOneExists(androidx.compose.ui.test.SemanticsMatcher matcher, long timeoutMillis);
+ method @androidx.compose.ui.test.ExperimentalTestApi public void waitUntilDoesNotExist(androidx.compose.ui.test.SemanticsMatcher matcher, long timeoutMillis);
+ method @androidx.compose.ui.test.ExperimentalTestApi public void waitUntilExactlyOneExists(androidx.compose.ui.test.SemanticsMatcher matcher, long timeoutMillis);
+ method @androidx.compose.ui.test.ExperimentalTestApi public void waitUntilNodeCount(androidx.compose.ui.test.SemanticsMatcher matcher, int count, long timeoutMillis);
property public final A activity;
property public final R activityRule;
property public androidx.compose.ui.unit.Density density;
@@ -115,6 +123,10 @@
method public void unregisterIdlingResource(androidx.compose.ui.test.IdlingResource idlingResource);
method public void waitForIdle();
method public void waitUntil(optional long timeoutMillis, kotlin.jvm.functions.Function0<java.lang.Boolean> condition);
+ method @androidx.compose.ui.test.ExperimentalTestApi public void waitUntilAtLeastOneExists(androidx.compose.ui.test.SemanticsMatcher matcher, optional long timeoutMillis);
+ method @androidx.compose.ui.test.ExperimentalTestApi public void waitUntilDoesNotExist(androidx.compose.ui.test.SemanticsMatcher matcher, optional long timeoutMillis);
+ method @androidx.compose.ui.test.ExperimentalTestApi public void waitUntilExactlyOneExists(androidx.compose.ui.test.SemanticsMatcher matcher, optional long timeoutMillis);
+ method @androidx.compose.ui.test.ExperimentalTestApi public void waitUntilNodeCount(androidx.compose.ui.test.SemanticsMatcher matcher, int count, optional long timeoutMillis);
property public abstract androidx.compose.ui.unit.Density density;
property public abstract androidx.compose.ui.test.MainTestClock mainClock;
}
diff --git a/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/ComposeTestRuleWaitUntilTest.kt b/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/ComposeTestRuleWaitUntilTest.kt
new file mode 100644
index 0000000..3652cf4
--- /dev/null
+++ b/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/ComposeTestRuleWaitUntilTest.kt
@@ -0,0 +1,148 @@
+/*
+ * 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.ui.test.junit4
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.testutils.expectError
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.ComposeTimeoutException
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.hasTestTag
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalTestApi::class)
+class ComposeTestRuleWaitUntilTest {
+
+ @get:Rule
+ val rule = createComposeRule()
+
+ companion object {
+ private const val TestTag = "TestTag"
+ private const val Timeout = 500L
+ }
+
+ @Composable
+ private fun TaggedBox() = Box(
+ Modifier
+ .size(10.dp, 10.dp)
+ .testTag(TestTag)
+ )
+
+ @Test
+ fun waitUntilNodeCount_succeedsWhen_nodeCountCorrect() {
+ rule.setContent {
+ TaggedBox()
+ TaggedBox()
+ TaggedBox()
+ }
+
+ rule.waitUntilNodeCount(hasTestTag(TestTag), 3, Timeout)
+ }
+
+ @Test
+ fun waitUntilNodeCount_throwsWhen_nodeCountIncorrect() {
+ rule.setContent {
+ TaggedBox()
+ TaggedBox()
+ TaggedBox()
+ }
+
+ expectError<ComposeTimeoutException>(
+ expectedMessage = "Condition still not satisfied after $Timeout ms"
+ ) {
+ rule.waitUntilNodeCount(hasTestTag(TestTag), 2, Timeout)
+ }
+ }
+
+ @Test
+ fun waitUntilAtLeastOneExists_succeedsWhen_nodesExist() {
+ rule.setContent {
+ TaggedBox()
+ TaggedBox()
+ }
+
+ rule.waitUntilAtLeastOneExists(hasTestTag(TestTag))
+ }
+
+ @Test
+ fun waitUntilAtLeastOneExists_throwsWhen_nodesDoNotExist() {
+ rule.setContent {
+ Box(Modifier.size(10.dp))
+ }
+
+ expectError<ComposeTimeoutException>(
+ expectedMessage = "Condition still not satisfied after $Timeout ms"
+ ) {
+ rule.waitUntilAtLeastOneExists(hasTestTag(TestTag), Timeout)
+ }
+ }
+
+ @Test
+ fun waitUntilExactlyOneExists_succeedsWhen_oneNodeExists() {
+ rule.setContent {
+ TaggedBox()
+ }
+
+ rule.waitUntilExactlyOneExists(hasTestTag(TestTag))
+ }
+
+ @Test
+ fun waitUntilExactlyOneExists_throwsWhen_twoNodesExist() {
+ rule.setContent {
+ TaggedBox()
+ TaggedBox()
+ }
+
+ expectError<ComposeTimeoutException>(
+ expectedMessage = "Condition still not satisfied after $Timeout ms"
+ ) {
+ rule.waitUntilExactlyOneExists(hasTestTag(TestTag), Timeout)
+ }
+ }
+
+ @Test
+ fun waitUntilDoesNotExists_succeedsWhen_nodeDoesNotExist() {
+ rule.setContent {
+ Box(Modifier.size(10.dp))
+ }
+
+ rule.waitUntilDoesNotExist(hasTestTag(TestTag), timeoutMillis = Timeout)
+ }
+
+ @Test
+ fun waitUntilDoesNotExists_throwsWhen_nodeExistsUntilTimeout() {
+ rule.setContent {
+ TaggedBox()
+ }
+
+ expectError<ComposeTimeoutException>(
+ expectedMessage = "Condition still not satisfied after $Timeout ms"
+ ) {
+ rule.waitUntilDoesNotExist(hasTestTag(TestTag), timeoutMillis = Timeout)
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/WaitUntilNodeCountTest.kt b/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/WaitUntilNodeCountTest.kt
new file mode 100644
index 0000000..9fc70a6
--- /dev/null
+++ b/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/WaitUntilNodeCountTest.kt
@@ -0,0 +1,148 @@
+/*
+ * 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.ui.test.junit4
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.testutils.expectError
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.ComposeTimeoutException
+import androidx.compose.ui.test.ExperimentalTestApi
+import androidx.compose.ui.test.hasTestTag
+import androidx.compose.ui.test.runComposeUiTest
+import androidx.compose.ui.test.waitUntilAtLeastOneExists
+import androidx.compose.ui.test.waitUntilDoesNotExist
+import androidx.compose.ui.test.waitUntilExactlyOneExists
+import androidx.compose.ui.test.waitUntilNodeCount
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalTestApi::class)
+class WaitUntilNodeCountTest {
+ companion object {
+ private const val TestTag = "TestTag"
+ private const val Timeout = 500L
+ }
+
+ @Composable
+ private fun TaggedBox() = Box(
+ Modifier
+ .size(10.dp, 10.dp)
+ .testTag(TestTag)
+ )
+
+ @Test
+ fun waitUntilNodeCount_succeedsWhen_nodeCountCorrect() = runComposeUiTest {
+ setContent {
+ TaggedBox()
+ TaggedBox()
+ TaggedBox()
+ }
+
+ waitUntilNodeCount(hasTestTag(TestTag), 3, Timeout)
+ }
+
+ @Test
+ fun waitUntilNodeCount_throwsWhen_nodeCountIncorrect() = runComposeUiTest {
+ setContent {
+ TaggedBox()
+ TaggedBox()
+ TaggedBox()
+ }
+
+ expectError<ComposeTimeoutException>(
+ expectedMessage = "Condition still not satisfied after $Timeout ms"
+ ) {
+ waitUntilNodeCount(hasTestTag(TestTag), 2, Timeout)
+ }
+ }
+
+ @Test
+ fun waitUntilAtLeastOneExists_succeedsWhen_nodesExist() = runComposeUiTest {
+ setContent {
+ TaggedBox()
+ TaggedBox()
+ }
+
+ waitUntilAtLeastOneExists(hasTestTag(TestTag))
+ }
+
+ @Test
+ fun waitUntilAtLeastOneExists_throwsWhen_nodesDoNotExist() = runComposeUiTest {
+ setContent {
+ Box(Modifier.size(10.dp))
+ }
+
+ expectError<ComposeTimeoutException>(
+ expectedMessage = "Condition still not satisfied after $Timeout ms"
+ ) {
+ waitUntilAtLeastOneExists(hasTestTag(TestTag), Timeout)
+ }
+ }
+
+ @Test
+ fun waitUntilExactlyOneExists_succeedsWhen_oneNodeExists() = runComposeUiTest {
+ setContent {
+ TaggedBox()
+ }
+
+ waitUntilExactlyOneExists(hasTestTag(TestTag))
+ }
+
+ @Test
+ fun waitUntilExactlyOneExists_throwsWhen_twoNodesExist() = runComposeUiTest {
+ setContent {
+ TaggedBox()
+ TaggedBox()
+ }
+
+ expectError<ComposeTimeoutException>(
+ expectedMessage = "Condition still not satisfied after $Timeout ms"
+ ) {
+ waitUntilExactlyOneExists(hasTestTag(TestTag), Timeout)
+ }
+ }
+
+ @Test
+ fun waitUntilDoesNotExists_succeedsWhen_nodeDoesNotExist() = runComposeUiTest {
+ setContent {
+ Box(Modifier.size(10.dp))
+ }
+
+ waitUntilDoesNotExist(hasTestTag(TestTag), timeoutMillis = Timeout)
+ }
+
+ @Test
+ fun waitUntilDoesNotExists_throwsWhen_nodeExistsUntilTimeout() = runComposeUiTest {
+ setContent {
+ TaggedBox()
+ }
+
+ expectError<ComposeTimeoutException>(
+ expectedMessage = "Condition still not satisfied after $Timeout ms"
+ ) {
+ waitUntilDoesNotExist(hasTestTag(TestTag), timeoutMillis = Timeout)
+ }
+ }
+}
\ No newline at end of file
diff --git a/compose/ui/ui-test-junit4/src/androidMain/kotlin/androidx/compose/ui/test/junit4/AndroidComposeTestRule.android.kt b/compose/ui/ui-test-junit4/src/androidMain/kotlin/androidx/compose/ui/test/junit4/AndroidComposeTestRule.android.kt
index ec2ea21..626ca1e3 100644
--- a/compose/ui/ui-test-junit4/src/androidMain/kotlin/androidx/compose/ui/test/junit4/AndroidComposeTestRule.android.kt
+++ b/compose/ui/ui-test-junit4/src/androidMain/kotlin/androidx/compose/ui/test/junit4/AndroidComposeTestRule.android.kt
@@ -25,6 +25,10 @@
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.SemanticsNodeInteraction
import androidx.compose.ui.test.SemanticsNodeInteractionCollection
+import androidx.compose.ui.test.waitUntilAtLeastOneExists
+import androidx.compose.ui.test.waitUntilDoesNotExist
+import androidx.compose.ui.test.waitUntilExactlyOneExists
+import androidx.compose.ui.test.waitUntilNodeCount
import androidx.compose.ui.unit.Density
import androidx.test.ext.junit.rules.ActivityScenarioRule
import kotlin.coroutines.CoroutineContext
@@ -301,6 +305,22 @@
override fun waitUntil(timeoutMillis: Long, condition: () -> Boolean) =
composeTest.waitUntil(timeoutMillis, condition)
+ @ExperimentalTestApi
+ override fun waitUntilNodeCount(matcher: SemanticsMatcher, count: Int, timeoutMillis: Long) =
+ composeTest.waitUntilNodeCount(matcher, count, timeoutMillis)
+
+ @ExperimentalTestApi
+ override fun waitUntilAtLeastOneExists(matcher: SemanticsMatcher, timeoutMillis: Long) =
+ composeTest.waitUntilAtLeastOneExists(matcher, timeoutMillis)
+
+ @ExperimentalTestApi
+ override fun waitUntilExactlyOneExists(matcher: SemanticsMatcher, timeoutMillis: Long) =
+ composeTest.waitUntilExactlyOneExists(matcher, timeoutMillis)
+
+ @ExperimentalTestApi
+ override fun waitUntilDoesNotExist(matcher: SemanticsMatcher, timeoutMillis: Long) =
+ composeTest.waitUntilDoesNotExist(matcher, timeoutMillis)
+
override fun registerIdlingResource(idlingResource: IdlingResource) =
composeTest.registerIdlingResource(idlingResource)
diff --git a/compose/ui/ui-test-junit4/src/commonMain/kotlin/androidx/compose/ui/test/ComposeUiTest.kt b/compose/ui/ui-test-junit4/src/commonMain/kotlin/androidx/compose/ui/test/ComposeUiTest.kt
index e7900ea..3414dab 100644
--- a/compose/ui/ui-test-junit4/src/commonMain/kotlin/androidx/compose/ui/test/ComposeUiTest.kt
+++ b/compose/ui/ui-test-junit4/src/commonMain/kotlin/androidx/compose/ui/test/ComposeUiTest.kt
@@ -161,8 +161,8 @@
* @param condition Condition that must be satisfied in order for this method to successfully
* finish.
*
- * @throws ComposeTimeoutException If the condition is not satisfied after [timeoutMillis]
- * (in wall clock time).
+ * @throws androidx.compose.ui.test.ComposeTimeoutException If the condition is not satisfied
+ * after [timeoutMillis] (in wall clock time).
*/
fun waitUntil(timeoutMillis: Long = 1_000, condition: () -> Boolean)
@@ -186,4 +186,86 @@
fun setContent(composable: @Composable () -> Unit)
}
+/**
+ * Blocks until the number of nodes matching the given [matcher] is equal to the given [count].
+ *
+ * @see ComposeUiTest.waitUntil
+ *
+ * @param matcher The matcher that will be used to filter nodes.
+ * @param count The number of nodes that are expected to
+ * @param timeoutMillis The time after which this method throws an exception if the number of nodes
+ * that match the [matcher] is not [count]. This observes wall clock time, not frame time.
+ *
+ * @throws androidx.compose.ui.test.ComposeTimeoutException If the number of nodes that match the
+ * [matcher] is not [count] after [timeoutMillis] (in wall clock time).
+ */
+@ExperimentalTestApi
+fun ComposeUiTest.waitUntilNodeCount(
+ matcher: SemanticsMatcher,
+ count: Int,
+ timeoutMillis: Long = 1_000L
+) {
+ waitUntil(timeoutMillis) {
+ onAllNodes(matcher).fetchSemanticsNodes().size == count
+ }
+}
+
+/**
+ * Blocks until at least one node matches the given [matcher].
+ *
+ * @see ComposeUiTest.waitUntil
+ *
+ * @param matcher The matcher that will be used to filter nodes.
+ * @param timeoutMillis The time after which this method throws an exception if no nodes match the
+ * given [matcher]. This observes wall clock time, not frame time.
+ *
+ * @throws androidx.compose.ui.test.ComposeTimeoutException If no nodes match the given [matcher]
+ * after [timeoutMillis] (in wall clock time).
+ */
+@ExperimentalTestApi
+fun ComposeUiTest.waitUntilAtLeastOneExists(
+ matcher: SemanticsMatcher,
+ timeoutMillis: Long = 1_000L
+) {
+ waitUntil(timeoutMillis) {
+ onAllNodes(matcher).fetchSemanticsNodes().isNotEmpty()
+ }
+}
+
+/**
+ * Blocks until exactly one node matches the given [matcher].
+ *
+ * @see ComposeUiTest.waitUntil
+ *
+ * @param matcher The matcher that will be used to filter nodes.
+ * @param timeoutMillis The time after which this method throws an exception if exactly one node
+ * does not match the given [matcher]. This observes wall clock time, not frame time.
+ *
+ * @throws androidx.compose.ui.test.ComposeTimeoutException If exactly one node does not match the
+ * given [matcher] after [timeoutMillis] (in wall clock time).
+ */
+@ExperimentalTestApi
+fun ComposeUiTest.waitUntilExactlyOneExists(
+ matcher: SemanticsMatcher,
+ timeoutMillis: Long = 1_000L
+) = waitUntilNodeCount(matcher, 1, timeoutMillis)
+
+/**
+ * Blocks until no nodes match the given [matcher].
+ *
+ * @see ComposeUiTest.waitUntil
+ *
+ * @param matcher The matcher that will be used to filter nodes.
+ * @param timeoutMillis The time after which this method throws an exception if any nodes match
+ * the given [matcher]. This observes wall clock time, not frame time.
+ *
+ * @throws androidx.compose.ui.test.ComposeTimeoutException If any nodes match the given [matcher]
+ * after [timeoutMillis] (in wall clock time).
+ */
+@ExperimentalTestApi
+fun ComposeUiTest.waitUntilDoesNotExist(
+ matcher: SemanticsMatcher,
+ timeoutMillis: Long = 1_000L
+) = waitUntilNodeCount(matcher, 0, timeoutMillis)
+
internal const val NanoSecondsPerMilliSecond = 1_000_000L
diff --git a/compose/ui/ui-test-junit4/src/desktopMain/kotlin/androidx/compose/ui/test/junit4/DesktopComposeTestRule.desktop.kt b/compose/ui/ui-test-junit4/src/desktopMain/kotlin/androidx/compose/ui/test/junit4/DesktopComposeTestRule.desktop.kt
index f9ca8ad..9fd4197 100644
--- a/compose/ui/ui-test-junit4/src/desktopMain/kotlin/androidx/compose/ui/test/junit4/DesktopComposeTestRule.desktop.kt
+++ b/compose/ui/ui-test-junit4/src/desktopMain/kotlin/androidx/compose/ui/test/junit4/DesktopComposeTestRule.desktop.kt
@@ -26,6 +26,10 @@
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.SemanticsNodeInteraction
import androidx.compose.ui.test.SemanticsNodeInteractionCollection
+import androidx.compose.ui.test.waitUntilAtLeastOneExists
+import androidx.compose.ui.test.waitUntilDoesNotExist
+import androidx.compose.ui.test.waitUntilExactlyOneExists
+import androidx.compose.ui.test.waitUntilNodeCount
import androidx.compose.ui.unit.Density
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
@@ -89,6 +93,22 @@
override fun waitUntil(timeoutMillis: Long, condition: () -> Boolean) =
composeTest.waitUntil(timeoutMillis, condition)
+ @ExperimentalTestApi
+ override fun waitUntilNodeCount(matcher: SemanticsMatcher, count: Int, timeoutMillis: Long) =
+ composeTest.waitUntilNodeCount(matcher, count, timeoutMillis)
+
+ @ExperimentalTestApi
+ override fun waitUntilAtLeastOneExists(matcher: SemanticsMatcher, timeoutMillis: Long) =
+ composeTest.waitUntilAtLeastOneExists(matcher, timeoutMillis)
+
+ @ExperimentalTestApi
+ override fun waitUntilExactlyOneExists(matcher: SemanticsMatcher, timeoutMillis: Long) =
+ composeTest.waitUntilExactlyOneExists(matcher, timeoutMillis)
+
+ @ExperimentalTestApi
+ override fun waitUntilDoesNotExist(matcher: SemanticsMatcher, timeoutMillis: Long) =
+ composeTest.waitUntilDoesNotExist(matcher, timeoutMillis)
+
override fun registerIdlingResource(idlingResource: IdlingResource) =
composeTest.registerIdlingResource(idlingResource)
diff --git a/compose/ui/ui-test-junit4/src/jvmMain/kotlin/androidx/compose/ui/test/junit4/ComposeTestRule.jvm.kt b/compose/ui/ui-test-junit4/src/jvmMain/kotlin/androidx/compose/ui/test/junit4/ComposeTestRule.jvm.kt
index b0d353a..08dadac 100644
--- a/compose/ui/ui-test-junit4/src/jvmMain/kotlin/androidx/compose/ui/test/junit4/ComposeTestRule.jvm.kt
+++ b/compose/ui/ui-test-junit4/src/jvmMain/kotlin/androidx/compose/ui/test/junit4/ComposeTestRule.jvm.kt
@@ -21,6 +21,7 @@
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.IdlingResource
import androidx.compose.ui.test.MainTestClock
+import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
import androidx.compose.ui.unit.Density
import kotlin.coroutines.CoroutineContext
@@ -127,11 +128,73 @@
* @param condition Condition that must be satisfied in order for this method to successfully
* finish.
*
- * @throws ComposeTimeoutException If the condition is not satisfied after [timeoutMillis].
+ * @throws androidx.compose.ui.test.ComposeTimeoutException If the condition is not satisfied
+ * after [timeoutMillis].
*/
fun waitUntil(timeoutMillis: Long = 1_000, condition: () -> Boolean)
/**
+ * Blocks until the number of nodes matching the given [matcher] is equal to the given [count].
+ *
+ * @see ComposeTestRule.waitUntil
+ *
+ * @param matcher The matcher that will be used to filter nodes.
+ * @param count The number of nodes that are expected to
+ * @param timeoutMillis The time after which this method throws an exception if the number of
+ * nodes that match the [matcher] is not [count]. This observes wall clock time, not frame time.
+ *
+ * @throws androidx.compose.ui.test.ComposeTimeoutException If the number of nodes that match
+ * the [matcher] is not [count] after [timeoutMillis] (in wall clock time).
+ */
+ @ExperimentalTestApi
+ fun waitUntilNodeCount(matcher: SemanticsMatcher, count: Int, timeoutMillis: Long = 1_000L)
+
+ /**
+ * Blocks until at least one node matches the given [matcher].
+ *
+ * @see ComposeTestRule.waitUntil
+ *
+ * @param matcher The matcher that will be used to filter nodes.
+ * @param timeoutMillis The time after which this method throws an exception if no nodes match
+ * the given [matcher]. This observes wall clock time, not frame time.
+ *
+ * @throws androidx.compose.ui.test.ComposeTimeoutException If no nodes match the given
+ * [matcher] after [timeoutMillis] (in wall clock time).
+ */
+ @ExperimentalTestApi
+ fun waitUntilAtLeastOneExists(matcher: SemanticsMatcher, timeoutMillis: Long = 1_000L)
+
+ /**
+ * Blocks until exactly one node matches the given [matcher].
+ *
+ * @see ComposeTestRule.waitUntil
+ *
+ * @param matcher The matcher that will be used to filter nodes.
+ * @param timeoutMillis The time after which this method throws an exception if exactly one node
+ * does not match the given [matcher]. This observes wall clock time, not frame time.
+ *
+ * @throws androidx.compose.ui.test.ComposeTimeoutException If exactly one node does not match
+ * the given [matcher] after [timeoutMillis] (in wall clock time).
+ */
+ @ExperimentalTestApi
+ fun waitUntilExactlyOneExists(matcher: SemanticsMatcher, timeoutMillis: Long = 1_000L)
+
+ /**
+ * Blocks until no nodes match the given [matcher].
+ *
+ * @see ComposeTestRule.waitUntil
+ *
+ * @param matcher The matcher that will be used to filter nodes.
+ * @param timeoutMillis The time after which this method throws an exception if any nodes match
+ * the given [matcher]. This observes wall clock time, not frame time.
+ *
+ * @throws androidx.compose.ui.test.ComposeTimeoutException If any nodes match the given
+ * [matcher] after [timeoutMillis] (in wall clock time).
+ */
+ @ExperimentalTestApi
+ fun waitUntilDoesNotExist(matcher: SemanticsMatcher, timeoutMillis: Long = 1_000L)
+
+ /**
* Registers an [IdlingResource] in this test.
*/
fun registerIdlingResource(idlingResource: IdlingResource)
diff --git a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/ComposeViewAdapter.kt b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/ComposeViewAdapter.kt
index 62ec3a6..541262b 100644
--- a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/ComposeViewAdapter.kt
+++ b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/ComposeViewAdapter.kt
@@ -646,9 +646,9 @@
}
private val FakeViewModelStoreOwner = object : ViewModelStoreOwner {
- private val viewModelStore = ViewModelStore()
+ private val vmStore = ViewModelStore()
- override fun getViewModelStore() = viewModelStore
+ override val viewModelStore = vmStore
}
private val FakeOnBackPressedDispatcherOwner = object : OnBackPressedDispatcherOwner {
diff --git a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/AnimationSearch.kt b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/AnimationSearch.kt
index 85fa93c..74f9023 100644
--- a/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/AnimationSearch.kt
+++ b/compose/ui/ui-tooling/src/androidMain/kotlin/androidx/compose/ui/tooling/animation/AnimationSearch.kt
@@ -38,6 +38,7 @@
private const val ANIMATED_VISIBILITY = "AnimatedVisibility"
private const val ANIMATE_VALUE_AS_STATE = "animateValueAsState"
private const val REMEMBER = "remember"
+private const val REMEMBER_INFINITE_TRANSITION = "rememberInfiniteTransition"
private const val REMEMBER_UPDATED_STATE = "rememberUpdatedState"
private const val SIZE_ANIMATION_MODIFIER = "androidx.compose.animation.SizeAnimationModifier"
@@ -58,9 +59,12 @@
}
@OptIn(UiToolingDataApi::class)
-private inline fun <reified T> Group.findData(): T? {
+private inline fun <reified T> Group.findData(includeGrandchildren: Boolean = false): T? {
// Search in self data and children data
- return (data + children.flatMap { it.data }).firstOrNull { data ->
+ val dataToSearch = data + children.let {
+ if (includeGrandchildren) (it + it.flatMap { child -> child.children }) else it
+ }.flatMap { it.data }
+ return dataToSearch.firstOrNull { data ->
data is T
} as? T
}
@@ -201,11 +205,13 @@
private fun findAnimations(groupsWithLocation: Collection<Group>):
List<InfiniteTransitionSearchInfo> {
- val groups = groupsWithLocation.filter { group -> group.name == "run" }
- .filterIsInstance<CallGroup>()
+ val groups =
+ groupsWithLocation.filter { group -> group.name == REMEMBER_INFINITE_TRANSITION }
+ .filterIsInstance<CallGroup>()
+
return groups.mapNotNull {
val infiniteTransition = it.findData<InfiniteTransition>()
- val toolingOverride = it.findData<MutableState<State<Long>?>>()
+ val toolingOverride = it.findData<MutableState<State<Long>?>>(true)
if (infiniteTransition != null && toolingOverride != null) {
if (toolingOverride.value == null) {
toolingOverride.value = ToolingState(0L)
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
index 9af6a59..1e844e4 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/AndroidAccessibilityTest.kt
@@ -86,8 +86,8 @@
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.ImageBitmap
-import androidx.compose.ui.graphics.toAndroidRect
import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.graphics.toComposeRect
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.AndroidComposeView
import androidx.compose.ui.platform.AndroidComposeViewAccessibilityDelegateCompat
@@ -1150,7 +1150,7 @@
textFieldNode.positionInWindow
)
val expectedTopLeftInScreenCoords = androidComposeView.localToScreen(
- expectedRectInLocalCoords.toAndroidRect().topLeftToOffset()
+ expectedRectInLocalCoords.topLeft
)
assertEquals(expectedTopLeftInScreenCoords.x, rectF.left)
assertEquals(expectedTopLeftInScreenCoords.y, rectF.top)
@@ -2932,7 +2932,7 @@
accessibilityNodeInfo.getBoundsInScreen(rect)
val resultWidth = rect.right - rect.left
val resultHeight = rect.bottom - rect.top
- val resultInLocalCoords = androidComposeView.screenToLocal(rect.topLeftToOffset())
+ val resultInLocalCoords = androidComposeView.screenToLocal(rect.toComposeRect().topLeft)
assertEquals(size, resultWidth)
assertEquals(size, resultHeight)
@@ -3466,5 +3466,3 @@
)
}
}
-
-private fun Rect.topLeftToOffset() = Offset(this.left.toFloat(), this.top.toFloat())
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofill.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofill.android.kt
index a1b44c7..436c8be 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofill.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/autofill/AndroidAutofill.android.kt
@@ -27,7 +27,6 @@
import androidx.annotation.DoNotInline
import androidx.annotation.RequiresApi
import androidx.compose.ui.ExperimentalComposeUiApi
-import androidx.compose.ui.graphics.toAndroidRect
import androidx.compose.ui.util.fastMap
/**
@@ -46,13 +45,20 @@
init { view.importantForAutofill = View.IMPORTANT_FOR_AUTOFILL_YES }
override fun requestAutofillForNode(autofillNode: AutofillNode) {
+ val boundingBox = autofillNode.boundingBox
+ ?: error("requestAutofill called before onChildPositioned()")
+
// TODO(b/138731416): Find out what happens when notifyViewEntered() is called multiple times
// before calling notifyViewExited().
autofillManager.notifyViewEntered(
view,
autofillNode.id,
- autofillNode.boundingBox?.toAndroidRect()
- ?: error("requestAutofill called before onChildPositioned()")
+ android.graphics.Rect(
+ boundingBox.left.toInt(),
+ boundingBox.top.toInt(),
+ boundingBox.right.toInt(),
+ boundingBox.bottom.toInt()
+ )
)
}
@@ -89,7 +95,8 @@
autofillNode.autofillTypes.fastMap { it.androidType }.toTypedArray()
)
- if (autofillNode.boundingBox == null) {
+ val boundingBox = autofillNode.boundingBox
+ if (boundingBox == null) {
// Do we need an exception here? warning? silently ignore? If the boundingbox is
// null, the autofill overlay will not be shown.
Log.w(
@@ -97,9 +104,14 @@
"""Bounding box not set.
Did you call perform autofillTree before the component was positioned? """
)
- }
- autofillNode.boundingBox?.toAndroidRect()?.run {
- AutofillApi23Helper.setDimens(child, left, top, 0, 0, width(), height())
+ } else {
+ val left = boundingBox.left.toInt()
+ val top = boundingBox.top.toInt()
+ val right = boundingBox.right.toInt()
+ val bottom = boundingBox.bottom.toInt()
+ val width = right - left
+ val height = bottom - top
+ AutofillApi23Helper.setDimens(child, left, top, 0, 0, width, height)
}
}
index++
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
index f2876ab..64e9bbe 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidComposeViewAccessibilityDelegateCompat.android.kt
@@ -49,7 +49,6 @@
import androidx.compose.ui.fastJoinToString
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
-import androidx.compose.ui.graphics.toAndroidRect
import androidx.compose.ui.graphics.toComposeRect
import androidx.compose.ui.layout.boundsInParent
import androidx.compose.ui.layout.boundsInWindow
@@ -2797,7 +2796,18 @@
if (!root.layoutNode.isPlaced || !root.layoutNode.isAttached) {
return nodes
}
- val unaccountedSpace = Region().also { it.set(root.boundsInRoot.toAndroidRect()) }
+ val unaccountedSpace = Region().also {
+ it.set(
+ root.boundsInRoot.run {
+ android.graphics.Rect(
+ left.toInt(),
+ top.toInt(),
+ right.toInt(),
+ bottom.toInt()
+ )
+ }
+ )
+ }
fun findAllSemanticNodesRecursive(currentNode: SemanticsNode) {
val notAttachedOrPlaced =
@@ -2807,7 +2817,12 @@
) {
return
}
- val boundsInRoot = currentNode.touchBoundsInRoot.toAndroidRect()
+ val boundsInRoot = android.graphics.Rect(
+ currentNode.touchBoundsInRoot.left.toInt(),
+ currentNode.touchBoundsInRoot.top.toInt(),
+ currentNode.touchBoundsInRoot.right.toInt(),
+ currentNode.touchBoundsInRoot.bottom.toInt(),
+ )
val region = Region().also { it.set(boundsInRoot) }
val virtualViewId = if (currentNode.id == root.id) {
AccessibilityNodeProviderCompat.HOST_VIEW_ID
@@ -2836,7 +2851,12 @@
}
nodes[virtualViewId] = SemanticsNodeWithAdjustedBounds(
currentNode,
- boundsForFakeNode.toAndroidRect()
+ android.graphics.Rect(
+ boundsForFakeNode.left.toInt(),
+ boundsForFakeNode.top.toInt(),
+ boundsForFakeNode.right.toInt(),
+ boundsForFakeNode.bottom.toInt(),
+ )
)
} else if (virtualViewId == AccessibilityNodeProviderCompat.HOST_VIEW_ID) {
// Root view might have WRAP_CONTENT layout params in which case it will have zero
diff --git a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java
index 1c94351..c675c67 100644
--- a/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java
+++ b/constraintlayout/constraintlayout/src/main/java/androidx/constraintlayout/widget/ConstraintLayout.java
@@ -105,7 +105,6 @@
* ConstraintLayout.LayoutParams} for layout attributes
* </p>
*
- * <div class="special reference">
* <h3>Developer Guide</h3>
*
* <h4 id="RelativePositioning"> Relative positioning </h4>
@@ -556,7 +555,6 @@
* <p>This attribute is a mask, so you can decide to turn on or off
* specific optimizations by listing the ones you want.
* For example: <i>app:layout_optimizationLevel="direct|barrier|chain"</i> </p>
- * </div>
*/
public class ConstraintLayout extends ViewGroup {
/**
diff --git a/development/importMaven/src/main/kotlin/androidx/build/importMaven/ImportVersionCatalog.kt b/development/importMaven/src/main/kotlin/androidx/build/importMaven/ImportVersionCatalog.kt
index 93a8175..7c554df 100644
--- a/development/importMaven/src/main/kotlin/androidx/build/importMaven/ImportVersionCatalog.kt
+++ b/development/importMaven/src/main/kotlin/androidx/build/importMaven/ImportVersionCatalog.kt
@@ -46,7 +46,6 @@
Interners.newStrongInterner(),
Interners.newStrongInterner(),
project.objects,
- project.providers,
{ error("Not supported") },
configurations
)
diff --git a/docs-tip-of-tree/build.gradle b/docs-tip-of-tree/build.gradle
index d61d7f9..498ff9f 100644
--- a/docs-tip-of-tree/build.gradle
+++ b/docs-tip-of-tree/build.gradle
@@ -18,8 +18,9 @@
docs(project(":ads:ads-identifier-testing"))
kmpDocs(project(":annotation:annotation"))
docs(project(":annotation:annotation-experimental"))
- docs(project(":appactions:interaction:interaction-proto"))
docs(project(":appactions:interaction:interaction-capabilities-core"))
+ docs(project(":appactions:interaction:interaction-proto"))
+ docs(project(":appactions:interaction:interaction-service"))
docs(project(":appcompat:appcompat"))
docs(project(":appcompat:appcompat-resources"))
docs(project(":appsearch:appsearch"))
diff --git a/fragment/OWNERS b/fragment/OWNERS
index 94b111e..b867087 100644
--- a/fragment/OWNERS
+++ b/fragment/OWNERS
@@ -1,4 +1,4 @@
-# Bug component: 460964
+# Bug component: 461227
ilake@google.com
jbwoods@google.com
mount@google.com
diff --git a/fragment/fragment/api/current.txt b/fragment/fragment/api/current.txt
index 76aeea3..8417281 100644
--- a/fragment/fragment/api/current.txt
+++ b/fragment/fragment/api/current.txt
@@ -145,11 +145,11 @@
method @Deprecated public void setTargetFragment(androidx.fragment.app.Fragment?, int);
method @Deprecated public void setUserVisibleHint(boolean);
method public boolean shouldShowRequestPermissionRationale(String);
- method public void startActivity(android.content.Intent!);
- method public void startActivity(android.content.Intent!, android.os.Bundle?);
- method @Deprecated public void startActivityForResult(android.content.Intent!, int);
- method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
- method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void startActivity(android.content.Intent);
+ method public void startActivity(android.content.Intent, android.os.Bundle?);
+ method @Deprecated public void startActivityForResult(android.content.Intent, int);
+ method @Deprecated public void startActivityForResult(android.content.Intent, int, android.os.Bundle?);
+ method @Deprecated public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
method public void startPostponedEnterTransition();
method public void unregisterForContextMenu(android.view.View);
}
@@ -174,9 +174,9 @@
method public void onStateNotSaved();
method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
- method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
- method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
- method @Deprecated public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int);
+ method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int, android.os.Bundle?);
+ method @Deprecated public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
method public void supportFinishAfterTransition();
method @Deprecated public void supportInvalidateOptionsMenu();
method public void supportPostponeEnterTransition();
@@ -261,9 +261,9 @@
method @Deprecated public void onRequestPermissionsFromFragment(androidx.fragment.app.Fragment, String![], int);
method public boolean onShouldSaveFragmentState(androidx.fragment.app.Fragment);
method public boolean onShouldShowRequestPermissionRationale(String);
- method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
- method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
- method @Deprecated public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int);
+ method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int, android.os.Bundle?);
+ method @Deprecated public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
method public void onSupportInvalidateOptionsMenu();
}
diff --git a/fragment/fragment/api/public_plus_experimental_current.txt b/fragment/fragment/api/public_plus_experimental_current.txt
index 76aeea3..8417281 100644
--- a/fragment/fragment/api/public_plus_experimental_current.txt
+++ b/fragment/fragment/api/public_plus_experimental_current.txt
@@ -145,11 +145,11 @@
method @Deprecated public void setTargetFragment(androidx.fragment.app.Fragment?, int);
method @Deprecated public void setUserVisibleHint(boolean);
method public boolean shouldShowRequestPermissionRationale(String);
- method public void startActivity(android.content.Intent!);
- method public void startActivity(android.content.Intent!, android.os.Bundle?);
- method @Deprecated public void startActivityForResult(android.content.Intent!, int);
- method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
- method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void startActivity(android.content.Intent);
+ method public void startActivity(android.content.Intent, android.os.Bundle?);
+ method @Deprecated public void startActivityForResult(android.content.Intent, int);
+ method @Deprecated public void startActivityForResult(android.content.Intent, int, android.os.Bundle?);
+ method @Deprecated public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
method public void startPostponedEnterTransition();
method public void unregisterForContextMenu(android.view.View);
}
@@ -174,9 +174,9 @@
method public void onStateNotSaved();
method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
- method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
- method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
- method @Deprecated public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int);
+ method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int, android.os.Bundle?);
+ method @Deprecated public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
method public void supportFinishAfterTransition();
method @Deprecated public void supportInvalidateOptionsMenu();
method public void supportPostponeEnterTransition();
@@ -261,9 +261,9 @@
method @Deprecated public void onRequestPermissionsFromFragment(androidx.fragment.app.Fragment, String![], int);
method public boolean onShouldSaveFragmentState(androidx.fragment.app.Fragment);
method public boolean onShouldShowRequestPermissionRationale(String);
- method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
- method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
- method @Deprecated public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int);
+ method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int, android.os.Bundle?);
+ method @Deprecated public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
method public void onSupportInvalidateOptionsMenu();
}
diff --git a/fragment/fragment/api/restricted_current.txt b/fragment/fragment/api/restricted_current.txt
index bdcefeb..3671696 100644
--- a/fragment/fragment/api/restricted_current.txt
+++ b/fragment/fragment/api/restricted_current.txt
@@ -149,11 +149,11 @@
method @Deprecated public void setTargetFragment(androidx.fragment.app.Fragment?, int);
method @Deprecated public void setUserVisibleHint(boolean);
method public boolean shouldShowRequestPermissionRationale(String);
- method public void startActivity(android.content.Intent!);
- method public void startActivity(android.content.Intent!, android.os.Bundle?);
- method @Deprecated public void startActivityForResult(android.content.Intent!, int);
- method @Deprecated public void startActivityForResult(android.content.Intent!, int, android.os.Bundle?);
- method @Deprecated public void startIntentSenderForResult(android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void startActivity(android.content.Intent);
+ method public void startActivity(android.content.Intent, android.os.Bundle?);
+ method @Deprecated public void startActivityForResult(android.content.Intent, int);
+ method @Deprecated public void startActivityForResult(android.content.Intent, int, android.os.Bundle?);
+ method @Deprecated public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
method public void startPostponedEnterTransition();
method public void unregisterForContextMenu(android.view.View);
}
@@ -178,9 +178,9 @@
method public void onStateNotSaved();
method public void setEnterSharedElementCallback(androidx.core.app.SharedElementCallback?);
method public void setExitSharedElementCallback(androidx.core.app.SharedElementCallback?);
- method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
- method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
- method @Deprecated public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int);
+ method public void startActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int, android.os.Bundle?);
+ method @Deprecated public void startIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
method public void supportFinishAfterTransition();
method @Deprecated public void supportInvalidateOptionsMenu();
method public void supportPostponeEnterTransition();
@@ -265,9 +265,9 @@
method @Deprecated public void onRequestPermissionsFromFragment(androidx.fragment.app.Fragment, String![], int);
method public boolean onShouldSaveFragmentState(androidx.fragment.app.Fragment);
method public boolean onShouldShowRequestPermissionRationale(String);
- method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int);
- method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent!, int, android.os.Bundle?);
- method @Deprecated public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender!, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
+ method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int);
+ method public void onStartActivityFromFragment(androidx.fragment.app.Fragment, android.content.Intent, int, android.os.Bundle?);
+ method @Deprecated public void onStartIntentSenderFromFragment(androidx.fragment.app.Fragment, android.content.IntentSender, int, android.content.Intent?, int, int, int, android.os.Bundle?) throws android.content.IntentSender.SendIntentException;
method public void onSupportInvalidateOptionsMenu();
}
diff --git a/fragment/fragment/build.gradle b/fragment/fragment/build.gradle
index 658a821..b751358 100644
--- a/fragment/fragment/build.gradle
+++ b/fragment/fragment/build.gradle
@@ -32,7 +32,7 @@
api("androidx.activity:activity:1.5.1")
api(projectOrArtifact(":lifecycle:lifecycle-runtime"))
api("androidx.lifecycle:lifecycle-livedata-core:2.5.1")
- api("androidx.lifecycle:lifecycle-viewmodel:2.5.1")
+ api(projectOrArtifact(":lifecycle:lifecycle-viewmodel"))
api("androidx.lifecycle:lifecycle-viewmodel-savedstate:2.5.1")
api("androidx.savedstate:savedstate:1.2.0")
api("androidx.annotation:annotation-experimental:1.0.0")
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/ControllerHostCallbacks.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/ControllerHostCallbacks.kt
index 095f013..f4ba719b 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/ControllerHostCallbacks.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/ControllerHostCallbacks.kt
@@ -81,12 +81,10 @@
class ControllerHostCallbacks(
private val activity: FragmentActivity,
- private val viewModelStore: ViewModelStore
+ private val vmStore: ViewModelStore
) : FragmentHostCallback<FragmentActivity>(activity), ViewModelStoreOwner {
- override fun getViewModelStore(): ViewModelStore {
- return viewModelStore
- }
+ override val viewModelStore: ViewModelStore = vmStore
override fun onDump(
prefix: String,
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
index cbd53a2..31a1632 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
@@ -1431,7 +1431,7 @@
* Call {@link Activity#startActivity(Intent)} from the fragment's
* containing Activity.
*/
- public void startActivity(@SuppressLint("UnknownNullness") Intent intent) {
+ public void startActivity(@NonNull Intent intent) {
startActivity(intent, null);
}
@@ -1439,7 +1439,7 @@
* Call {@link Activity#startActivity(Intent, Bundle)} from the fragment's
* containing Activity.
*/
- public void startActivity(@SuppressLint("UnknownNullness") Intent intent,
+ public void startActivity(@NonNull Intent intent,
@Nullable Bundle options) {
if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
@@ -1468,7 +1468,7 @@
*/
@SuppressWarnings("deprecation")
@Deprecated
- public void startActivityForResult(@SuppressLint("UnknownNullness") Intent intent,
+ public void startActivityForResult(@NonNull Intent intent,
int requestCode) {
startActivityForResult(intent, requestCode, null);
}
@@ -1496,7 +1496,7 @@
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
- public void startActivityForResult(@SuppressLint("UnknownNullness") Intent intent,
+ public void startActivityForResult(@NonNull Intent intent,
int requestCode, @Nullable Bundle options) {
if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
@@ -1534,7 +1534,7 @@
* {@link ActivityResultContract}.
*/
@Deprecated
- public void startIntentSenderForResult(@SuppressLint("UnknownNullness") IntentSender intent,
+ public void startIntentSenderForResult(@NonNull IntentSender intent,
int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues,
int extraFlags, @Nullable Bundle options) throws IntentSender.SendIntentException {
if (mHost == null) {
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentActivity.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentActivity.java
index b48c19c..c373049 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentActivity.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentActivity.java
@@ -18,7 +18,6 @@
import static androidx.activity.result.contract.ActivityResultContracts.StartIntentSenderForResult;
-import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
@@ -501,7 +500,7 @@
* greater than 65535, an IllegalArgumentException would be thrown.
*/
public void startActivityFromFragment(@NonNull Fragment fragment,
- @SuppressLint("UnknownNullness") Intent intent, int requestCode) {
+ @NonNull Intent intent, int requestCode) {
startActivityFromFragment(fragment, intent, requestCode, null);
}
@@ -519,7 +518,7 @@
*/
@SuppressWarnings("deprecation")
public void startActivityFromFragment(@NonNull Fragment fragment,
- @SuppressLint("UnknownNullness") Intent intent, int requestCode,
+ @NonNull Intent intent, int requestCode,
@Nullable Bundle options) {
// request code will be -1 if called from fragment.startActivity
if (requestCode == -1) {
@@ -558,7 +557,7 @@
@SuppressWarnings({"deprecation"})
@Deprecated
public void startIntentSenderFromFragment(@NonNull Fragment fragment,
- @SuppressLint("UnknownNullness") IntentSender intent, int requestCode,
+ @NonNull IntentSender intent, int requestCode,
@Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
@Nullable Bundle options) throws IntentSender.SendIntentException {
if (requestCode == -1) {
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentHostCallback.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentHostCallback.java
index 21079f0..b9ebe38 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentHostCallback.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentHostCallback.java
@@ -19,7 +19,6 @@
import static androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions;
import static androidx.activity.result.contract.ActivityResultContracts.StartIntentSenderForResult;
-import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
@@ -149,7 +148,7 @@
* See {@link FragmentActivity#startActivityForResult(Intent, int)}.
*/
public void onStartActivityFromFragment(@NonNull Fragment fragment,
- @SuppressLint("UnknownNullness") Intent intent, int requestCode) {
+ @NonNull Intent intent, int requestCode) {
onStartActivityFromFragment(fragment, intent, requestCode, null);
}
@@ -158,7 +157,7 @@
* See {@link FragmentActivity#startActivityForResult(Intent, int, Bundle)}.
*/
public void onStartActivityFromFragment(
- @NonNull Fragment fragment, @SuppressLint("UnknownNullness") Intent intent,
+ @NonNull Fragment fragment, @NonNull Intent intent,
int requestCode, @Nullable Bundle options) {
if (requestCode != -1) {
throw new IllegalStateException(
@@ -179,7 +178,7 @@
*/
@Deprecated
public void onStartIntentSenderFromFragment(@NonNull Fragment fragment,
- @SuppressLint("UnknownNullness") IntentSender intent, int requestCode,
+ @NonNull IntentSender intent, int requestCode,
@Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
@Nullable Bundle options) throws IntentSender.SendIntentException {
if (requestCode != -1) {
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
index 1e0f070..af6591c 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -2815,12 +2815,12 @@
}
void launchStartActivityForResult(@NonNull Fragment f,
- @SuppressLint("UnknownNullness") Intent intent,
+ @NonNull Intent intent,
int requestCode, @Nullable Bundle options) {
if (mStartActivityForResult != null) {
LaunchedFragmentInfo info = new LaunchedFragmentInfo(f.mWho, requestCode);
mLaunchedFragments.addLast(info);
- if (intent != null && options != null) {
+ if (options != null) {
intent.putExtra(EXTRA_ACTIVITY_OPTIONS_BUNDLE, options);
}
mStartActivityForResult.launch(intent);
@@ -2831,7 +2831,7 @@
@SuppressWarnings("deprecation")
void launchStartIntentSenderForResult(@NonNull Fragment f,
- @SuppressLint("UnknownNullness") IntentSender intent,
+ @NonNull IntentSender intent,
int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues,
int extraFlags, @Nullable Bundle options) throws IntentSender.SendIntentException {
if (mStartIntentSenderForResult != null) {
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 809209f..ac37082 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
@@ -228,6 +228,7 @@
}
}
+ @Ignore("b/266588723")
@Test
fun createTextWithFillMaxDimensions() {
TestGlanceAppWidget.uiDefinition = {
@@ -346,6 +347,7 @@
}
}
+ @Ignore("b/265078768")
@Test
fun createRowWithTwoTexts() {
TestGlanceAppWidget.uiDefinition = {
diff --git a/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/PolygonTest.kt b/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/PolygonTest.kt
index 379f501..69601cf 100644
--- a/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/PolygonTest.kt
+++ b/graphics/graphics-shapes/src/androidTest/java/androidx/graphics/shapes/PolygonTest.kt
@@ -21,7 +21,10 @@
import androidx.core.graphics.plus
import androidx.core.graphics.times
import androidx.test.filters.SmallTest
-import org.junit.Assert
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotEquals
+import org.junit.Assert.assertTrue
import org.junit.Test
@SmallTest
@@ -73,7 +76,7 @@
fun pathTest() {
val shape = square.toCubicShape()
val path = shape.toPath()
- Assert.assertFalse(path.isEmpty)
+ assertFalse(path.isEmpty)
}
@Test
@@ -95,7 +98,7 @@
val squareCopy = Polygon(square)
val identity = Matrix()
square.transform(identity)
- Assert.assertEquals(square, squareCopy)
+ assertEquals(square, squareCopy)
// Now create a matrix which translates points by (1, 2) and make sure
// the shape is translated similarly by it
@@ -112,4 +115,48 @@
assertPointsEqualish(squareCopyCubics[i].p3 + offset, squareCubics[i].p3)
}
}
+
+ @Test
+ fun featuresTest() {
+ val squareFeatures = square.features
+
+ // Verify that cubics of polygon == cubics of features of that polygon
+ assertTrue(square.toCubicShape().cubics == squareFeatures.flatMap { it.cubics })
+
+ // Same as above but with rounded corners
+ val roundedSquare = RoundedPolygon(4, rounding = CornerRounding(.1f))
+ val roundedFeatures = roundedSquare.features
+ assertTrue(roundedSquare.toCubicShape().cubics == roundedFeatures.flatMap { it.cubics })
+
+ // Same as the first polygon test, but with a copy of that polygon
+ val squareCopy = Polygon(square)
+ val squareCopyFeatures = squareCopy.features
+ assertTrue(squareCopy.toCubicShape().cubics == squareCopyFeatures.flatMap { it.cubics })
+
+ // Test other elements of Features
+ val copy = Polygon(square)
+ val matrix = Matrix()
+ matrix.setTranslate(1f, 2f)
+ val features = copy.features
+ val preTransformVertices = mutableListOf<PointF>()
+ val preTransformCenters = mutableListOf<PointF>()
+ for (feature in features) {
+ if (feature is Corner) {
+ // Copy into new Point objects since the ones in the feature should transform
+ preTransformVertices.add(PointF(feature.vertex.x, feature.vertex.y))
+ preTransformCenters.add(PointF(feature.roundedCenter.x, feature.roundedCenter.y))
+ }
+ }
+ copy.transform(matrix)
+ val postTransformVertices = mutableListOf<PointF>()
+ val postTransformCenters = mutableListOf<PointF>()
+ for (feature in features) {
+ if (feature is Corner) {
+ postTransformVertices.add(feature.vertex)
+ postTransformCenters.add(feature.roundedCenter)
+ }
+ }
+ assertNotEquals(preTransformVertices, postTransformVertices)
+ assertNotEquals(preTransformCenters, postTransformCenters)
+ }
}
\ No newline at end of file
diff --git a/graphics/graphics-shapes/src/main/java/androidx/graphics/shapes/Polygon.kt b/graphics/graphics-shapes/src/main/java/androidx/graphics/shapes/Polygon.kt
index 24194e4..5129044 100644
--- a/graphics/graphics-shapes/src/main/java/androidx/graphics/shapes/Polygon.kt
+++ b/graphics/graphics-shapes/src/main/java/androidx/graphics/shapes/Polygon.kt
@@ -181,11 +181,12 @@
val tempFeatures = mutableListOf<Feature>()
for (feature in source.features) {
if (feature is Edge) {
- tempFeatures.add(Edge(feature))
+ tempFeatures.add(Edge(this, feature))
} else {
- tempFeatures.add(Corner(feature as Corner))
+ tempFeatures.add(Corner(this, feature as Corner))
}
}
+ features = tempFeatures
center = PointF(source.center.x, source.center.y)
cubicShape.updateCubics(newCubics)
}
@@ -257,11 +258,15 @@
// from above, along with new cubics representing the edges between those corners.
val tempFeatures = mutableListOf<Feature>()
for (i in 0 until n) {
- cubics.addAll(corners[i])
+ val cornerIndices = mutableListOf<Int>()
+ for (cubic in corners[i]) {
+ cornerIndices.add(cubics.size)
+ cubics.add(cubic)
+ }
// TODO: determine and pass convexity flag
- tempFeatures.add(Corner(corners[i], roundedCorners[i].center, vertices[i]))
+ tempFeatures.add(Corner(this, cornerIndices, roundedCorners[i].center, vertices[i]))
+ tempFeatures.add(Edge(this, listOf(cubics.size)))
cubics.add(Cubic.straightLine(corners[i].last().p3, corners[(i + 1) % n].first().p0))
- tempFeatures.add(Edge(listOf(cubics[cubics.size - 1])))
}
features = tempFeatures
cubicShape.updateCubics(cubics)
@@ -276,6 +281,9 @@
matrix.mapPoints(point)
center.x = point[0]
center.y = point[1]
+ for (feature in features) {
+ feature.transform(matrix)
+ }
}
/**
@@ -415,15 +423,27 @@
* of what the shape actually is, rather than simply manipulating the raw curves and lines
* which describe it.
*/
-internal sealed class Feature(val cubics: List<Cubic>)
+internal sealed class Feature(private val polygon: Polygon, protected val cubicIndices: List<Int>) {
+ val cubics: MutableList<Cubic>
+ get() {
+ val featureCubics = mutableListOf<Cubic>()
+ val cubics = polygon.toCubicShape().cubics
+ for (index in cubicIndices) {
+ featureCubics.add(cubics[index])
+ }
+ return featureCubics
+ }
+
+ open fun transform(matrix: Matrix) {}
+}
/**
* Edges have only a list of the cubic curves which make up the edge. Edges lie between
* corners and have no vertex or concavity; the curves are simply straight lines (represented
* by Cubic curves).
*/
-internal class Edge(cubics: List<Cubic>) : Feature(cubics) {
- constructor(source: Edge) : this(source.cubics)
+internal class Edge(polygon: Polygon, indices: List<Int>) : Feature(polygon, indices) {
+ constructor(polygon: Polygon, source: Edge) : this(polygon, source.cubicIndices)
}
/**
@@ -434,18 +454,27 @@
* convex (outer) and concave (inner) corners.
*/
internal class Corner(
- cubics: List<Cubic>,
+ polygon: Polygon,
+ cubicIndices: List<Int>,
// TODO: parameters here should be immutable
val vertex: PointF,
val roundedCenter: PointF,
val convex: Boolean = true
-) : Feature(cubics) {
- constructor(source: Corner) : this(
- source.cubics,
+) : Feature(polygon, cubicIndices) {
+ constructor(polygon: Polygon, source: Corner) : this(
+ polygon,
+ source.cubicIndices,
source.vertex,
source.roundedCenter,
source.convex
)
+
+ override fun transform(matrix: Matrix) {
+ val tempPoints = floatArrayOf(vertex.x, vertex.y, roundedCenter.x, roundedCenter.y)
+ matrix.mapPoints(tempPoints)
+ vertex.set(tempPoints[0], tempPoints[1])
+ roundedCenter.set(tempPoints[2], tempPoints[3])
+ }
}
/**
diff --git a/health/connect/connect-client/src/main/java/androidx/health/platform/client/SdkConfig.java b/health/connect/connect-client/src/main/java/androidx/health/platform/client/SdkConfig.java
index 3e2ec2d..7629a30 100644
--- a/health/connect/connect-client/src/main/java/androidx/health/platform/client/SdkConfig.java
+++ b/health/connect/connect-client/src/main/java/androidx/health/platform/client/SdkConfig.java
@@ -25,7 +25,7 @@
@RestrictTo(RestrictTo.Scope.LIBRARY)
public final class SdkConfig {
// should be increased everytime a new SDK is released
- public static final int SDK_VERSION = 10;
+ public static final int SDK_VERSION = 11;
private SdkConfig() {}
}
diff --git a/lifecycle/lifecycle-viewmodel-compose/src/androidTest/java/androidx/lifecycle/viewmodel/compose/ViewModelTest.kt b/lifecycle/lifecycle-viewmodel-compose/src/androidTest/java/androidx/lifecycle/viewmodel/compose/ViewModelTest.kt
index c067c51..3b02e84 100644
--- a/lifecycle/lifecycle-viewmodel-compose/src/androidTest/java/androidx/lifecycle/viewmodel/compose/ViewModelTest.kt
+++ b/lifecycle/lifecycle-viewmodel-compose/src/androidTest/java/androidx/lifecycle/viewmodel/compose/ViewModelTest.kt
@@ -270,6 +270,6 @@
val store = ViewModelStore()
val factory = FakeViewModelProviderFactory()
- override fun getViewModelStore(): ViewModelStore = store
+ override val viewModelStore: ViewModelStore = store
override val defaultViewModelProviderFactory = factory
}
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/build.gradle b/lifecycle/lifecycle-viewmodel-savedstate/build.gradle
index 3ceb0b3..a88aecc 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/build.gradle
+++ b/lifecycle/lifecycle-viewmodel-savedstate/build.gradle
@@ -52,10 +52,6 @@
constraints {
implementation(project(":lifecycle:lifecycle-livedata-core"))
implementation(project(":lifecycle:lifecycle-viewmodel"))
- // this syntax is a temporary workout to allow project dependency on cross-project-set
- // i.e. COMPOSE + MAIN project sets
- // update syntax when b/239979823 is fixed
- implementation("androidx.lifecycle:lifecycle-viewmodel-compose:${androidx.LibraryVersions.LIFECYCLE}")
}
}
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/TestComponent.kt b/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/TestComponent.kt
index 1f7b190..efdb532 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/TestComponent.kt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/TestComponent.kt
@@ -49,7 +49,7 @@
override val savedStateRegistry: SavedStateRegistry
get() = savedStateController.savedStateRegistry
- override fun getViewModelStore(): ViewModelStore = vmStore
+ override val viewModelStore: ViewModelStore = vmStore
fun resume() {
lifecycleRegistry.currentState = Lifecycle.State.RESUMED
diff --git a/lifecycle/lifecycle-viewmodel/api/current.txt b/lifecycle/lifecycle-viewmodel/api/current.txt
index 75944f4..f8457f6 100644
--- a/lifecycle/lifecycle-viewmodel/api/current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/current.txt
@@ -80,6 +80,7 @@
public interface ViewModelStoreOwner {
method public androidx.lifecycle.ViewModelStore getViewModelStore();
+ property public abstract androidx.lifecycle.ViewModelStore viewModelStore;
}
public final class ViewTreeViewModelKt {
diff --git a/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_current.txt b/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_current.txt
index 75944f4..f8457f6 100644
--- a/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/public_plus_experimental_current.txt
@@ -80,6 +80,7 @@
public interface ViewModelStoreOwner {
method public androidx.lifecycle.ViewModelStore getViewModelStore();
+ property public abstract androidx.lifecycle.ViewModelStore viewModelStore;
}
public final class ViewTreeViewModelKt {
diff --git a/lifecycle/lifecycle-viewmodel/api/restricted_current.txt b/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
index 75944f4..f8457f6 100644
--- a/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
@@ -80,6 +80,7 @@
public interface ViewModelStoreOwner {
method public androidx.lifecycle.ViewModelStore getViewModelStore();
+ property public abstract androidx.lifecycle.ViewModelStore viewModelStore;
}
public final class ViewTreeViewModelKt {
diff --git a/lifecycle/lifecycle-viewmodel/src/androidTest/java/androidx/lifecycle/ViewTreeViewModelStoreOwnerTest.kt b/lifecycle/lifecycle-viewmodel/src/androidTest/java/androidx/lifecycle/ViewTreeViewModelStoreOwnerTest.kt
index 2fd80c7..6424d49 100644
--- a/lifecycle/lifecycle-viewmodel/src/androidTest/java/androidx/lifecycle/ViewTreeViewModelStoreOwnerTest.kt
+++ b/lifecycle/lifecycle-viewmodel/src/androidTest/java/androidx/lifecycle/ViewTreeViewModelStoreOwnerTest.kt
@@ -133,8 +133,9 @@
}
internal class FakeViewModelStoreOwner : ViewModelStoreOwner {
- override fun getViewModelStore(): ViewModelStore {
- throw UnsupportedOperationException("not a real ViewModelStoreOwner")
- }
+ override val viewModelStore: ViewModelStore
+ get() {
+ throw UnsupportedOperationException("not a real ViewModelStoreOwner")
+ }
}
}
diff --git a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelStoreOwner.java b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelStoreOwner.kt
similarity index 64%
rename from lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelStoreOwner.java
rename to lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelStoreOwner.kt
index 19152be..5296800 100644
--- a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelStoreOwner.java
+++ b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelStoreOwner.kt
@@ -13,27 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package androidx.lifecycle;
-
-import androidx.annotation.NonNull;
+package androidx.lifecycle
/**
- * A scope that owns {@link ViewModelStore}.
- * <p>
+ * A scope that owns [ViewModelStore].
+ *
* A responsibility of an implementation of this interface is to retain owned ViewModelStore
- * during the configuration changes and call {@link ViewModelStore#clear()}, when this scope is
+ * during the configuration changes and call [ViewModelStore.clear], when this scope is
* going to be destroyed.
*
* @see ViewTreeViewModelStoreOwner
*/
-@SuppressWarnings("WeakerAccess")
-public interface ViewModelStoreOwner {
+interface ViewModelStoreOwner {
+
/**
- * Returns owned {@link ViewModelStore}
- *
- * @return a {@code ViewModelStore}
+ * The owned [ViewModelStore]
*/
- @NonNull
- ViewModelStore getViewModelStore();
-}
+ val viewModelStore: ViewModelStore
+}
\ No newline at end of file
diff --git a/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.kt b/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.kt
index 2536918..934878d 100644
--- a/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.kt
+++ b/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.kt
@@ -62,8 +62,7 @@
@Test
fun testOwnedBy() {
- val store = ViewModelStore()
- val owner = ViewModelStoreOwner { store }
+ val owner = FakeViewModelStoreOwner()
val provider = ViewModelProvider(owner, ViewModelProvider.NewInstanceFactory())
val viewModel = provider[ViewModel1::class.java]
assertThat(viewModel).isSameInstanceAs(provider[ViewModel1::class.java])
@@ -82,8 +81,7 @@
@Test
fun testKeyedFactory() {
- val store = ViewModelStore()
- val owner = ViewModelStoreOwner { store }
+ val owner = FakeViewModelStoreOwner()
val explicitlyKeyed: ViewModelProvider.Factory = object : ViewModelProvider.Factory {
override fun <T : ViewModel> create(
modelClass: Class<T>,
@@ -172,13 +170,16 @@
private val mStore: ViewModelStore,
private val mFactory: ViewModelProvider.Factory
) : ViewModelStoreOwner, HasDefaultViewModelProviderFactory {
- override fun getViewModelStore(): ViewModelStore {
- return mStore
- }
-
+ override val viewModelStore: ViewModelStore = mStore
override val defaultViewModelProviderFactory = mFactory
}
+ class FakeViewModelStoreOwner internal constructor(
+ store: ViewModelStore = ViewModelStore()
+ ) : ViewModelStoreOwner {
+ override val viewModelStore: ViewModelStore = store
+ }
+
open class ViewModel1 : ViewModel() {
var cleared = false
override fun onCleared() {
@@ -197,7 +198,7 @@
internal open class ViewModelStoreOwnerWithCreationExtras : ViewModelStoreOwner,
HasDefaultViewModelProviderFactory {
- private val viewModelStore = ViewModelStore()
+ private val _viewModelStore = ViewModelStore()
override val defaultViewModelProviderFactory: ViewModelProvider.Factory
get() = throw UnsupportedOperationException()
@@ -208,9 +209,7 @@
return extras
}
- override fun getViewModelStore(): ViewModelStore {
- return viewModelStore
- }
+ override val viewModelStore: ViewModelStore = _viewModelStore
}
}
diff --git a/navigation/navigation-common/api/current.txt b/navigation/navigation-common/api/current.txt
index 34e00ed..a0905df 100644
--- a/navigation/navigation-common/api/current.txt
+++ b/navigation/navigation-common/api/current.txt
@@ -129,6 +129,7 @@
property public final String id;
property public final androidx.lifecycle.SavedStateHandle savedStateHandle;
property public androidx.savedstate.SavedStateRegistry savedStateRegistry;
+ property public androidx.lifecycle.ViewModelStore viewModelStore;
}
public final class NavDeepLink {
diff --git a/navigation/navigation-common/api/public_plus_experimental_current.txt b/navigation/navigation-common/api/public_plus_experimental_current.txt
index 34e00ed..a0905df 100644
--- a/navigation/navigation-common/api/public_plus_experimental_current.txt
+++ b/navigation/navigation-common/api/public_plus_experimental_current.txt
@@ -129,6 +129,7 @@
property public final String id;
property public final androidx.lifecycle.SavedStateHandle savedStateHandle;
property public androidx.savedstate.SavedStateRegistry savedStateRegistry;
+ property public androidx.lifecycle.ViewModelStore viewModelStore;
}
public final class NavDeepLink {
diff --git a/navigation/navigation-common/api/restricted_current.txt b/navigation/navigation-common/api/restricted_current.txt
index 34e00ed..a0905df 100644
--- a/navigation/navigation-common/api/restricted_current.txt
+++ b/navigation/navigation-common/api/restricted_current.txt
@@ -129,6 +129,7 @@
property public final String id;
property public final androidx.lifecycle.SavedStateHandle savedStateHandle;
property public androidx.savedstate.SavedStateRegistry savedStateRegistry;
+ property public androidx.lifecycle.ViewModelStore viewModelStore;
}
public final class NavDeepLink {
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt b/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt
index 3f0656e..953aae9 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavBackStackEntry.kt
@@ -197,29 +197,30 @@
}
}
- /**
- * {@inheritDoc}
- *
- * @throws IllegalStateException if called before the [lifecycle] has moved to
- * [Lifecycle.State.CREATED] or before the [androidx.navigation.NavHost] has called
- * [androidx.navigation.NavHostController.setViewModelStore].
- */
- public override fun getViewModelStore(): ViewModelStore {
- check(savedStateRegistryAttached) {
- "You cannot access the NavBackStackEntry's ViewModels until it is added to " +
- "the NavController's back stack (i.e., the Lifecycle of the NavBackStackEntry " +
- "reaches the CREATED state)."
+ public override val viewModelStore: ViewModelStore
+ /**
+ * {@inheritDoc}
+ *
+ * @throws IllegalStateException if called before the [lifecycle] has moved to
+ * [Lifecycle.State.CREATED] or before the [androidx.navigation.NavHost] has called
+ * [androidx.navigation.NavHostController.setViewModelStore].
+ */
+ get() {
+ check(savedStateRegistryAttached) {
+ "You cannot access the NavBackStackEntry's ViewModels until it is added to " +
+ "the NavController's back stack (i.e., the Lifecycle of the " +
+ "NavBackStackEntry reaches the CREATED state)."
+ }
+ check(lifecycle.currentState != Lifecycle.State.DESTROYED) {
+ "You cannot access the NavBackStackEntry's ViewModels after the " +
+ "NavBackStackEntry is destroyed."
+ }
+ checkNotNull(viewModelStoreProvider) {
+ "You must call setViewModelStore() on your NavHostController before " +
+ "accessing the ViewModelStore of a navigation graph."
+ }
+ return viewModelStoreProvider.getViewModelStore(id)
}
- check(lifecycle.currentState != Lifecycle.State.DESTROYED) {
- "You cannot access the NavBackStackEntry's ViewModels after the " +
- "NavBackStackEntry is destroyed."
- }
- checkNotNull(viewModelStoreProvider) {
- "You must call setViewModelStore() on your NavHostController before accessing the " +
- "ViewModelStore of a navigation graph."
- }
- return viewModelStoreProvider.getViewModelStore(id)
- }
override val defaultViewModelProviderFactory: ViewModelProvider.Factory = defaultFactory
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/TestUtils.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/TestUtils.kt
index 57fd35f..94f7888 100644
--- a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/TestUtils.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/TestUtils.kt
@@ -16,7 +16,7 @@
package androidx.privacysandbox.tools.apicompiler
-import androidx.privacysandbox.tools.apicompiler.util.allTestLibraryStubs
+import androidx.privacysandbox.tools.testing.allTestLibraryStubs
import androidx.privacysandbox.tools.testing.CompilationTestHelper
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.compiler.TestCompilationResult
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/util/KspTestRunner.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/util/KspTestRunner.kt
index 57468ca..31aee1f2 100644
--- a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/util/KspTestRunner.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/util/KspTestRunner.kt
@@ -16,10 +16,11 @@
package androidx.privacysandbox.tools.apicompiler.util
-import androidx.privacysandbox.tools.core.model.ParsedApi
import androidx.privacysandbox.tools.apicompiler.parser.ApiParser
-import androidx.privacysandbox.tools.testing.CompilationTestHelper.assertThat
+import androidx.privacysandbox.tools.core.model.ParsedApi
import androidx.privacysandbox.tools.testing.CompilationResultSubject
+import androidx.privacysandbox.tools.testing.CompilationTestHelper.assertThat
+import androidx.privacysandbox.tools.testing.allTestLibraryStubs
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.compiler.TestCompilationArguments
import androidx.room.compiler.processing.util.compiler.compile
diff --git a/privacysandbox/tools/tools-apigenerator/src/main/java/androidx/privacysandbox/tools/apigenerator/InterfaceFileGenerator.kt b/privacysandbox/tools/tools-apigenerator/src/main/java/androidx/privacysandbox/tools/apigenerator/InterfaceFileGenerator.kt
index 02ecc7d..e7e87a0 100644
--- a/privacysandbox/tools/tools-apigenerator/src/main/java/androidx/privacysandbox/tools/apigenerator/InterfaceFileGenerator.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/main/java/androidx/privacysandbox/tools/apigenerator/InterfaceFileGenerator.kt
@@ -33,12 +33,13 @@
fun generate(annotatedInterface: AnnotatedInterface): FileSpec {
val annotatedInterfaceType =
TypeSpec.interfaceBuilder(annotatedInterface.type.poetClassName()).build {
+ addSuperinterfaces(annotatedInterface.superTypes.map { it.poetClassName() })
addFunctions(annotatedInterface.methods.map(::generateInterfaceMethod))
}
return FileSpec.get(annotatedInterface.type.packageName, annotatedInterfaceType)
.toBuilder().build {
- addCommonSettings()
+ addCommonSettings()
}
}
diff --git a/privacysandbox/tools/tools-apigenerator/src/main/java/androidx/privacysandbox/tools/apigenerator/parser/ApiStubParser.kt b/privacysandbox/tools/tools-apigenerator/src/main/java/androidx/privacysandbox/tools/apigenerator/parser/ApiStubParser.kt
index fd952ab..f0bb98a 100644
--- a/privacysandbox/tools/tools-apigenerator/src/main/java/androidx/privacysandbox/tools/apigenerator/parser/ApiStubParser.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/main/java/androidx/privacysandbox/tools/apigenerator/parser/ApiStubParser.kt
@@ -22,6 +22,7 @@
import androidx.privacysandbox.tools.core.model.Parameter
import androidx.privacysandbox.tools.core.model.ParsedApi
import androidx.privacysandbox.tools.core.model.Type
+import androidx.privacysandbox.tools.core.model.Types
import androidx.privacysandbox.tools.core.model.ValueProperty
import androidx.privacysandbox.tools.core.validator.ModelValidator
import java.nio.file.Path
@@ -55,6 +56,7 @@
private fun parseInterface(service: KmClass, annotationName: String): AnnotatedInterface {
val type = parseClassName(service.name)
+ val superTypes = service.supertypes.map(this::parseType).filterNot { it == Types.any }
if (!Flag.Class.IS_INTERFACE(service.flags)) {
throw PrivacySandboxParsingException(
@@ -65,6 +67,7 @@
return AnnotatedInterface(
type = type,
+ superTypes = superTypes,
methods = service.functions.map(this::parseMethod),
)
}
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/BaseApiGeneratorTest.kt b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/BaseApiGeneratorTest.kt
index 860b155..73ce728 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/BaseApiGeneratorTest.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/BaseApiGeneratorTest.kt
@@ -18,6 +18,7 @@
import androidx.privacysandbox.tools.core.Metadata
import androidx.privacysandbox.tools.testing.CompilationTestHelper.assertCompiles
+import androidx.privacysandbox.tools.testing.allTestLibraryStubs
import androidx.privacysandbox.tools.testing.hasAllExpectedGeneratedSourceFilesAndContent
import androidx.privacysandbox.tools.testing.loadSourcesFromDirectory
import androidx.room.compiler.processing.util.Source
@@ -49,7 +50,7 @@
@Test
fun generatedApi_compiles() {
- assertCompiles(generatedSources)
+ assertCompiles(generatedSources + allTestLibraryStubs)
}
@Test
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/TestUtils.kt b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/TestUtils.kt
index fade128..ea01aa8 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/TestUtils.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/TestUtils.kt
@@ -18,6 +18,7 @@
import androidx.privacysandbox.tools.apipackager.PrivacySandboxApiPackager
import androidx.privacysandbox.tools.testing.CompilationTestHelper.assertCompiles
+import androidx.privacysandbox.tools.testing.allTestLibraryStubs
import androidx.room.compiler.processing.util.Source
import androidx.room.compiler.processing.util.compiler.TestCompilationResult
import java.nio.file.Files.createTempDirectory
@@ -31,13 +32,17 @@
*
* @param descriptorResources map of extra resources that will be added to descriptors jar keyed by
* their relative path.
+ * @param addLibraryStubs whether to include latest Android platform API stubs that support the
+ * Privacy Sandbox.
*/
fun compileIntoInterfaceDescriptorsJar(
sources: List<Source>,
descriptorResources: Map<Path, ByteArray> = mapOf(),
+ addLibraryStubs: Boolean = true,
): Path {
+ val testSources = if (addLibraryStubs) sources + allTestLibraryStubs else sources
val tempDir = createTempDirectory("compile").also { it.toFile().deleteOnExit() }
- val result = assertCompiles(sources.toList())
+ val result = assertCompiles(testSources.toList())
val sdkInterfaceDescriptors = tempDir.resolve("sdk-interface-descriptors.jar")
val outputClasspath = mergedClasspath(result)
descriptorResources.forEach { (relativePath, contents) ->
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/parser/ApiStubParserTest.kt b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/parser/ApiStubParserTest.kt
index efc6bf0..1909e41 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/parser/ApiStubParserTest.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/java/androidx/privacysandbox/tools/apigenerator/parser/ApiStubParserTest.kt
@@ -27,6 +27,7 @@
import androidx.privacysandbox.tools.core.model.Types.asNullable
import androidx.privacysandbox.tools.core.model.ValueProperty
import androidx.privacysandbox.tools.testing.CompilationTestHelper.assertCompiles
+import androidx.privacysandbox.tools.testing.allTestLibraryStubs
import androidx.room.compiler.processing.util.Source
import androidx.testutils.assertThrows
import com.google.common.truth.Truth.assertThat
@@ -39,34 +40,47 @@
@Test
fun annotatedInterface_isParsed() {
val source = Source.kotlin(
- "com/mysdk/TestSandboxSdk.kt", """
- package com.mysdk
- import androidx.privacysandbox.tools.PrivacySandboxCallback
- import androidx.privacysandbox.tools.PrivacySandboxInterface
- import androidx.privacysandbox.tools.PrivacySandboxService
- import androidx.privacysandbox.tools.PrivacySandboxValue
- @PrivacySandboxService
- interface MySdk {
- fun doSomething(magicNumber: Int, awesomeString: String?)
- suspend fun getPayload(request: PayloadRequest): PayloadResponse
- suspend fun getInterface(): MyInterface
- suspend fun processList(list: List<Long>): List<Long>
- }
- @PrivacySandboxInterface
- interface MyInterface {
- suspend fun getMorePayload(request: PayloadRequest): PayloadResponse
- }
- @PrivacySandboxValue
- data class PayloadType(val size: Long, val appId: String)
- @PrivacySandboxValue
- data class PayloadResponse(val url: String)
- @PrivacySandboxValue
- data class PayloadRequest(val type: PayloadType)
- @PrivacySandboxCallback
- interface CustomCallback {
- fun onComplete(status: Int)
- }
- """,
+ "com/mysdk/TestSandboxSdk.kt",
+ """
+ |package com.mysdk
+ |
+ |import androidx.privacysandbox.tools.PrivacySandboxCallback
+ |import androidx.privacysandbox.tools.PrivacySandboxInterface
+ |import androidx.privacysandbox.tools.PrivacySandboxService
+ |import androidx.privacysandbox.tools.PrivacySandboxValue
+ |import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+ |
+ |@PrivacySandboxService
+ |interface MySdk {
+ | fun doSomething(magicNumber: Int, awesomeString: String?)
+ | suspend fun getPayload(request: PayloadRequest): PayloadResponse
+ | suspend fun getInterface(): MyInterface
+ | suspend fun getUiInterface(): MyUiInterface
+ | suspend fun processList(list: List<Long>): List<Long>
+ |}
+ |
+ |@PrivacySandboxInterface
+ |interface MyInterface {
+ | suspend fun getMorePayload(request: PayloadRequest): PayloadResponse
+ |}
+ |
+ |@PrivacySandboxInterface
+ |interface MyUiInterface : SandboxedUiAdapter {}
+ |
+ |@PrivacySandboxValue
+ |data class PayloadType(val size: Long, val appId: String)
+ |
+ |@PrivacySandboxValue
+ |data class PayloadResponse(val url: String)
+ |
+ |@PrivacySandboxValue
+ |data class PayloadRequest(val type: PayloadType)
+ |
+ |@PrivacySandboxCallback
+ |interface CustomCallback {
+ | fun onComplete(status: Int)
+ |}
+ """.trimMargin(),
)
val expectedPayloadType = AnnotatedValue(
@@ -122,6 +136,12 @@
isSuspend = true,
),
Method(
+ name = "getUiInterface",
+ parameters = listOf(),
+ returnType = Type("com.mysdk", "MyUiInterface"),
+ isSuspend = true,
+ ),
+ Method(
name = "processList",
parameters = listOf(
Parameter(
@@ -134,7 +154,7 @@
),
)
)
- val expectedInterface =
+ val expectedInterfaces = listOf(
AnnotatedInterface(
type = Type(packageName = "com.mysdk", simpleName = "MyInterface"),
methods = listOf(
@@ -150,7 +170,13 @@
isSuspend = true,
)
)
- )
+ ),
+ AnnotatedInterface(
+ type = Type(packageName = "com.mysdk", simpleName = "MyUiInterface"),
+ superTypes = listOf(Types.sandboxedUiAdapter),
+ methods = listOf(),
+ ),
+ )
val expectedCallback = AnnotatedInterface(
type = Type(packageName = "com.mysdk", simpleName = "CustomCallback"),
methods = listOf(
@@ -176,7 +202,7 @@
expectedPayloadResponse,
)
assertThat(actualApi.callbacks).containsExactly(expectedCallback)
- assertThat(actualApi.interfaces).containsExactly(expectedInterface)
+ assertThat(actualApi.interfaces).containsExactlyElementsIn(expectedInterfaces)
}
@Test
@@ -378,7 +404,7 @@
}
private fun compileAndParseApi(vararg sources: Source): ParsedApi {
- val classpath = mergedClasspath(assertCompiles(sources.toList()))
+ val classpath = mergedClasspath(assertCompiles(sources.toList() + allTestLibraryStubs))
return ApiStubParser.parse(classpath)
}
}
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/input/com/sdk/MySdk.kt b/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/input/com/sdk/MySdk.kt
index 8ace244..b64faf5 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/input/com/sdk/MySdk.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/input/com/sdk/MySdk.kt
@@ -2,6 +2,7 @@
import androidx.privacysandbox.tools.PrivacySandboxInterface
import androidx.privacysandbox.tools.PrivacySandboxService
+import androidx.privacysandbox.ui.core.SandboxedUiAdapter
@PrivacySandboxService
interface MySdk {
@@ -20,6 +21,6 @@
}
@PrivacySandboxInterface
-interface MySecondInterface {
+interface MySecondInterface : SandboxedUiAdapter {
fun doStuff()
}
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/output/com/sdk/MySecondInterface.kt b/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/output/com/sdk/MySecondInterface.kt
index b858ed5..0505e08 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/output/com/sdk/MySecondInterface.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/output/com/sdk/MySecondInterface.kt
@@ -1,5 +1,7 @@
package com.sdk
-public interface MySecondInterface {
+import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+
+public interface MySecondInterface : SandboxedUiAdapter {
public fun doStuff(): Unit
}
diff --git a/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/output/com/sdk/MySecondInterfaceClientProxy.kt b/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/output/com/sdk/MySecondInterfaceClientProxy.kt
index 67e7d28a..9880002 100644
--- a/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/output/com/sdk/MySecondInterfaceClientProxy.kt
+++ b/privacysandbox/tools/tools-apigenerator/src/test/test-data/interfaces/output/com/sdk/MySecondInterfaceClientProxy.kt
@@ -1,9 +1,27 @@
package com.sdk
+import android.content.Context
+import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+import androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient
+import java.util.concurrent.Executor
+
public class MySecondInterfaceClientProxy(
public val remote: IMySecondInterface,
+ public val sandboxedUiAdapter: SandboxedUiAdapter,
) : MySecondInterface {
public override fun doStuff(): Unit {
remote.doStuff()
}
+
+ public override fun openSession(
+ context: Context,
+ initialWidth: Int,
+ initialHeight: Int,
+ isZOrderOnTop: Boolean,
+ clientExecutor: Executor,
+ client: SandboxedUiAdapter.SessionClient,
+ ): Unit {
+ sandboxedUiAdapter.openSession(context, initialWidth, initialHeight, isZOrderOnTop,
+ clientExecutor, client)
+ }
}
diff --git a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/ClientProxyTypeGenerator.kt b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/ClientProxyTypeGenerator.kt
index 43b9abe..49d0853 100644
--- a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/ClientProxyTypeGenerator.kt
+++ b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/generator/ClientProxyTypeGenerator.kt
@@ -21,11 +21,13 @@
import androidx.privacysandbox.tools.core.generator.SpecNames.suspendCancellableCoroutineMethod
import androidx.privacysandbox.tools.core.model.AnnotatedInterface
import androidx.privacysandbox.tools.core.model.Method
+import androidx.privacysandbox.tools.core.model.Types
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.CodeBlock
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.KModifier
+import com.squareup.kotlinpoet.ParameterSpec
import com.squareup.kotlinpoet.PropertySpec
import com.squareup.kotlinpoet.TypeSpec
import com.squareup.kotlinpoet.joinToCode
@@ -34,24 +36,34 @@
private val basePackageName: String,
private val binderCodeConverter: BinderCodeConverter
) {
- private val cancellationSignalClassName =
- ClassName(basePackageName, "ICancellationSignal")
+ private val cancellationSignalClassName = ClassName(basePackageName, "ICancellationSignal")
+ private val sandboxedUiAdapterPropertyName = "sandboxedUiAdapter"
fun generate(annotatedInterface: AnnotatedInterface): FileSpec {
val className = annotatedInterface.clientProxyNameSpec().simpleName
val remoteBinderClassName = annotatedInterface.aidlType().innerType.poetTypeName()
+ val inheritsUiAdapter = annotatedInterface.superTypes.contains(Types.sandboxedUiAdapter)
val classSpec = TypeSpec.classBuilder(className).build {
addSuperinterface(annotatedInterface.type.poetTypeName())
- primaryConstructor(
- listOf(
+ primaryConstructor(buildList {
+ add(
PropertySpec.builder("remote", remoteBinderClassName)
.addModifiers(KModifier.PUBLIC).build()
)
- )
+ if (inheritsUiAdapter) add(
+ PropertySpec.builder(
+ sandboxedUiAdapterPropertyName, Types.sandboxedUiAdapter.poetTypeName()
+ ).addModifiers(KModifier.PUBLIC).build()
+ )
+ })
addFunctions(annotatedInterface.methods.map(::toFunSpec))
+
+ if (inheritsUiAdapter) {
+ addFunction(generateOpenSession())
+ }
}
return FileSpec.builder(annotatedInterface.type.packageName, className).build {
@@ -94,6 +106,28 @@
addCode(generateRemoteCall(method))
}
+ private fun generateOpenSession() = FunSpec.builder("openSession").build {
+ addModifiers(KModifier.OVERRIDE)
+ addParameters(
+ listOf(
+ ParameterSpec("context", ClassName("android.content", "Context")),
+ ParameterSpec("initialWidth", Types.int.poetClassName()),
+ ParameterSpec("initialHeight", Types.int.poetClassName()),
+ ParameterSpec("isZOrderOnTop", Types.boolean.poetClassName()),
+ ParameterSpec("clientExecutor", ClassName("java.util.concurrent", "Executor")),
+ ParameterSpec(
+ "client", ClassName(
+ "androidx.privacysandbox.ui.core", "SandboxedUiAdapter.SessionClient"
+ )
+ ),
+ )
+ )
+ addStatement(
+ "$sandboxedUiAdapterPropertyName.openSession(context, initialWidth, initialHeight, " +
+ "isZOrderOnTop, clientExecutor, client)"
+ )
+ }
+
private fun generateTransactionCallbackObject(method: Method) = CodeBlock.builder().build {
val transactionCallbackClassName = ClassName(
basePackageName,
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/util/LibraryStubs.kt b/privacysandbox/tools/tools-testing/src/main/java/androidx/privacysandbox/tools/testing/LibraryStubs.kt
similarity index 98%
rename from privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/util/LibraryStubs.kt
rename to privacysandbox/tools/tools-testing/src/main/java/androidx/privacysandbox/tools/testing/LibraryStubs.kt
index b9e9314..b51203a 100644
--- a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/util/LibraryStubs.kt
+++ b/privacysandbox/tools/tools-testing/src/main/java/androidx/privacysandbox/tools/testing/LibraryStubs.kt
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package androidx.privacysandbox.tools.apicompiler.util
+package androidx.privacysandbox.tools.testing
import androidx.room.compiler.processing.util.Source
diff --git a/privacysandbox/ui/ui-client/api/current.txt b/privacysandbox/ui/ui-client/api/current.txt
index e6f50d0..e6beb91 100644
--- a/privacysandbox/ui/ui-client/api/current.txt
+++ b/privacysandbox/ui/ui-client/api/current.txt
@@ -1 +1,10 @@
// Signature format: 4.0
+package androidx.privacysandbox.ui.client {
+
+ @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public final class SandboxedUiAdapterFactory {
+ method public androidx.privacysandbox.ui.core.SandboxedUiAdapter createFromCoreLibInfo(android.os.Bundle coreLibInfo);
+ field public static final androidx.privacysandbox.ui.client.SandboxedUiAdapterFactory INSTANCE;
+ }
+
+}
+
diff --git a/privacysandbox/ui/ui-client/api/public_plus_experimental_current.txt b/privacysandbox/ui/ui-client/api/public_plus_experimental_current.txt
index e6f50d0..e6beb91 100644
--- a/privacysandbox/ui/ui-client/api/public_plus_experimental_current.txt
+++ b/privacysandbox/ui/ui-client/api/public_plus_experimental_current.txt
@@ -1 +1,10 @@
// Signature format: 4.0
+package androidx.privacysandbox.ui.client {
+
+ @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public final class SandboxedUiAdapterFactory {
+ method public androidx.privacysandbox.ui.core.SandboxedUiAdapter createFromCoreLibInfo(android.os.Bundle coreLibInfo);
+ field public static final androidx.privacysandbox.ui.client.SandboxedUiAdapterFactory INSTANCE;
+ }
+
+}
+
diff --git a/privacysandbox/ui/ui-client/api/restricted_current.txt b/privacysandbox/ui/ui-client/api/restricted_current.txt
index e6f50d0..e6beb91 100644
--- a/privacysandbox/ui/ui-client/api/restricted_current.txt
+++ b/privacysandbox/ui/ui-client/api/restricted_current.txt
@@ -1 +1,10 @@
// Signature format: 4.0
+package androidx.privacysandbox.ui.client {
+
+ @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public final class SandboxedUiAdapterFactory {
+ method public androidx.privacysandbox.ui.core.SandboxedUiAdapter createFromCoreLibInfo(android.os.Bundle coreLibInfo);
+ field public static final androidx.privacysandbox.ui.client.SandboxedUiAdapterFactory INSTANCE;
+ }
+
+}
+
diff --git a/privacysandbox/ui/ui-client/build.gradle b/privacysandbox/ui/ui-client/build.gradle
index 82beabb..918c043 100644
--- a/privacysandbox/ui/ui-client/build.gradle
+++ b/privacysandbox/ui/ui-client/build.gradle
@@ -24,7 +24,8 @@
dependencies {
api(libs.kotlinStdlib)
- // Add dependencies here
+ implementation project(path: ':privacysandbox:ui:ui-core')
+ implementation project(path: ':annotation:annotation')
}
android {
diff --git a/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/SandboxedUiAdapterFactory.kt b/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/SandboxedUiAdapterFactory.kt
new file mode 100644
index 0000000..f87ab3d
--- /dev/null
+++ b/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/SandboxedUiAdapterFactory.kt
@@ -0,0 +1,119 @@
+/*
+ * 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.privacysandbox.ui.client
+
+import android.content.Context
+import android.hardware.display.DisplayManager
+import android.os.Binder
+import android.os.Build
+import android.os.Bundle
+import android.view.Display
+import android.view.SurfaceControlViewHost
+import android.view.SurfaceView
+import android.view.View
+import androidx.annotation.RequiresApi
+import androidx.privacysandbox.ui.core.IRemoteSessionClient
+import androidx.privacysandbox.ui.core.IRemoteSessionController
+import androidx.privacysandbox.ui.core.ISandboxedUiAdapter
+import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+import java.util.concurrent.Executor
+
+/**
+ * Provides an adapter created from the supplied Bundle which acts as a proxy between the host app
+ * and Binder provided by the provider of content.
+ * @throws IllegalArgumentException if CoreLibInfo does not contain a Binder with the key
+ * uiAdapterBinder
+ */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+object SandboxedUiAdapterFactory {
+ // Bundle key is a binary compatibility requirement
+ private const val UI_ADAPTER_BINDER = "uiAdapterBinder"
+ fun createFromCoreLibInfo(coreLibInfo: Bundle): SandboxedUiAdapter {
+ val uiAdapterBinder = requireNotNull(coreLibInfo.getBinder(UI_ADAPTER_BINDER)) {
+ "Invalid CoreLibInfo bundle, missing $UI_ADAPTER_BINDER."
+ }
+ val adapterInterface = ISandboxedUiAdapter.Stub.asInterface(
+ uiAdapterBinder
+ )
+ return RemoteAdapter(adapterInterface)
+ }
+
+ private class RemoteAdapter(private val adapterInterface: ISandboxedUiAdapter) :
+ SandboxedUiAdapter {
+
+ override fun openSession(
+ context: Context,
+ initialWidth: Int,
+ initialHeight: Int,
+ isZOrderOnTop: Boolean,
+ clientExecutor: Executor,
+ client: SandboxedUiAdapter.SessionClient
+ ) {
+ val mDisplayManager =
+ context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
+ val displayId = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY).displayId
+
+ adapterInterface.openRemoteSession(
+ Binder(), // Host Token
+ displayId,
+ initialWidth,
+ initialHeight,
+ isZOrderOnTop,
+ RemoteSessionClient(context, client, clientExecutor)
+ )
+ }
+
+ class RemoteSessionClient(
+ val context: Context,
+ val client: SandboxedUiAdapter.SessionClient,
+ val clientExecutor: Executor
+ ) : IRemoteSessionClient.Stub() {
+
+ override fun onRemoteSessionOpened(
+ surfacePackage: SurfaceControlViewHost.SurfacePackage,
+ remoteSessionController: IRemoteSessionController,
+ isZOrderOnTop: Boolean
+ ) {
+ val surfaceView = SurfaceView(context)
+ surfaceView.setChildSurfacePackage(surfacePackage)
+ surfaceView.setZOrderOnTop(isZOrderOnTop)
+
+ clientExecutor.execute {
+ client.onSessionOpened(SessionImpl(surfaceView, remoteSessionController))
+ }
+ }
+
+ override fun onRemoteSessionError(errorString: String) {
+ clientExecutor.execute {
+ client.onSessionError(Throwable(errorString))
+ }
+ }
+ }
+
+ private class SessionImpl(
+ val surfaceView: SurfaceView,
+ val remoteSessionController: IRemoteSessionController
+ ) : SandboxedUiAdapter.Session {
+
+ override val view: View = surfaceView
+
+ override fun close() {
+ remoteSessionController.close()
+ }
+ }
+ }
+}
diff --git a/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/androidx-privacysandbox-ui-ui-client-documentation.md b/privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/androidx-privacysandbox-ui-ui-client-documentation.md
similarity index 100%
rename from privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/androidx-privacysandbox-ui-ui-client-documentation.md
rename to privacysandbox/ui/ui-client/src/main/java/androidx/privacysandbox/ui/client/androidx-privacysandbox-ui-ui-client-documentation.md
diff --git a/privacysandbox/ui/ui-core/api/current.txt b/privacysandbox/ui/ui-core/api/current.txt
index e6f50d0..3ab33d6 100644
--- a/privacysandbox/ui/ui-core/api/current.txt
+++ b/privacysandbox/ui/ui-core/api/current.txt
@@ -1 +1,27 @@
// Signature format: 4.0
+package androidx.privacysandbox.ui.core {
+
+ public interface SandboxedUiAdapter {
+ method public void openSession(android.content.Context context, int initialWidth, int initialHeight, boolean isZOrderOnTop, java.util.concurrent.Executor clientExecutor, androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient client);
+ }
+
+ public static interface SandboxedUiAdapter.Session {
+ method public void close();
+ method public android.view.View getView();
+ property public abstract android.view.View view;
+ }
+
+ public static interface SandboxedUiAdapter.SessionClient {
+ method public void onSessionError(Throwable throwable);
+ method public void onSessionOpened(androidx.privacysandbox.ui.core.SandboxedUiAdapter.Session session);
+ }
+
+ public final class SdkRuntimeUiLibVersions {
+ method public int getClientVersion();
+ property public final int clientVersion;
+ field public static final androidx.privacysandbox.ui.core.SdkRuntimeUiLibVersions INSTANCE;
+ field public static final int apiVersion = 1; // 0x1
+ }
+
+}
+
diff --git a/privacysandbox/ui/ui-core/api/public_plus_experimental_current.txt b/privacysandbox/ui/ui-core/api/public_plus_experimental_current.txt
index e6f50d0..3ab33d6 100644
--- a/privacysandbox/ui/ui-core/api/public_plus_experimental_current.txt
+++ b/privacysandbox/ui/ui-core/api/public_plus_experimental_current.txt
@@ -1 +1,27 @@
// Signature format: 4.0
+package androidx.privacysandbox.ui.core {
+
+ public interface SandboxedUiAdapter {
+ method public void openSession(android.content.Context context, int initialWidth, int initialHeight, boolean isZOrderOnTop, java.util.concurrent.Executor clientExecutor, androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient client);
+ }
+
+ public static interface SandboxedUiAdapter.Session {
+ method public void close();
+ method public android.view.View getView();
+ property public abstract android.view.View view;
+ }
+
+ public static interface SandboxedUiAdapter.SessionClient {
+ method public void onSessionError(Throwable throwable);
+ method public void onSessionOpened(androidx.privacysandbox.ui.core.SandboxedUiAdapter.Session session);
+ }
+
+ public final class SdkRuntimeUiLibVersions {
+ method public int getClientVersion();
+ property public final int clientVersion;
+ field public static final androidx.privacysandbox.ui.core.SdkRuntimeUiLibVersions INSTANCE;
+ field public static final int apiVersion = 1; // 0x1
+ }
+
+}
+
diff --git a/privacysandbox/ui/ui-core/api/restricted_current.txt b/privacysandbox/ui/ui-core/api/restricted_current.txt
index e6f50d0..3ab33d6 100644
--- a/privacysandbox/ui/ui-core/api/restricted_current.txt
+++ b/privacysandbox/ui/ui-core/api/restricted_current.txt
@@ -1 +1,27 @@
// Signature format: 4.0
+package androidx.privacysandbox.ui.core {
+
+ public interface SandboxedUiAdapter {
+ method public void openSession(android.content.Context context, int initialWidth, int initialHeight, boolean isZOrderOnTop, java.util.concurrent.Executor clientExecutor, androidx.privacysandbox.ui.core.SandboxedUiAdapter.SessionClient client);
+ }
+
+ public static interface SandboxedUiAdapter.Session {
+ method public void close();
+ method public android.view.View getView();
+ property public abstract android.view.View view;
+ }
+
+ public static interface SandboxedUiAdapter.SessionClient {
+ method public void onSessionError(Throwable throwable);
+ method public void onSessionOpened(androidx.privacysandbox.ui.core.SandboxedUiAdapter.Session session);
+ }
+
+ public final class SdkRuntimeUiLibVersions {
+ method public int getClientVersion();
+ property public final int clientVersion;
+ field public static final androidx.privacysandbox.ui.core.SdkRuntimeUiLibVersions INSTANCE;
+ field public static final int apiVersion = 1; // 0x1
+ }
+
+}
+
diff --git a/privacysandbox/ui/ui-core/build.gradle b/privacysandbox/ui/ui-core/build.gradle
index 4e0e9bd..f0b88cd 100644
--- a/privacysandbox/ui/ui-core/build.gradle
+++ b/privacysandbox/ui/ui-core/build.gradle
@@ -24,11 +24,21 @@
dependencies {
api(libs.kotlinStdlib)
- // Add dependencies here
+ implementation 'androidx.annotation:annotation:1.5.0'
+ androidTestImplementation(libs.junit)
+ androidTestImplementation(libs.kotlinStdlib)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.truth)
}
android {
namespace "androidx.privacysandbox.ui.core"
+ buildFeatures {
+ aidl = true
+ }
}
androidx {
diff --git a/privacysandbox/ui/ui-core/src/main/aidl/androidx/privacysandbox/ui/core/IRemoteSessionClient.aidl b/privacysandbox/ui/ui-core/src/main/aidl/androidx/privacysandbox/ui/core/IRemoteSessionClient.aidl
new file mode 100644
index 0000000..63a66c1
--- /dev/null
+++ b/privacysandbox/ui/ui-core/src/main/aidl/androidx/privacysandbox/ui/core/IRemoteSessionClient.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package androidx.privacysandbox.ui.core;
+
+import androidx.privacysandbox.ui.core.IRemoteSessionController;
+import android.view.SurfaceControlViewHost.SurfacePackage;
+
+/** @hide */
+oneway interface IRemoteSessionClient {
+ void onRemoteSessionOpened(in SurfacePackage surfacePackage,
+ IRemoteSessionController remoteSessionController, boolean isZOrderOnTop);
+ void onRemoteSessionError(String exception);
+}
\ No newline at end of file
diff --git a/privacysandbox/ui/ui-core/src/main/aidl/androidx/privacysandbox/ui/core/IRemoteSessionController.aidl b/privacysandbox/ui/ui-core/src/main/aidl/androidx/privacysandbox/ui/core/IRemoteSessionController.aidl
new file mode 100644
index 0000000..b64a992
--- /dev/null
+++ b/privacysandbox/ui/ui-core/src/main/aidl/androidx/privacysandbox/ui/core/IRemoteSessionController.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package androidx.privacysandbox.ui.core;
+
+/** @hide */
+oneway interface IRemoteSessionController {
+ void close();
+}
\ No newline at end of file
diff --git a/privacysandbox/ui/ui-core/src/main/aidl/androidx/privacysandbox/ui/core/ISandboxedUiAdapter.aidl b/privacysandbox/ui/ui-core/src/main/aidl/androidx/privacysandbox/ui/core/ISandboxedUiAdapter.aidl
new file mode 100644
index 0000000..a452da6
--- /dev/null
+++ b/privacysandbox/ui/ui-core/src/main/aidl/androidx/privacysandbox/ui/core/ISandboxedUiAdapter.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package androidx.privacysandbox.ui.core;
+
+import androidx.privacysandbox.ui.core.IRemoteSessionClient;
+import android.content.Context;
+
+/** @hide */
+oneway interface ISandboxedUiAdapter {
+ void openRemoteSession(
+ IBinder hostToken, int displayId, int initialWidth, int initialHeight, boolean isZOrderOnTop,
+ IRemoteSessionClient remoteSessionClient);
+}
\ No newline at end of file
diff --git a/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SandboxedUiAdapter.kt b/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SandboxedUiAdapter.kt
new file mode 100644
index 0000000..c6751e3
--- /dev/null
+++ b/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SandboxedUiAdapter.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.privacysandbox.ui.core
+
+import android.content.Context
+import android.view.View
+import java.util.concurrent.Executor
+
+/**
+ * An Adapter that provides content from a SandboxedSdk to be displayed as part of a host app's UI.
+ */
+
+interface SandboxedUiAdapter {
+
+ /**
+ * Open a new session for displaying content with an initial size of
+ * [initialWidth]x[initialHeight] pixels. [client] will receive all incoming communication from
+ * the provider of content. All incoming calls to [client] will be made through the provided
+ * [clientExecutor]. [isZOrderOnTop] tracks if the content surface will be placed on top of its
+ * window
+ */
+ fun openSession(
+ context: Context,
+ initialWidth: Int,
+ initialHeight: Int,
+ isZOrderOnTop: Boolean,
+ clientExecutor: Executor,
+ client: SessionClient
+ )
+
+ /**
+ * A single session with the provider of remote content.
+ */
+ interface Session {
+
+ /**
+ * Return the [View] that presents content for this session. The same view will be returned
+ * for the life of the session object. Accessing [view] after [close] may throw an
+ * [IllegalStateException].
+ */
+ val view: View
+
+ /**
+ * Close this session, indicating that the remote provider of content should
+ * dispose of associated resources and that the [SessionClient] should not
+ * receive further callback events.
+ */
+ fun close()
+ }
+
+ /**
+ * The client of a single session that will receive callback events from an active session.
+ */
+ interface SessionClient {
+ /**
+ * Called to report that the session was opened successfully, delivering the [Session]
+ * handle that should be used to notify the session of UI events.
+ */
+ fun onSessionOpened(session: Session)
+
+ /**
+ * Called to report a terminal error in the session. No further events will be reported
+ * to this [SessionClient] and any further or currently pending calls to the [Session]
+ * that may have been in flight may be ignored.
+ */
+ fun onSessionError(throwable: Throwable)
+ }
+}
diff --git a/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SdkRuntimeUiLibVersions.kt b/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SdkRuntimeUiLibVersions.kt
new file mode 100644
index 0000000..ce0f622
--- /dev/null
+++ b/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/SdkRuntimeUiLibVersions.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.privacysandbox.ui.core
+
+import androidx.annotation.RestrictTo
+
+object SdkRuntimeUiLibVersions {
+ var clientVersion: Int = -1
+ /**
+ * @hide
+ */
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+ set
+
+ const val apiVersion: Int = 1
+}
\ No newline at end of file
diff --git a/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/androidx-privacysandbox-ui-ui-core-documentation.md b/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/androidx-privacysandbox-ui-ui-core-documentation.md
similarity index 99%
rename from privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/androidx-privacysandbox-ui-ui-core-documentation.md
rename to privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/androidx-privacysandbox-ui-ui-core-documentation.md
index aa56a66..df34ca3 100644
--- a/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/androidx-privacysandbox-ui-ui-core-documentation.md
+++ b/privacysandbox/ui/ui-core/src/main/java/androidx/privacysandbox/ui/core/androidx-privacysandbox-ui-ui-core-documentation.md
@@ -3,5 +3,6 @@
Privacy Sandbox Ui Core
# Package androidx.privacysandbox.ui.core
+
This package contains interface and class definitions shared between Privacy
Sandbox Ui Client and Privacy Sandbox Ui Provider.
diff --git a/privacysandbox/ui/ui-provider/api/current.txt b/privacysandbox/ui/ui-provider/api/current.txt
index e6f50d0..20170b4 100644
--- a/privacysandbox/ui/ui-provider/api/current.txt
+++ b/privacysandbox/ui/ui-provider/api/current.txt
@@ -1 +1,9 @@
// Signature format: 4.0
+package androidx.privacysandbox.ui.provider {
+
+ @RequiresApi(33) public final class SandboxedUiAdapterProxy {
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static android.os.Bundle toCoreLibInfo(androidx.privacysandbox.ui.core.SandboxedUiAdapter, android.content.Context context);
+ }
+
+}
+
diff --git a/privacysandbox/ui/ui-provider/api/public_plus_experimental_current.txt b/privacysandbox/ui/ui-provider/api/public_plus_experimental_current.txt
index e6f50d0..20170b4 100644
--- a/privacysandbox/ui/ui-provider/api/public_plus_experimental_current.txt
+++ b/privacysandbox/ui/ui-provider/api/public_plus_experimental_current.txt
@@ -1 +1,9 @@
// Signature format: 4.0
+package androidx.privacysandbox.ui.provider {
+
+ @RequiresApi(33) public final class SandboxedUiAdapterProxy {
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static android.os.Bundle toCoreLibInfo(androidx.privacysandbox.ui.core.SandboxedUiAdapter, android.content.Context context);
+ }
+
+}
+
diff --git a/privacysandbox/ui/ui-provider/api/restricted_current.txt b/privacysandbox/ui/ui-provider/api/restricted_current.txt
index e6f50d0..20170b4 100644
--- a/privacysandbox/ui/ui-provider/api/restricted_current.txt
+++ b/privacysandbox/ui/ui-provider/api/restricted_current.txt
@@ -1 +1,9 @@
// Signature format: 4.0
+package androidx.privacysandbox.ui.provider {
+
+ @RequiresApi(33) public final class SandboxedUiAdapterProxy {
+ method @RequiresApi(android.os.Build.VERSION_CODES.TIRAMISU) public static android.os.Bundle toCoreLibInfo(androidx.privacysandbox.ui.core.SandboxedUiAdapter, android.content.Context context);
+ }
+
+}
+
diff --git a/privacysandbox/ui/ui-provider/build.gradle b/privacysandbox/ui/ui-provider/build.gradle
index 6b2b1324..bcbd719 100644
--- a/privacysandbox/ui/ui-provider/build.gradle
+++ b/privacysandbox/ui/ui-provider/build.gradle
@@ -24,7 +24,15 @@
dependencies {
api(libs.kotlinStdlib)
- // Add dependencies here
+ implementation project(path: ':privacysandbox:ui:ui-core')
+ implementation project(path: ':annotation:annotation')
+ androidTestImplementation(libs.junit)
+ androidTestImplementation(libs.kotlinStdlib)
+ androidTestImplementation(libs.testExtJunit)
+ androidTestImplementation(libs.testCore)
+ androidTestImplementation(libs.testRunner)
+ androidTestImplementation(libs.testRules)
+ androidTestImplementation(libs.truth)
}
android {
diff --git a/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/BinderAdapterDelegate.kt b/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/BinderAdapterDelegate.kt
new file mode 100644
index 0000000..84149c0
--- /dev/null
+++ b/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/BinderAdapterDelegate.kt
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+@file:RequiresApi(Build.VERSION_CODES.TIRAMISU)
+@file:JvmName("SandboxedUiAdapterProxy")
+
+package androidx.privacysandbox.ui.provider
+
+import android.content.Context
+import android.hardware.display.DisplayManager
+import android.os.Build
+import android.os.Bundle
+import android.os.Handler
+import android.os.IBinder
+import android.os.Looper
+import android.view.SurfaceControlViewHost
+import androidx.annotation.RequiresApi
+import androidx.annotation.VisibleForTesting
+import androidx.privacysandbox.ui.core.IRemoteSessionClient
+import androidx.privacysandbox.ui.core.IRemoteSessionController
+import androidx.privacysandbox.ui.core.ISandboxedUiAdapter
+import androidx.privacysandbox.ui.core.SandboxedUiAdapter
+import java.util.concurrent.Executor
+
+/**
+ * Provides a [Bundle] containing a Binder which represents a [SandboxedUiAdapter]. The Bundle
+ * is shuttled to the host app in order for the [SandboxedUiAdapter] to be used to retrieve
+ * content.
+ */
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+fun SandboxedUiAdapter.toCoreLibInfo(@Suppress("ContextFirst") context: Context): Bundle {
+ val binderAdapter = BinderAdapterDelegate(context, this)
+ // TODO: Add version info
+ val bundle = Bundle()
+ // Bundle key is a binary compatibility requirement
+ bundle.putBinder("uiAdapterBinder", binderAdapter)
+ return bundle
+}
+
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
+private class BinderAdapterDelegate(
+ private val sandboxContext: Context,
+ private val adapter: SandboxedUiAdapter
+) : ISandboxedUiAdapter.Stub() {
+
+ fun openSession(
+ context: Context,
+ initialWidth: Int,
+ initialHeight: Int,
+ isZOrderOnTop: Boolean,
+ clientExecutor: Executor,
+ client: SandboxedUiAdapter.SessionClient
+ ) {
+ adapter.openSession(
+ context, initialWidth, initialHeight, isZOrderOnTop, clientExecutor,
+ client
+ )
+ }
+
+ override fun openRemoteSession(
+ hostToken: IBinder,
+ displayId: Int,
+ initialWidth: Int,
+ initialHeight: Int,
+ isZOrderOnTop: Boolean,
+ remoteSessionClient: IRemoteSessionClient
+ ) {
+ val mHandler = Handler(Looper.getMainLooper())
+ mHandler.post {
+ try {
+ val mDisplayManager: DisplayManager =
+ sandboxContext.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
+ val windowContext =
+ sandboxContext.createDisplayContext(mDisplayManager.getDisplay(displayId))
+ val surfaceControlViewHost = SurfaceControlViewHost(
+ windowContext,
+ mDisplayManager.getDisplay(displayId), hostToken
+ )
+ val sessionClient = SessionClientProxy(
+ surfaceControlViewHost, initialWidth, initialHeight, remoteSessionClient
+ )
+ openSession(
+ windowContext, initialWidth, initialHeight, isZOrderOnTop,
+ Runnable::run, sessionClient
+ )
+ } catch (exception: Throwable) {
+ remoteSessionClient.onRemoteSessionError(exception.message)
+ }
+ }
+ }
+
+ private inner class SessionClientProxy(
+ private val surfaceControlViewHost: SurfaceControlViewHost,
+ private val initialWidth: Int,
+ private val initialHeight: Int,
+ private val remoteSessionClient: IRemoteSessionClient
+ ) : SandboxedUiAdapter.SessionClient {
+
+ override fun onSessionOpened(session: SandboxedUiAdapter.Session) {
+ val view = session.view
+ surfaceControlViewHost.setView(view, initialWidth, initialHeight)
+ val surfacePackage = surfaceControlViewHost.surfacePackage
+ val remoteSessionController =
+ RemoteSessionController(surfaceControlViewHost, session)
+ remoteSessionClient.onRemoteSessionOpened(
+ surfacePackage, remoteSessionController,
+ /* isZOrderOnTop= */ true
+ )
+ }
+
+ override fun onSessionError(throwable: Throwable) {
+ remoteSessionClient.onRemoteSessionError(throwable.message)
+ }
+
+ @VisibleForTesting
+ private inner class RemoteSessionController(
+ val surfaceControlViewHost: SurfaceControlViewHost,
+ val session: SandboxedUiAdapter.Session
+ ) : IRemoteSessionController.Stub() {
+ override fun close() {
+ session.close()
+ surfaceControlViewHost.release()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/androidx-privacysandbox-ui-ui-provider-documentation.md b/privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/androidx-privacysandbox-ui-ui-provider-documentation.md
similarity index 100%
rename from privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/androidx-privacysandbox-ui-ui-provider-documentation.md
rename to privacysandbox/ui/ui-provider/src/main/java/androidx/privacysandbox/ui/provider/androidx-privacysandbox-ui-ui-provider-documentation.md
diff --git a/settings.gradle b/settings.gradle
index c8a5999..2471fc2d 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -365,8 +365,9 @@
includeProject(":annotation:annotation-experimental-lint")
includeProject(":annotation:annotation-experimental-lint-integration-tests", "annotation/annotation-experimental-lint/integration-tests")
includeProject(":annotation:annotation-sampled")
-includeProject(":appactions:interaction:interaction-proto", [BuildType.MAIN])
includeProject(":appactions:interaction:interaction-capabilities-core", [BuildType.MAIN])
+includeProject(":appactions:interaction:interaction-proto", [BuildType.MAIN])
+includeProject(":appactions:interaction:interaction-service", [BuildType.MAIN])
includeProject(":appcompat:appcompat", [BuildType.MAIN])
includeProject(":appcompat:appcompat-benchmark", [BuildType.MAIN])
includeProject(":appcompat:appcompat-lint", [BuildType.MAIN])
@@ -382,8 +383,8 @@
includeProject(":appsearch:appsearch-local-storage", [BuildType.MAIN])
includeProject(":appsearch:appsearch-platform-storage", [BuildType.MAIN])
includeProject(":appsearch:appsearch-test-util", [BuildType.MAIN])
-includeProject(":arch:core:core-common", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
-includeProject(":arch:core:core-runtime", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
+includeProject(":arch:core:core-common", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":arch:core:core-runtime", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
includeProject(":arch:core:core-testing", [BuildType.MAIN])
includeProject(":asynclayoutinflater:asynclayoutinflater", [BuildType.MAIN])
includeProject(":asynclayoutinflater:asynclayoutinflater-appcompat", [BuildType.MAIN])
@@ -399,6 +400,13 @@
includeProject(":benchmark:benchmark-junit4")
includeProject(":benchmark:benchmark-macro", [BuildType.MAIN, BuildType.COMPOSE])
includeProject(":benchmark:benchmark-macro-junit4", [BuildType.MAIN, BuildType.COMPOSE])
+includeProject(":benchmark:integration-tests:baselineprofiles-producer", [BuildType.MAIN])
+includeProject(":benchmark:integration-tests:baselineprofiles-consumer", [BuildType.MAIN])
+includeProject(":benchmark:integration-tests:baselineprofiles-flavors-producer", [BuildType.MAIN])
+includeProject(":benchmark:integration-tests:baselineprofiles-flavors-consumer", [BuildType.MAIN])
+includeProject(":benchmark:integration-tests:baselineprofiles-library-consumer", [BuildType.MAIN])
+includeProject(":benchmark:integration-tests:baselineprofiles-library-producer", [BuildType.MAIN])
+includeProject(":benchmark:integration-tests:baselineprofiles-library-build-provider", [BuildType.MAIN])
includeProject(":benchmark:integration-tests:dry-run-benchmark", [BuildType.MAIN])
includeProject(":benchmark:integration-tests:macrobenchmark", [BuildType.MAIN])
includeProject(":benchmark:integration-tests:macrobenchmark-target", [BuildType.MAIN])
@@ -715,33 +723,33 @@
includeProject(":lifecycle:integration-tests:incrementality", [BuildType.MAIN, BuildType.FLAN])
includeProject(":lifecycle:integration-tests:lifecycle-testapp", "lifecycle/integration-tests/testapp", [BuildType.MAIN, BuildType.FLAN])
includeProject(":lifecycle:integration-tests:lifecycle-testapp-kotlin", "lifecycle/integration-tests/kotlintestapp", [BuildType.MAIN, BuildType.FLAN])
-includeProject(":lifecycle:lifecycle-common", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
-includeProject(":lifecycle:lifecycle-common-java8", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
+includeProject(":lifecycle:lifecycle-common", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-common-java8", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
includeProject(":lifecycle:lifecycle-compiler", [BuildType.MAIN, BuildType.FLAN])
includeProject(":lifecycle:lifecycle-extensions", [BuildType.MAIN, BuildType.FLAN])
-includeProject(":lifecycle:lifecycle-livedata", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
-includeProject(":lifecycle:lifecycle-livedata-core", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
-includeProject(":lifecycle:lifecycle-livedata-core-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
-includeProject(":lifecycle:lifecycle-livedata-core-ktx-lint", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
+includeProject(":lifecycle:lifecycle-livedata", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-livedata-core", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-livedata-core-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-livedata-core-ktx-lint", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
includeProject(":lifecycle:lifecycle-livedata-core-truth", [BuildType.MAIN, BuildType.FLAN])
-includeProject(":lifecycle:lifecycle-livedata-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
+includeProject(":lifecycle:lifecycle-livedata-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
includeProject(":lifecycle:lifecycle-process", [BuildType.MAIN, BuildType.FLAN])
includeProject(":lifecycle:lifecycle-reactivestreams", [BuildType.MAIN, BuildType.FLAN])
includeProject(":lifecycle:lifecycle-reactivestreams-ktx", [BuildType.MAIN, BuildType.FLAN])
-includeProject(":lifecycle:lifecycle-runtime", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
+includeProject(":lifecycle:lifecycle-runtime", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
includeProject(":lifecycle:lifecycle-runtime-compose", [BuildType.COMPOSE])
includeProject(":lifecycle:lifecycle-runtime-compose:lifecycle-runtime-compose-samples", "lifecycle/lifecycle-runtime-compose/samples", [BuildType.COMPOSE])
includeProject(":lifecycle:lifecycle-runtime-compose:integration-tests:lifecycle-runtime-compose-demos", [BuildType.COMPOSE])
-includeProject(":lifecycle:lifecycle-runtime-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
-includeProject(":lifecycle:lifecycle-runtime-ktx-lint", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
-includeProject(":lifecycle:lifecycle-runtime-testing", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
+includeProject(":lifecycle:lifecycle-runtime-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-runtime-ktx-lint", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-runtime-testing", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
includeProject(":lifecycle:lifecycle-service", [BuildType.MAIN, BuildType.FLAN])
-includeProject(":lifecycle:lifecycle-viewmodel", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
+includeProject(":lifecycle:lifecycle-viewmodel", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
includeProject(":lifecycle:lifecycle-viewmodel-compose", [BuildType.COMPOSE])
includeProject(":lifecycle:lifecycle-viewmodel-compose:lifecycle-viewmodel-compose-samples", "lifecycle/lifecycle-viewmodel-compose/samples", [BuildType.COMPOSE])
includeProject(":lifecycle:lifecycle-viewmodel-compose:integration-tests:lifecycle-viewmodel-demos", [BuildType.COMPOSE])
-includeProject(":lifecycle:lifecycle-viewmodel-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
-includeProject(":lifecycle:lifecycle-viewmodel-savedstate", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE])
+includeProject(":lifecycle:lifecycle-viewmodel-ktx", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
+includeProject(":lifecycle:lifecycle-viewmodel-savedstate", [BuildType.MAIN, BuildType.FLAN, BuildType.WEAR, BuildType.COMPOSE, BuildType.CAMERA])
includeProject(":lint-checks")
includeProject(":lint-checks:integration-tests")
includeProject(":loader:loader", [BuildType.MAIN])
diff --git a/tracing/OWNERS b/tracing/OWNERS
index 5db1872..9b3f90f 100644
--- a/tracing/OWNERS
+++ b/tracing/OWNERS
@@ -1,3 +1,4 @@
+# Bug component: 873508
ccraik@google.com
jgielzak@google.com
rahulrav@google.com
diff --git a/wear/compose/integration-tests/demos/build.gradle b/wear/compose/integration-tests/demos/build.gradle
index f826f7d..2d08931 100644
--- a/wear/compose/integration-tests/demos/build.gradle
+++ b/wear/compose/integration-tests/demos/build.gradle
@@ -27,7 +27,7 @@
minSdk 25
targetSdk 30
versionCode 12
- versionName "1.11"
+ versionName "1.12"
// Change the APK name to match the *testapp regex we use to pick up APKs for testing as
// part of CI.
archivesBaseName = "wear-compose-demos-testapp"
diff --git a/wear/watchface/watchface-editor/src/main/java/androidx/wear/watchface/editor/WatchFaceEditorContract.kt b/wear/watchface/watchface-editor/src/main/java/androidx/wear/watchface/editor/WatchFaceEditorContract.kt
index 4ece658..88edba6 100644
--- a/wear/watchface/watchface-editor/src/main/java/androidx/wear/watchface/editor/WatchFaceEditorContract.kt
+++ b/wear/watchface/watchface-editor/src/main/java/androidx/wear/watchface/editor/WatchFaceEditorContract.kt
@@ -16,6 +16,7 @@
package androidx.wear.watchface.editor
+import androidx.wear.watchface.data.DeviceConfig as WireDeviceConfig
import android.annotation.SuppressLint
import android.app.Activity
import android.content.ComponentName
@@ -47,8 +48,6 @@
internal const val USER_STYLE_KEY: String = "USER_STYLE_KEY"
internal const val USER_STYLE_VALUES: String = "USER_STYLE_VALUES"
-typealias WireDeviceConfig = androidx.wear.watchface.data.DeviceConfig
-
/**
* Parameters for an optional final screenshot taken by [EditorSession] upon exit and reported via
* [EditorState].
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 d160094..84970d4 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
@@ -5488,6 +5488,49 @@
}
@Test
+ public fun updateComplicationTimelineOnly_updatesComplication() {
+ // Arrange
+ initWallpaperInteractiveWatchFaceInstance(complicationSlots = listOf(leftComplication))
+ val defaultBase = WireComplicationData.Builder(WireComplicationData.TYPE_LONG_TEXT)
+ .setLongText(WireComplicationText("default"))
+ .build()
+ val timelineEntryBase = WireComplicationData.Builder(WireComplicationData.TYPE_LONG_TEXT)
+ .setLongText(WireComplicationText("timeline"))
+ .build()
+ val oldTimelineEntry = WireComplicationData.Builder(defaultBase).build().apply {
+ setTimelineEntryCollection(
+ listOf(
+ WireComplicationData.Builder(timelineEntryBase).build().apply {
+ timelineStartEpochSecond = 100
+ timelineEndEpochSecond = 200
+ }
+ )
+ )
+ }
+ val newTimelineEntry = WireComplicationData.Builder(defaultBase).build().apply {
+ setTimelineEntryCollection(
+ listOf(
+ WireComplicationData.Builder(timelineEntryBase).build().apply {
+ timelineStartEpochSecond = 200
+ timelineEndEpochSecond = 300
+ }
+ )
+ )
+ }
+ engineWrapper.setComplicationDataList(
+ listOf(IdAndComplicationDataWireFormat(LEFT_COMPLICATION_ID, oldTimelineEntry))
+ )
+ complicationSlotsManager.selectComplicationDataForInstant(Instant.ofEpochSecond(150))
+ // Act
+ engineWrapper.setComplicationDataList(
+ listOf(IdAndComplicationDataWireFormat(LEFT_COMPLICATION_ID, newTimelineEntry))
+ )
+ complicationSlotsManager.selectComplicationDataForInstant(Instant.ofEpochSecond(250))
+ // Assert
+ assertThat(getLeftLongTextComplicationDataText()).isEqualTo("timeline")
+ }
+
+ @Test
@Config(sdk = [Build.VERSION_CODES.R])
public fun renderParameters_isScreenshot() {
initWallpaperInteractiveWatchFaceInstance(
diff --git a/work/OWNERS b/work/OWNERS
index e994ca6..d390fd5 100644
--- a/work/OWNERS
+++ b/work/OWNERS
@@ -1,6 +1,7 @@
-# Bug component: 409906
+# Bug component: 324783
+sergeyv@google.com
sumir@google.com
rahulrav@google.com
ilake@google.com
-per-file settings.gradle = dustinlam@google.com, rahulrav@google.com
+per-file settings.gradle = dustinlam@google.com, rahulrav@google.com, sergeyv@google.com
diff --git a/work/work-runtime/src/androidTest/AndroidManifest.xml b/work/work-runtime/src/androidTest/AndroidManifest.xml
index 3f54449..e636ee9 100644
--- a/work/work-runtime/src/androidTest/AndroidManifest.xml
+++ b/work/work-runtime/src/androidTest/AndroidManifest.xml
@@ -17,10 +17,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!--
- ~ Adding this permission to the test-app's AndroidManifest.xml. This is because
+ ~ Adding these permissions to the test-app's AndroidManifest.xml. This is because
~ we don't want applications to implicitly add this permission on API 31 and above. We only
~ need this permission for tests.
-->
- <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
+ <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"
+ android:maxSdkVersion="32"/>
+ <uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
<application android:name="androidx.multidex.MultiDexApplication"/>
</manifest>
diff --git a/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemalarm/AlarmsTest.java b/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemalarm/AlarmsTest.java
index 2c2aced..164a3ef 100644
--- a/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemalarm/AlarmsTest.java
+++ b/work/work-runtime/src/androidTest/java/androidx/work/impl/background/systemalarm/AlarmsTest.java
@@ -25,11 +25,9 @@
import static org.hamcrest.MatcherAssert.assertThat;
import android.content.Context;
-import android.os.Build;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SdkSuppress;
import androidx.test.filters.SmallTest;
import androidx.work.DatabaseTest;
import androidx.work.OneTimeWorkRequest;
@@ -51,12 +49,7 @@
private final long mTriggerAt = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1);
@Test
- @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
public void testSetAlarm_noPreExistingAlarms() {
- if (Build.VERSION.SDK_INT == 33 && !"REL".equals(Build.VERSION.CODENAME)) {
- return; // b/262909049: Do not run this test on pre-release Android U.
- }
-
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
insertWork(work);
WorkGenerationalId workSpecId = generationalId(work.getWorkSpec());
@@ -67,12 +60,7 @@
}
@Test
- @SdkSuppress(maxSdkVersion = 33) // b/262909049: Failing on SDK 34
public void testSetAlarm_withPreExistingAlarms() {
- if (Build.VERSION.SDK_INT == 33 && !"REL".equals(Build.VERSION.CODENAME)) {
- return; // b/262909049: Do not run this test on pre-release Android U.
- }
-
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(TestWorker.class).build();
insertWork(work);
WorkGenerationalId workSpecId = generationalId(work.getWorkSpec());