Merge "Create SpaPrivileged Lib"
This commit is contained in:
@@ -16,9 +16,9 @@
|
||||
|
||||
buildscript {
|
||||
ext {
|
||||
minSdk_version = 31
|
||||
compose_version = '1.2.0-alpha04'
|
||||
compose_material3_version = '1.0.0-alpha06'
|
||||
spa_min_sdk = 31
|
||||
jetpack_compose_version = '1.2.0-alpha04'
|
||||
jetpack_compose_material3_version = '1.0.0-alpha06'
|
||||
}
|
||||
}
|
||||
plugins {
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
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.settingslib.spa.codelab">
|
||||
|
||||
<application
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.SettingsLib.Compose.DayNight">
|
||||
android:theme="@style/Theme.SpaLib.DayNight">
|
||||
<activity
|
||||
android:name="com.android.settingslib.spa.codelab.MainActivity"
|
||||
android:exported="true">
|
||||
|
||||
@@ -25,7 +25,7 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.android.settingslib.spa.codelab"
|
||||
minSdk minSdk_version
|
||||
minSdk spa_min_sdk
|
||||
targetSdk 33
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
@@ -52,7 +52,7 @@ android {
|
||||
compose true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion compose_version
|
||||
kotlinCompilerExtensionVersion jetpack_compose_version
|
||||
}
|
||||
packagingOptions {
|
||||
resources {
|
||||
|
||||
@@ -24,7 +24,7 @@ android {
|
||||
compileSdk 33
|
||||
|
||||
defaultConfig {
|
||||
minSdk minSdk_version
|
||||
minSdk spa_min_sdk
|
||||
targetSdk 33
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ android {
|
||||
compose true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion compose_version
|
||||
kotlinCompilerExtensionVersion jetpack_compose_version
|
||||
}
|
||||
packagingOptions {
|
||||
resources {
|
||||
@@ -59,11 +59,11 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api "androidx.compose.material3:material3:$compose_material3_version"
|
||||
api "androidx.compose.material:material-icons-extended:$compose_version"
|
||||
api "androidx.compose.runtime:runtime-livedata:$compose_version"
|
||||
api "androidx.compose.ui:ui-tooling-preview:$compose_version"
|
||||
api "androidx.compose.material3:material3:$jetpack_compose_material3_version"
|
||||
api "androidx.compose.material:material-icons-extended:$jetpack_compose_version"
|
||||
api "androidx.compose.runtime:runtime-livedata:$jetpack_compose_version"
|
||||
api "androidx.compose.ui:ui-tooling-preview:$jetpack_compose_version"
|
||||
api 'androidx.navigation:navigation-compose:2.5.0'
|
||||
api 'com.google.android.material:material:1.6.1'
|
||||
debugApi "androidx.compose.ui:ui-tooling:$compose_version"
|
||||
debugApi "androidx.compose.ui:ui-tooling:$jetpack_compose_version"
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
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>
|
||||
|
||||
<style name="Theme.SettingsLib.Compose.DayNight" />
|
||||
<style name="Theme.SpaLib.DayNight" />
|
||||
</resources>
|
||||
|
||||
@@ -13,15 +13,15 @@
|
||||
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>
|
||||
|
||||
<style name="Theme.SettingsLib.Compose" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<style name="Theme.SpaLib" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<item name="android:statusBarColor">@android:color/transparent</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.SettingsLib.Compose.DayNight">
|
||||
<style name="Theme.SpaLib.DayNight">
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* 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.framework.compose
|
||||
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.RememberObserver
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.asAndroidColorFilter
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
||||
import androidx.compose.ui.graphics.nativeCanvas
|
||||
import androidx.compose.ui.graphics.painter.BitmapPainter
|
||||
import androidx.compose.ui.graphics.painter.ColorPainter
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.graphics.withSave
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
* *************************************************************************************************
|
||||
* This file was forked from
|
||||
* https://github.com/google/accompanist/blob/main/drawablepainter/src/main/java/com/google/accompanist/drawablepainter/DrawablePainter.kt
|
||||
* and will be removed once it lands in AndroidX.
|
||||
*/
|
||||
|
||||
private val MAIN_HANDLER by lazy(LazyThreadSafetyMode.NONE) {
|
||||
Handler(Looper.getMainLooper())
|
||||
}
|
||||
|
||||
/**
|
||||
* A [Painter] which draws an Android [Drawable] and supports [Animatable] drawables. Instances
|
||||
* should be remembered to be able to start and stop [Animatable] animations.
|
||||
*
|
||||
* Instances are usually retrieved from [rememberDrawablePainter].
|
||||
*/
|
||||
class DrawablePainter(
|
||||
val drawable: Drawable
|
||||
) : Painter(), RememberObserver {
|
||||
private var drawInvalidateTick by mutableStateOf(0)
|
||||
private var drawableIntrinsicSize by mutableStateOf(drawable.intrinsicSize)
|
||||
|
||||
private val callback: Drawable.Callback by lazy {
|
||||
object : Drawable.Callback {
|
||||
override fun invalidateDrawable(d: Drawable) {
|
||||
// Update the tick so that we get re-drawn
|
||||
drawInvalidateTick++
|
||||
// Update our intrinsic size too
|
||||
drawableIntrinsicSize = drawable.intrinsicSize
|
||||
}
|
||||
|
||||
override fun scheduleDrawable(d: Drawable, what: Runnable, time: Long) {
|
||||
MAIN_HANDLER.postAtTime(what, time)
|
||||
}
|
||||
|
||||
override fun unscheduleDrawable(d: Drawable, what: Runnable) {
|
||||
MAIN_HANDLER.removeCallbacks(what)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
if (drawable.intrinsicWidth >= 0 && drawable.intrinsicHeight >= 0) {
|
||||
// Update the drawable's bounds to match the intrinsic size
|
||||
drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRemembered() {
|
||||
drawable.callback = callback
|
||||
drawable.setVisible(true, true)
|
||||
if (drawable is Animatable) drawable.start()
|
||||
}
|
||||
|
||||
override fun onAbandoned() = onForgotten()
|
||||
|
||||
override fun onForgotten() {
|
||||
if (drawable is Animatable) drawable.stop()
|
||||
drawable.setVisible(false, false)
|
||||
drawable.callback = null
|
||||
}
|
||||
|
||||
override fun applyAlpha(alpha: Float): Boolean {
|
||||
drawable.alpha = (alpha * 255).roundToInt().coerceIn(0, 255)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun applyColorFilter(colorFilter: ColorFilter?): Boolean {
|
||||
drawable.colorFilter = colorFilter?.asAndroidColorFilter()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun applyLayoutDirection(layoutDirection: LayoutDirection): Boolean =
|
||||
drawable.setLayoutDirection(
|
||||
when (layoutDirection) {
|
||||
LayoutDirection.Ltr -> View.LAYOUT_DIRECTION_LTR
|
||||
LayoutDirection.Rtl -> View.LAYOUT_DIRECTION_RTL
|
||||
}
|
||||
)
|
||||
|
||||
override val intrinsicSize: Size get() = drawableIntrinsicSize
|
||||
|
||||
override fun DrawScope.onDraw() {
|
||||
drawIntoCanvas { canvas ->
|
||||
// Reading this ensures that we invalidate when invalidateDrawable() is called
|
||||
drawInvalidateTick
|
||||
|
||||
// Update the Drawable's bounds
|
||||
drawable.setBounds(0, 0, size.width.roundToInt(), size.height.roundToInt())
|
||||
|
||||
canvas.withSave {
|
||||
drawable.draw(canvas.nativeCanvas)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remembers [Drawable] wrapped up as a [Painter]. This function attempts to un-wrap the
|
||||
* drawable contents and use Compose primitives where possible.
|
||||
*
|
||||
* If the provided [drawable] is `null`, an empty no-op painter is returned.
|
||||
*
|
||||
* This function tries to dispatch lifecycle events to [drawable] as much as possible from
|
||||
* within Compose.
|
||||
*
|
||||
* @sample com.google.accompanist.sample.drawablepainter.BasicSample
|
||||
*/
|
||||
@Composable
|
||||
fun rememberDrawablePainter(drawable: Drawable?): Painter = remember(drawable) {
|
||||
when (drawable) {
|
||||
null -> EmptyPainter
|
||||
is BitmapDrawable -> BitmapPainter(drawable.bitmap.asImageBitmap())
|
||||
is ColorDrawable -> ColorPainter(Color(drawable.color))
|
||||
// Since the DrawablePainter will be remembered and it implements RememberObserver, it
|
||||
// will receive the necessary events
|
||||
else -> DrawablePainter(drawable.mutate())
|
||||
}
|
||||
}
|
||||
|
||||
private val Drawable.intrinsicSize: Size
|
||||
get() = when {
|
||||
// Only return a finite size if the drawable has an intrinsic size
|
||||
intrinsicWidth >= 0 && intrinsicHeight >= 0 -> {
|
||||
Size(width = intrinsicWidth.toFloat(), height = intrinsicHeight.toFloat())
|
||||
}
|
||||
else -> Size.Unspecified
|
||||
}
|
||||
|
||||
internal object EmptyPainter : Painter() {
|
||||
override val intrinsicSize: Size get() = Size.Unspecified
|
||||
override fun DrawScope.onDraw() {}
|
||||
}
|
||||
@@ -16,9 +16,17 @@
|
||||
|
||||
package com.android.settingslib.spa.framework.compose
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
|
||||
@Composable
|
||||
fun <T> rememberContext(constructor: (Context) -> T): T {
|
||||
val context = LocalContext.current
|
||||
return remember(context) { constructor(context) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Remember the [State] initialized with the [this].
|
||||
|
||||
@@ -25,8 +25,6 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -39,6 +37,7 @@ import com.android.settingslib.spa.framework.compose.toState
|
||||
import com.android.settingslib.spa.framework.theme.SettingsDimension
|
||||
import com.android.settingslib.spa.framework.theme.SettingsOpacity
|
||||
import com.android.settingslib.spa.framework.theme.SettingsTheme
|
||||
import com.android.settingslib.spa.widget.ui.SettingsTitle
|
||||
|
||||
@Composable
|
||||
internal fun BaseLayout(
|
||||
@@ -94,11 +93,7 @@ private fun BaseIcon(
|
||||
@Composable
|
||||
private fun Titles(title: String, subTitle: @Composable () -> Unit, modifier: Modifier) {
|
||||
Column(modifier) {
|
||||
Text(
|
||||
text = title,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
SettingsTitle(title)
|
||||
subTitle()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@ package com.android.settingslib.spa.widget.preference
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.BatteryChargingFull
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -29,6 +27,7 @@ import androidx.compose.ui.unit.Dp
|
||||
import com.android.settingslib.spa.framework.compose.toState
|
||||
import com.android.settingslib.spa.framework.theme.SettingsDimension
|
||||
import com.android.settingslib.spa.framework.theme.SettingsTheme
|
||||
import com.android.settingslib.spa.widget.ui.SettingsBody
|
||||
|
||||
@Composable
|
||||
internal fun BasePreference(
|
||||
@@ -44,15 +43,7 @@ internal fun BasePreference(
|
||||
) {
|
||||
BaseLayout(
|
||||
title = title,
|
||||
subTitle = {
|
||||
if (summary.value.isNotEmpty()) {
|
||||
Text(
|
||||
text = summary.value,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
}
|
||||
},
|
||||
subTitle = { SettingsBody(summary) },
|
||||
modifier = modifier,
|
||||
icon = icon,
|
||||
enabled = enabled,
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
|
||||
@Composable
|
||||
fun SettingsTitle(title: State<String>) {
|
||||
SettingsTitle(title.value)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsTitle(title: String) {
|
||||
Text(
|
||||
text = title,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsBody(body: State<String>) {
|
||||
SettingsBody(body.value)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsBody(body: String) {
|
||||
if (body.isNotEmpty()) {
|
||||
Text(
|
||||
text = body,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ android {
|
||||
compileSdk 33
|
||||
|
||||
defaultConfig {
|
||||
minSdk minSdk_version
|
||||
minSdk spa_min_sdk
|
||||
targetSdk 33
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
@@ -50,7 +50,7 @@ android {
|
||||
compose true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion compose_version
|
||||
kotlinCompilerExtensionVersion jetpack_compose_version
|
||||
}
|
||||
packagingOptions {
|
||||
resources {
|
||||
@@ -62,6 +62,6 @@ android {
|
||||
dependencies {
|
||||
androidTestImplementation(project(":spa"))
|
||||
androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.3'
|
||||
androidTestImplementation("androidx.compose.ui:ui-test-junit4:$compose_version")
|
||||
androidTestDebugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
|
||||
androidTestImplementation("androidx.compose.ui:ui-test-junit4:$jetpack_compose_version")
|
||||
androidTestDebugImplementation "androidx.compose.ui:ui-test-manifest:$jetpack_compose_version"
|
||||
}
|
||||
|
||||
33
packages/SettingsLib/SpaPrivileged/Android.bp
Normal file
33
packages/SettingsLib/SpaPrivileged/Android.bp
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// 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 {
|
||||
default_applicable_licenses: ["frameworks_base_license"],
|
||||
}
|
||||
|
||||
android_library {
|
||||
name: "SpaPrivilegedLib",
|
||||
|
||||
srcs: ["src/**/*.kt"],
|
||||
|
||||
static_libs: [
|
||||
"SpaLib",
|
||||
"SettingsLib",
|
||||
"androidx.compose.runtime_runtime",
|
||||
],
|
||||
kotlincflags: ["-Xjvm-default=all"],
|
||||
min_sdk_version: "31",
|
||||
}
|
||||
18
packages/SettingsLib/SpaPrivileged/AndroidManifest.xml
Normal file
18
packages/SettingsLib/SpaPrivileged/AndroidManifest.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?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 package="com.android.settingslib.spaprivileged" />
|
||||
1
packages/SettingsLib/SpaPrivileged/OWNERS
Normal file
1
packages/SettingsLib/SpaPrivileged/OWNERS
Normal file
@@ -0,0 +1 @@
|
||||
include platform/frameworks/base:/packages/SettingsLib/Spa/OWNERS
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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.spaprivileged.framework.app
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.produceState
|
||||
import com.android.settingslib.Utils
|
||||
import com.android.settingslib.spa.framework.compose.rememberContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Composable
|
||||
fun rememberAppRepository(): AppRepository = rememberContext(::AppRepositoryImpl)
|
||||
|
||||
interface AppRepository {
|
||||
@Composable
|
||||
fun produceLabel(app: ApplicationInfo): State<String>
|
||||
|
||||
@Composable
|
||||
fun produceIcon(app: ApplicationInfo): State<Drawable?>
|
||||
}
|
||||
|
||||
private class AppRepositoryImpl(private val context: Context) : AppRepository {
|
||||
private val packageManager = context.packageManager
|
||||
|
||||
@Composable
|
||||
override fun produceLabel(app: ApplicationInfo) = produceState(initialValue = "", app) {
|
||||
withContext(Dispatchers.Default) {
|
||||
value = app.loadLabel(packageManager).toString()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun produceIcon(app: ApplicationInfo) =
|
||||
produceState<Drawable?>(initialValue = null, app) {
|
||||
withContext(Dispatchers.Default) {
|
||||
value = Utils.getBadgedIcon(context, app)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.spaprivileged.framework.app
|
||||
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
|
||||
object PackageManagers {
|
||||
fun getPackageInfoAsUser(packageName: String, userId: Int): PackageInfo =
|
||||
PackageManager.getPackageInfoAsUserCached(packageName, 0, userId)
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.spaprivileged.template.app
|
||||
|
||||
import android.content.pm.ApplicationInfo
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.android.settingslib.spa.framework.compose.rememberDrawablePainter
|
||||
import com.android.settingslib.spa.widget.ui.SettingsBody
|
||||
import com.android.settingslib.spa.widget.ui.SettingsTitle
|
||||
import com.android.settingslib.spaprivileged.framework.app.PackageManagers
|
||||
import com.android.settingslib.spaprivileged.framework.app.rememberAppRepository
|
||||
|
||||
@Composable
|
||||
fun AppInfo(packageName: String, userId: Int) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
val packageInfo = remember { PackageManagers.getPackageInfoAsUser(packageName, userId) }
|
||||
Box(modifier = Modifier.padding(8.dp)) {
|
||||
AppIcon(app = packageInfo.applicationInfo, size = 48)
|
||||
}
|
||||
AppLabel(packageInfo.applicationInfo)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
SettingsBody(packageInfo.versionName)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AppIcon(app: ApplicationInfo, size: Int) {
|
||||
val appRepository = rememberAppRepository()
|
||||
Image(
|
||||
painter = rememberDrawablePainter(appRepository.produceIcon(app).value),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(size.dp)
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AppLabel(app: ApplicationInfo) {
|
||||
val appRepository = rememberAppRepository()
|
||||
SettingsTitle(appRepository.produceLabel(app))
|
||||
}
|
||||
Reference in New Issue
Block a user