diff --git a/app/ui/src/main/java/de/mm20/launcher2/ui/component/FakeSplashScreen.kt b/app/ui/src/main/java/de/mm20/launcher2/ui/component/FakeSplashScreen.kt index b1064e6e..dc23ad2b 100644 --- a/app/ui/src/main/java/de/mm20/launcher2/ui/component/FakeSplashScreen.kt +++ b/app/ui/src/main/java/de/mm20/launcher2/ui/component/FakeSplashScreen.kt @@ -3,6 +3,8 @@ package de.mm20.launcher2.ui.component import android.content.Context import android.content.pm.PackageManager import android.content.res.Resources +import android.graphics.drawable.AdaptiveIconDrawable +import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.util.TypedValue import androidx.compose.animation.animateColorAsState @@ -33,6 +35,9 @@ import de.mm20.launcher2.search.SavableSearchable import de.mm20.launcher2.search.data.LauncherApp import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import kotlin.math.abs +import kotlin.math.pow +import kotlin.math.sqrt @Composable fun FakeSplashScreen( @@ -92,7 +97,12 @@ fun rememberSplashScreenData(searchable: SavableSearchable?): SplashScreenData { val context = LocalContext.current val defaultBackgroundColor = MaterialTheme.colorScheme.background val state = remember { - mutableStateOf(SplashScreenData(backgroundColor = defaultBackgroundColor, iconSize = 288.dp)) + mutableStateOf( + SplashScreenData( + backgroundColor = defaultBackgroundColor, + iconSize = 288.dp + ) + ) } LaunchedEffect(searchable) { @@ -184,7 +194,7 @@ fun rememberSplashScreenData(searchable: SavableSearchable?): SplashScreenData { var iconSize = 288.dp - var iconBackground = if (typedValue.isColor && typedValue.data != 0) { + val iconBackground = if (typedValue.isColor && typedValue.data != 0) { iconSize = 240.dp Color(typedValue.data) } else { @@ -193,7 +203,19 @@ fun rememberSplashScreenData(searchable: SavableSearchable?): SplashScreenData { if (icon == null) { icon = activityInfo.loadIcon(context.packageManager) - iconSize = 160.dp + iconSize = 240.dp + } + + if (icon is AdaptiveIconDrawable) { + val bg = icon.background + if (bg is ColorDrawable && backgroundColor != null && iconBackground == null && + isRgbSimilarInHsv(bg.color, backgroundColor) + ) { + icon = icon.foreground + iconSize = 288.dp + } else { + iconSize = 160.dp + } } state.value = SplashScreenData( @@ -211,4 +233,51 @@ fun rememberSplashScreenData(searchable: SavableSearchable?): SplashScreenData { } internal val TypedValue.isColor - get() = type in TypedValue.TYPE_FIRST_COLOR_INT..TypedValue.TYPE_LAST_COLOR_INT \ No newline at end of file + get() = type in TypedValue.TYPE_FIRST_COLOR_INT..TypedValue.TYPE_LAST_COLOR_INT + + +/* + * From: https://android.googlesource.com/platform/frameworks/base/+/f05f9b960832b6272b6740721c0a4bbd1ce632c1/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java#550 + * Copyright (C) 2020 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. + */ +internal fun isRgbSimilarInHsv(a: Int, b: Int): Boolean { + if (a == b) { + return true + } + val lumA: Float = android.graphics.Color.luminance(a) + val lumB: Float = android.graphics.Color.luminance(b) + val contrastRatio = + if (lumA > lumB) (lumA + 0.05f) / (lumB + 0.05f) else (lumB + 0.05f) / (lumA + 0.05f) + if (contrastRatio < 2) { + return true + } + val aHsv = FloatArray(3) + val bHsv = FloatArray(3) + android.graphics.Color.colorToHSV(a, aHsv) + android.graphics.Color.colorToHSV(b, bHsv) + // Minimum degree of the hue between two colors, the result range is 0-180. + var minAngle = abs(aHsv[0] - bHsv[0]).toInt() + minAngle = (minAngle + 180) % 360 - 180 + + // Calculate the difference between two colors based on the HSV dimensions. + val normalizeH = minAngle / 180f + val squareH = normalizeH.toDouble().pow(2.0) + val squareS = (aHsv[1] - bHsv[1]).toDouble().pow(2.0) + val squareV = (aHsv[2] - bHsv[2]).toDouble().pow(2.0) + val square = squareH + squareS + squareV + val mean = square / 3 + val root = sqrt(mean) + return root < 0.1 +}