Add illustration widget to SPA and create a gallary sample page for it.
The widget now supports image resources. Bug: 242951784 Test: unit test and manually test on device Change-Id: Ie2bbdb4c887d9d1947c872ef62d56f98c4357f5b
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="412dp"
|
||||
android:height="300dp"
|
||||
android:viewportWidth="412"
|
||||
android:viewportHeight="300">
|
||||
<path
|
||||
android:pathData="M383.9,300H28.1C12.6,300 0,287.4 0,271.9V28.1C0,12.6 12.6,0 28.1,0h355.8C399.4,0 412,12.6 412,28.1v243.8C412,287.4 399.4,300 383.9,300z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M79.2,179.6h53.6v8.5h-53.6z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M142.5,179.6h30.4v8.5h-30.4z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M79.2,195.5h79.2v8.5h-79.2z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M168.1,195.5h34.1v8.5h-34.1z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M211.9,195.5h34.1v8.5h-34.1z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M182.7,179.6h73.1v8.5h-73.1z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M265.5,179.6h26.8v8.5h-26.8z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M302.1,179.6h26.8v8.5h-26.8z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M142.7,67.9h-11.5c-1.6,0 -2.9,1.3 -2.9,2.9H67.8c-7.9,0 -14.4,6.5 -14.4,14.4v132.4c0,7.9 6.5,14.4 14.4,14.4h276.4c7.9,0 14.4,-6.5 14.4,-14.4V85.2c0,-7.9 -6.5,-14.4 -14.4,-14.4H203.1c0,-1.6 -1.3,-2.9 -2.9,-2.9h-28.8c-1.6,0 -2.9,1.3 -2.9,2.9h-23C145.5,69.2 144.3,67.9 142.7,67.9zM344.2,73.7c6.4,0 11.5,5.2 11.5,11.5v132.4c0,6.3 -5.2,11.5 -11.5,11.5H67.8c-6.4,0 -11.5,-5.2 -11.5,-11.5V85.2c0,-6.3 5.2,-11.5 11.5,-11.5H344.2z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
</vector>
|
||||
@@ -22,6 +22,7 @@ import com.android.settingslib.spa.framework.common.SettingsPageProviderReposito
|
||||
import com.android.settingslib.spa.gallery.home.HomePageProvider
|
||||
import com.android.settingslib.spa.gallery.page.ArgumentPageProvider
|
||||
import com.android.settingslib.spa.gallery.page.FooterPageProvider
|
||||
import com.android.settingslib.spa.gallery.page.IllustrationPageProvider
|
||||
import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider
|
||||
import com.android.settingslib.spa.gallery.page.SliderPageProvider
|
||||
import com.android.settingslib.spa.gallery.preference.PreferenceMainPageProvider
|
||||
@@ -45,6 +46,7 @@ object SpaEnvironment {
|
||||
SpinnerPageProvider,
|
||||
SettingsPagerPageProvider,
|
||||
FooterPageProvider,
|
||||
IllustrationPageProvider,
|
||||
),
|
||||
rootPageData = listOf(
|
||||
SettingsPage(HomePageProvider.name),
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.android.settingslib.spa.gallery.R
|
||||
import com.android.settingslib.spa.gallery.SpaEnvironment
|
||||
import com.android.settingslib.spa.gallery.page.ArgumentPageProvider
|
||||
import com.android.settingslib.spa.gallery.page.FooterPageProvider
|
||||
import com.android.settingslib.spa.gallery.page.IllustrationPageProvider
|
||||
import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider
|
||||
import com.android.settingslib.spa.gallery.page.SliderPageProvider
|
||||
import com.android.settingslib.spa.gallery.preference.PreferenceMainPageProvider
|
||||
@@ -53,6 +54,7 @@ private fun HomePage() {
|
||||
SpinnerPageProvider.EntryItem()
|
||||
SettingsPagerPageProvider.EntryItem()
|
||||
FooterPageProvider.EntryItem()
|
||||
IllustrationPageProvider.EntryItem()
|
||||
|
||||
/**
|
||||
* A test button to generate hierarchy.
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.settingslib.spa.gallery.page
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.android.settingslib.spa.framework.common.SettingsPageProvider
|
||||
import com.android.settingslib.spa.framework.compose.navigator
|
||||
import com.android.settingslib.spa.framework.theme.SettingsTheme
|
||||
import com.android.settingslib.spa.gallery.R
|
||||
import com.android.settingslib.spa.widget.Illustration
|
||||
import com.android.settingslib.spa.widget.IllustrationModel
|
||||
import com.android.settingslib.spa.widget.ResourceType
|
||||
import com.android.settingslib.spa.widget.preference.Preference
|
||||
import com.android.settingslib.spa.widget.preference.PreferenceModel
|
||||
|
||||
object IllustrationPageProvider : SettingsPageProvider {
|
||||
override val name = "Illustration"
|
||||
|
||||
@Composable
|
||||
override fun Page(arguments: Bundle?) {
|
||||
IllustrationPage()
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EntryItem() {
|
||||
Preference(object : PreferenceModel {
|
||||
override val title = "Sample Illustration"
|
||||
override val onClick = navigator(name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun IllustrationPage() {
|
||||
Column(Modifier.verticalScroll(rememberScrollState())) {
|
||||
Preference(object : PreferenceModel {
|
||||
override val title = "Image Illustration"
|
||||
})
|
||||
|
||||
Illustration(object : IllustrationModel {
|
||||
override val resId = R.drawable.accessibility_captioning_banner
|
||||
override val resourceType = ResourceType.IMAGE
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun IllustrationPagePreview() {
|
||||
SettingsTheme {
|
||||
IllustrationPage()
|
||||
}
|
||||
}
|
||||
@@ -66,4 +66,5 @@ dependencies {
|
||||
api 'androidx.navigation:navigation-compose:2.5.0'
|
||||
api 'com.google.android.material:material:1.6.1'
|
||||
debugApi "androidx.compose.ui:ui-tooling:$jetpack_compose_version"
|
||||
implementation 'com.airbnb.android:lottie-compose:5.2.0'
|
||||
}
|
||||
|
||||
@@ -39,4 +39,10 @@ object SettingsDimension {
|
||||
|
||||
/** The size when app icon is displayed in App info page. */
|
||||
val appIconInfoSize = 48.dp
|
||||
|
||||
/** The sizes info of illustration widget. */
|
||||
val illustrationMaxWidth = 412.dp
|
||||
val illustrationMaxHeight = 300.dp
|
||||
val illustrationPadding = 16.dp
|
||||
val illustrationCornerRadius = 28.dp
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.settingslib.spa.widget
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import com.android.settingslib.spa.framework.theme.SettingsDimension
|
||||
import com.android.settingslib.spa.widget.ui.ImageBox
|
||||
|
||||
enum class ResourceType { IMAGE, LOTTIE }
|
||||
|
||||
/**
|
||||
* The widget model for [Illustration] widget.
|
||||
*/
|
||||
interface IllustrationModel {
|
||||
/**
|
||||
* The resource id of this [Illustration].
|
||||
*/
|
||||
val resId: Int
|
||||
|
||||
/**
|
||||
* The resource type of the [Illustration].
|
||||
*
|
||||
* It should be Lottie or Image.
|
||||
*/
|
||||
val resourceType: ResourceType
|
||||
}
|
||||
|
||||
/**
|
||||
* Illustration widget.
|
||||
*
|
||||
* Data is provided through [IllustrationModel].
|
||||
*/
|
||||
@Composable
|
||||
fun Illustration(model: IllustrationModel) {
|
||||
Illustration(
|
||||
resId = model.resId,
|
||||
resourceType = model.resourceType,
|
||||
modifier = Modifier,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Illustration(
|
||||
resId: Int,
|
||||
resourceType: ResourceType,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(SettingsDimension.illustrationPadding),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
val illustrationModifier = modifier
|
||||
.sizeIn(
|
||||
maxWidth = SettingsDimension.illustrationMaxWidth,
|
||||
maxHeight = SettingsDimension.illustrationMaxHeight,
|
||||
)
|
||||
.clip(RoundedCornerShape(SettingsDimension.illustrationCornerRadius))
|
||||
.background(color = MaterialTheme.colorScheme.surface)
|
||||
|
||||
when (resourceType) {
|
||||
ResourceType.LOTTIE -> {
|
||||
// TODO: Add Lottie function after lottie is enabled.
|
||||
}
|
||||
ResourceType.IMAGE -> {
|
||||
ImageBox(
|
||||
resId = resId,
|
||||
contentDescription = null,
|
||||
modifier = illustrationModifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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.settingslib.spa.widget.ui
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
|
||||
@Composable
|
||||
fun ImageBox(
|
||||
resId: Int,
|
||||
contentDescription: String?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier,
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(resId),
|
||||
contentDescription = contentDescription,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,9 @@ android {
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
res.srcDirs = ["res"]
|
||||
}
|
||||
androidTest {
|
||||
kotlin {
|
||||
srcDir "src"
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="412dp"
|
||||
android:height="300dp"
|
||||
android:viewportWidth="412"
|
||||
android:viewportHeight="300">
|
||||
<path
|
||||
android:pathData="M383.9,300H28.1C12.6,300 0,287.4 0,271.9V28.1C0,12.6 12.6,0 28.1,0h355.8C399.4,0 412,12.6 412,28.1v243.8C412,287.4 399.4,300 383.9,300z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M79.2,179.6h53.6v8.5h-53.6z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M142.5,179.6h30.4v8.5h-30.4z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M79.2,195.5h79.2v8.5h-79.2z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M168.1,195.5h34.1v8.5h-34.1z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M211.9,195.5h34.1v8.5h-34.1z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M182.7,179.6h73.1v8.5h-73.1z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M265.5,179.6h26.8v8.5h-26.8z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M302.1,179.6h26.8v8.5h-26.8z"
|
||||
android:fillColor="#1A73E8"/>
|
||||
<path
|
||||
android:pathData="M142.7,67.9h-11.5c-1.6,0 -2.9,1.3 -2.9,2.9H67.8c-7.9,0 -14.4,6.5 -14.4,14.4v132.4c0,7.9 6.5,14.4 14.4,14.4h276.4c7.9,0 14.4,-6.5 14.4,-14.4V85.2c0,-7.9 -6.5,-14.4 -14.4,-14.4H203.1c0,-1.6 -1.3,-2.9 -2.9,-2.9h-28.8c-1.6,0 -2.9,1.3 -2.9,2.9h-23C145.5,69.2 144.3,67.9 142.7,67.9zM344.2,73.7c6.4,0 11.5,5.2 11.5,11.5v132.4c0,6.3 -5.2,11.5 -11.5,11.5H67.8c-6.4,0 -11.5,-5.2 -11.5,-11.5V85.2c0,-6.3 5.2,-11.5 11.5,-11.5H344.2z"
|
||||
android:fillColor="#DADCE0"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.settingslib.spa.widget
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.semantics.SemanticsPropertyKey
|
||||
import androidx.compose.ui.semantics.SemanticsPropertyReceiver
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.test.SemanticsMatcher
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.filterToOne
|
||||
import androidx.compose.ui.test.hasAnyAncestor
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.android.settingslib.spa.tests.R
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class IllustrationTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
private val DrawableId = SemanticsPropertyKey<Int>("DrawableResId")
|
||||
private var SemanticsPropertyReceiver.drawableId by DrawableId
|
||||
|
||||
@Test
|
||||
fun image_displayed() {
|
||||
val resId = R.drawable.accessibility_captioning_banner
|
||||
composeTestRule.setContent {
|
||||
Illustration(
|
||||
resId = resId,
|
||||
resourceType = ResourceType.IMAGE,
|
||||
modifier = Modifier.semantics { drawableId = resId }
|
||||
)
|
||||
}
|
||||
|
||||
fun hasDrawable(@DrawableRes id: Int): SemanticsMatcher =
|
||||
SemanticsMatcher.expectValue(DrawableId, id)
|
||||
|
||||
val isIllustrationNode = !hasAnyAncestor(hasDrawable(resId))
|
||||
composeTestRule.onAllNodes(hasDrawable(resId))
|
||||
.filterToOne(isIllustrationNode)
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user