diff options
8 files changed, 226 insertions, 20 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/ExampleFeature.kt b/packages/SystemUI/compose/features/src/com/android/systemui/ExampleFeature.kt index 1ad54846fb25..c58c16259abe 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/ExampleFeature.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/ExampleFeature.kt @@ -17,8 +17,12 @@ package com.android.systemui import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface @@ -29,14 +33,37 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import kotlin.math.roundToInt /** * This is an example Compose feature, which shows a text and a count that is incremented when - * clicked. + * clicked. We also show the max width available to this component, which is displayed either next + * to or below the text depending on that max width. */ @Composable fun ExampleFeature(text: String, modifier: Modifier = Modifier) { + BoxWithConstraints(modifier) { + val maxWidth = maxWidth + if (maxWidth < 600.dp) { + Column { + CounterTile(text) + Spacer(Modifier.size(16.dp)) + MaxWidthTile(maxWidth) + } + } else { + Row { + CounterTile(text) + Spacer(Modifier.size(16.dp)) + MaxWidthTile(maxWidth) + } + } + } +} + +@Composable +private fun CounterTile(text: String, modifier: Modifier = Modifier) { Surface( modifier, color = MaterialTheme.colorScheme.primaryContainer, @@ -51,3 +78,17 @@ fun ExampleFeature(text: String, modifier: Modifier = Modifier) { } } } + +@Composable +private fun MaxWidthTile(maxWidth: Dp, modifier: Modifier = Modifier) { + Surface( + modifier, + color = MaterialTheme.colorScheme.tertiaryContainer, + shape = RoundedCornerShape(28.dp), + ) { + Text( + "The max available width to me is: ${maxWidth.value.roundToInt()}dp", + Modifier.padding(16.dp) + ) + } +} diff --git a/packages/SystemUI/compose/gallery/Android.bp b/packages/SystemUI/compose/gallery/Android.bp index 030ad854992a..bddc1e63fee8 100644 --- a/packages/SystemUI/compose/gallery/Android.bp +++ b/packages/SystemUI/compose/gallery/Android.bp @@ -52,6 +52,7 @@ android_library { android_app { name: "SystemUIComposeGallery", defaults: ["platform_app_defaults"], + manifest: "app/AndroidManifest.xml", static_libs: [ "SystemUIComposeGalleryLib", diff --git a/packages/SystemUI/compose/gallery/AndroidManifest.xml b/packages/SystemUI/compose/gallery/AndroidManifest.xml index 81132632079a..562e1cc3339a 100644 --- a/packages/SystemUI/compose/gallery/AndroidManifest.xml +++ b/packages/SystemUI/compose/gallery/AndroidManifest.xml @@ -17,21 +17,5 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.systemui.compose.gallery"> - <application - android:allowBackup="true" - android:icon="@mipmap/ic_launcher" - android:label="@string/app_name" - android:roundIcon="@mipmap/ic_launcher_round" - android:supportsRtl="true" - android:theme="@style/Theme.SystemUIGallery"> - <activity - android:name=".GalleryActivity" - android:exported="true" - android:label="@string/app_name"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> + </manifest> diff --git a/packages/SystemUI/compose/gallery/app/AndroidManifest.xml b/packages/SystemUI/compose/gallery/app/AndroidManifest.xml new file mode 100644 index 000000000000..81132632079a --- /dev/null +++ b/packages/SystemUI/compose/gallery/app/AndroidManifest.xml @@ -0,0 +1,37 @@ +<?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 xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.systemui.compose.gallery"> + <application + android:allowBackup="true" + android:icon="@mipmap/ic_launcher" + android:label="@string/app_name" + android:roundIcon="@mipmap/ic_launcher_round" + android:supportsRtl="true" + android:theme="@style/Theme.SystemUIGallery"> + <activity + android:name=".GalleryActivity" + android:exported="true" + android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ExampleFeatureScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ExampleFeatureScreen.kt index 652c403470f1..6e1721490f98 100644 --- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ExampleFeatureScreen.kt +++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ExampleFeatureScreen.kt @@ -18,10 +18,11 @@ package com.android.systemui.compose.gallery import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier import com.android.systemui.ExampleFeature /** The screen that shows ExampleFeature. */ @Composable -fun ExampleFeatureScreen() { - Column { ExampleFeature("This is an example feature!") } +fun ExampleFeatureScreen(modifier: Modifier = Modifier) { + Column(modifier) { ExampleFeature("This is an example feature!") } } diff --git a/packages/SystemUI/compose/testing/Android.bp b/packages/SystemUI/compose/testing/Android.bp new file mode 100644 index 000000000000..293e51f68b98 --- /dev/null +++ b/packages/SystemUI/compose/testing/Android.bp @@ -0,0 +1,43 @@ +// 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 { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"], +} + +android_library { + name: "SystemUIComposeTesting", + manifest: "AndroidManifest.xml", + + srcs: [ + "src/**/*.kt", + ], + + static_libs: [ + "SystemUIComposeCore", + "SystemUIScreenshotLib", + + "androidx.compose.runtime_runtime", + "androidx.compose.material3_material3", + "androidx.compose.ui_ui-test-junit4", + "androidx.compose.ui_ui-test-manifest", + ], + + kotlincflags: ["-Xjvm-default=all"], +} diff --git a/packages/SystemUI/compose/testing/AndroidManifest.xml b/packages/SystemUI/compose/testing/AndroidManifest.xml new file mode 100644 index 000000000000..b1f7c3be2796 --- /dev/null +++ b/packages/SystemUI/compose/testing/AndroidManifest.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2022 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + package="com.android.systemui.testing.compose"> + <application + android:appComponentFactory="androidx.core.app.AppComponentFactory" + tools:replace="android:appComponentFactory"> + </application> +</manifest> diff --git a/packages/SystemUI/compose/testing/src/com/android/systemui/testing/compose/ComposeScreenshotTestRule.kt b/packages/SystemUI/compose/testing/src/com/android/systemui/testing/compose/ComposeScreenshotTestRule.kt new file mode 100644 index 000000000000..7a0b1f190f99 --- /dev/null +++ b/packages/SystemUI/compose/testing/src/com/android/systemui/testing/compose/ComposeScreenshotTestRule.kt @@ -0,0 +1,74 @@ +/* + * 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 com.android.systemui.testing.compose + +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.ViewRootForTest +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onRoot +import com.android.systemui.compose.theme.SystemUITheme +import com.android.systemui.testing.screenshot.ScreenshotActivity +import com.android.systemui.testing.screenshot.ScreenshotTestRule +import com.android.systemui.testing.screenshot.ScreenshotTestSpec +import org.junit.rules.RuleChain +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement + +/** A rule for Compose screenshot diff tests. */ +class ComposeScreenshotTestRule(testSpec: ScreenshotTestSpec) : TestRule { + private val composeRule = createAndroidComposeRule<ScreenshotActivity>() + private val screenshotRule = ScreenshotTestRule(testSpec) + + private val delegate = RuleChain.outerRule(screenshotRule).around(composeRule) + + override fun apply(base: Statement, description: Description): Statement { + return delegate.apply(base, description) + } + + /** + * Compare [content] with the golden image identified by [goldenIdentifier] in the context of + * [testSpec]. + */ + fun screenshotTest( + goldenIdentifier: String, + content: @Composable () -> Unit, + ) { + // Make sure that the activity draws full screen and fits the whole display instead of the + // system bars. + val activity = composeRule.activity + activity.mainExecutor.execute { activity.window.setDecorFitsSystemWindows(false) } + + // Set the content using the AndroidComposeRule to make sure that the Activity is set up + // correctly. + composeRule.setContent { + SystemUITheme { + Surface( + color = MaterialTheme.colorScheme.background, + ) { + content() + } + } + } + composeRule.waitForIdle() + + val view = (composeRule.onRoot().fetchSemanticsNode().root as ViewRootForTest).view + screenshotRule.screenshotTest(goldenIdentifier, view) + } +} |