Skip to content

Commit 3af70d3

Browse files
neobuddy89joeyhuab
authored andcommitted
SystemUI: Add QS brightness slider gradient customization
Signed-off-by: Pranav Vashi <neobuddy89@gmail.com>
1 parent cd70b36 commit 3af70d3

2 files changed

Lines changed: 107 additions & 4 deletions

File tree

core/java/android/provider/Settings.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7717,6 +7717,12 @@ public static void setShowGTalkServiceStatusForUser(ContentResolver cr, boolean
77177717
*/
77187718
public static final String QS_TILE_GRADIENT = "qs_tile_gradient";
77197719

7720+
/**
7721+
* Gradient on QS brightness slider
7722+
* @hide
7723+
*/
7724+
public static final String QS_BRIGHTNESS_SLIDER_GRADIENT = "qs_brightness_slider_gradient";
7725+
77207726
/**
77217727
* Keys we no longer back up under the current schema, but want to continue to
77227728
* process when restoring historical backup datasets.

packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,16 @@ import androidx.compose.ui.draw.drawWithCache
7373
import androidx.compose.ui.draw.drawWithContent
7474
import androidx.compose.ui.geometry.CornerRadius
7575
import androidx.compose.ui.geometry.Offset
76+
import androidx.compose.ui.geometry.RoundRect
7677
import androidx.compose.ui.geometry.Size
78+
import androidx.compose.ui.graphics.Brush
7779
import androidx.compose.ui.graphics.Color
7880
import androidx.compose.ui.graphics.ColorFilter
81+
import androidx.compose.ui.graphics.Outline
82+
import androidx.compose.ui.graphics.Path
7983
import androidx.compose.ui.graphics.asImageBitmap
8084
import androidx.compose.ui.graphics.drawscope.DrawScope
85+
import androidx.compose.ui.graphics.drawscope.clipPath
8186
import androidx.compose.ui.graphics.drawscope.scale
8287
import androidx.compose.ui.graphics.drawscope.translate
8388
import androidx.compose.ui.graphics.painter.BitmapPainter
@@ -164,6 +169,9 @@ fun BrightnessSlider(
164169
else -> Dimensions.SliderTrackRoundedCorner
165170
}
166171

172+
val trackShape = RoundedCornerShape(trackCornerDp)
173+
val brightnessGradient = brightnessSliderGradient()
174+
167175
var value by remember(gammaValue) { mutableIntStateOf(gammaValue) }
168176
val animatedValue by
169177
animateFloatAsState(targetValue = value.toFloat(), label = "BrightnessSliderAnimatedValue")
@@ -188,7 +196,7 @@ fun BrightnessSlider(
188196
} else {
189197
null
190198
}
191-
val colors = colors()
199+
val colors = colors(brightnessGradient)
192200

193201
// The value state is recreated every time gammaValue changes, so we recreate this derivedState
194202
// We have to use value as that's the value that changes when the user is dragging (gammaValue
@@ -359,9 +367,31 @@ fun BrightnessSlider(
359367
BrightnessSliderMotionTestKeys.InactiveIconAlpha
360368
}
361369
.height(TrackHeight)
362-
.drawWithContent {
370+
.drawWithCache {
371+
372+
val outline = trackShape.createOutline(size, layoutDirection, this)
373+
val clipPath = outline.asPath()
374+
375+
onDrawWithContent {
363376
drawContent()
364377

378+
val gradient = brightnessGradient
379+
if (gradient != null) {
380+
val gapPx = ThumbTrackGapSize.toPx()
381+
val fraction = sliderState.coercedValueAsFraction
382+
val activeEnd = (size.width * fraction - gapPx).coerceAtLeast(0f)
383+
384+
if (activeEnd > 0f) {
385+
clipPath(clipPath) {
386+
drawRect(
387+
brush = gradient.brush,
388+
topLeft = Offset.Zero,
389+
size = Size(activeEnd.coerceAtMost(size.width), size.height)
390+
)
391+
}
392+
}
393+
}
394+
365395
val yOffset = size.height / 2 - IconSize.toSize().height / 2
366396
val activeTrackStart = 0f
367397
val activeTrackEnd =
@@ -393,6 +423,7 @@ fun BrightnessSlider(
393423
iconActiveAlphaAnimatable.value,
394424
)
395425
}
426+
}
396427
},
397428
trackCornerSize = trackCornerDp,
398429
trackInsideCornerSize = 2.dp,
@@ -425,6 +456,14 @@ fun BrightnessSlider(
425456
}
426457
}
427458

459+
fun Outline.asPath(): Path {
460+
return when (this) {
461+
is Outline.Generic -> path
462+
is Outline.Rounded -> Path().apply { addRoundRect(roundRect) }
463+
is Outline.Rectangle -> Path().apply { addRect(rect) }
464+
}
465+
}
466+
428467
@Composable
429468
fun rememberSliderShapeMode(): Int {
430469
val context = LocalContext.current
@@ -465,6 +504,62 @@ fun rememberSliderShapeMode(): Int {
465504
return shapeMode
466505
}
467506

507+
private data class BrightnessGradient(
508+
val brush: Brush,
509+
)
510+
511+
@Composable
512+
private fun rememberSliderGradient(): Boolean {
513+
val context = LocalContext.current
514+
val contentResolver = context.contentResolver
515+
516+
fun readEnabled(): Boolean {
517+
return try {
518+
Settings.System.getIntForUser(
519+
contentResolver, Settings.System.QS_BRIGHTNESS_SLIDER_GRADIENT, 0,
520+
UserHandle.USER_CURRENT
521+
) != 0
522+
} catch (_: Throwable) {
523+
false
524+
}
525+
}
526+
527+
var enabled by remember { mutableStateOf(readEnabled()) }
528+
529+
DisposableEffect(contentResolver) {
530+
val observer = object : ContentObserver(null) {
531+
override fun onChange(selfChange: Boolean) {
532+
enabled = readEnabled()
533+
}
534+
}
535+
536+
contentResolver.registerContentObserver(
537+
Settings.System.getUriFor(Settings.System.QS_BRIGHTNESS_SLIDER_GRADIENT),
538+
false, observer, UserHandle.USER_ALL
539+
)
540+
541+
onDispose {
542+
contentResolver.unregisterContentObserver(observer)
543+
}
544+
}
545+
546+
return enabled
547+
}
548+
549+
@Composable
550+
private fun brightnessSliderGradient(): BrightnessGradient? {
551+
if (!rememberSliderGradient()) return null
552+
553+
val colors = listOf(
554+
MaterialTheme.colorScheme.primary,
555+
MaterialTheme.colorScheme.secondary
556+
)
557+
558+
return BrightnessGradient(
559+
brush = Brush.horizontalGradient(colors)
560+
)
561+
}
562+
468563
private fun Modifier.sliderBackground(color: Color, corner: Dp) = drawWithCache {
469564
val offsetAround = SliderBackgroundFrameSize.toSize()
470565
val newSize = Size(size.width + 2 * offsetAround.width, size.height + 2 * offsetAround.height)
@@ -719,9 +814,11 @@ object BrightnessSliderMotionTestKeys {
719814
}
720815

721816
@Composable
722-
private fun colors(): SliderColors {
723-
return SliderDefaults.colors()
817+
private fun colors(brightnessGradient: BrightnessGradient?): SliderColors {
818+
val base = SliderDefaults.colors()
819+
return base
724820
.copy(
821+
activeTrackColor = if (brightnessGradient != null) Color.Transparent else base.activeTrackColor,
725822
inactiveTrackColor = LocalAndroidColorScheme.current.surfaceEffect1,
726823
activeTickColor = MaterialTheme.colorScheme.onPrimary,
727824
inactiveTickColor = MaterialTheme.colorScheme.onSurface,

0 commit comments

Comments
 (0)