diff --git a/build.gradle b/build.gradle index e1477d14631..0e114fd4c13 100644 --- a/build.gradle +++ b/build.gradle @@ -338,7 +338,7 @@ dependencies { implementation "androidx.recyclerview:recyclerview:1.3.2" implementation "androidx.preference:preference-ktx:1.2.1" - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0' implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2' implementation 'com.github.ChickenHook:RestrictionBypass:2.2' implementation 'dev.rikka.tools.refine:runtime:4.4.0' diff --git a/lawnchair/res/drawable/ic_firefox.xml b/lawnchair/res/drawable/ic_firefox.xml new file mode 100644 index 00000000000..247d797bcfe --- /dev/null +++ b/lawnchair/res/drawable/ic_firefox.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/lawnchair/res/drawable/ic_firefox_tinted.xml b/lawnchair/res/drawable/ic_firefox_tinted.xml new file mode 100644 index 00000000000..4beb0fdbdac --- /dev/null +++ b/lawnchair/res/drawable/ic_firefox_tinted.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/lawnchair/res/drawable/ic_iceraven.xml b/lawnchair/res/drawable/ic_iceraven.xml new file mode 100644 index 00000000000..7308766f81f --- /dev/null +++ b/lawnchair/res/drawable/ic_iceraven.xml @@ -0,0 +1,14 @@ + + + + diff --git a/lawnchair/res/drawable/ic_iceraven_tinted.xml b/lawnchair/res/drawable/ic_iceraven_tinted.xml new file mode 100644 index 00000000000..72268352ec1 --- /dev/null +++ b/lawnchair/res/drawable/ic_iceraven_tinted.xml @@ -0,0 +1,14 @@ + + + + \ No newline at end of file diff --git a/lawnchair/res/values/strings.xml b/lawnchair/res/values/strings.xml index a7e27c999eb..a0669d6a6bc 100644 --- a/lawnchair/res/values/strings.xml +++ b/lawnchair/res/values/strings.xml @@ -566,6 +566,9 @@ YouTube Pixel Search Yandex + Firefox + Iceraven + Mull %1$s and Lawnchair have a revenue share agreement.\n\nSearching with %1$s helps support Lawnchair. diff --git a/lawnchair/src/app/lawnchair/LawnchairLauncher.kt b/lawnchair/src/app/lawnchair/LawnchairLauncher.kt index 91c6de9a21c..6f4ea68e133 100644 --- a/lawnchair/src/app/lawnchair/LawnchairLauncher.kt +++ b/lawnchair/src/app/lawnchair/LawnchairLauncher.kt @@ -334,6 +334,7 @@ class LawnchairLauncher : QuickstepLauncher() { override fun onDestroy() { super.onDestroy() + // Only actually closes if required, safe to call if not enabled SmartspacerClient.close() } diff --git a/lawnchair/src/app/lawnchair/qsb/providers/Firefox.kt b/lawnchair/src/app/lawnchair/qsb/providers/Firefox.kt new file mode 100644 index 00000000000..99c610793ad --- /dev/null +++ b/lawnchair/src/app/lawnchair/qsb/providers/Firefox.kt @@ -0,0 +1,25 @@ +package app.lawnchair.qsb.providers + +import android.content.Intent +import app.lawnchair.qsb.ThemingMethod +import com.android.launcher3.R + +data object Firefox : QsbSearchProvider( + id = "Firefox", + name = R.string.search_provider_firefox, + icon = R.drawable.ic_firefox, + themedIcon = R.drawable.ic_firefox_tinted, + themingMethod = ThemingMethod.TINT, + packageName = "org.mozilla.firefox", + action = "org.mozilla.fenix.OPEN_TAB", + className = "org.mozilla.fenix.IntentReceiverActivity", + website = "https://play.google.com/store/apps/details?id=org.mozilla.firefox", + type = QsbSearchProviderType.APP, + supportVoiceIntent = false, +) { + + override fun handleCreateVoiceIntent(): Intent = + Intent(action) + .addFlags(INTENT_FLAGS) + .setClassName(packageName, "org.chromium.chrome.browser.VoiceSearchActivity") +} diff --git a/lawnchair/src/app/lawnchair/qsb/providers/Iceraven.kt b/lawnchair/src/app/lawnchair/qsb/providers/Iceraven.kt new file mode 100644 index 00000000000..c51b0e00b43 --- /dev/null +++ b/lawnchair/src/app/lawnchair/qsb/providers/Iceraven.kt @@ -0,0 +1,25 @@ +package app.lawnchair.qsb.providers + +import android.content.Intent +import app.lawnchair.qsb.ThemingMethod +import com.android.launcher3.R + +data object Iceraven : QsbSearchProvider( + id = "Iceraven", + name = R.string.search_provider_iceraven, + icon = R.drawable.ic_iceraven, + themedIcon = R.drawable.ic_iceraven_tinted, + themingMethod = ThemingMethod.TINT, + packageName = "io.github.forkmaintainers.iceraven", + action = "org.mozilla.fenix.OPEN_TAB", + className = "org.mozilla.fenix.IntentReceiverActivity", + website = "github.com/fork-maintainers/iceraven-browser/releases/latest", + type = QsbSearchProviderType.APP, + supportVoiceIntent = true, +) { + + override fun handleCreateVoiceIntent(): Intent = + Intent(action) + .addFlags(INTENT_FLAGS) + .setClassName(packageName, "org.chromium.chrome.browser.VoiceSearchActivity") +} diff --git a/lawnchair/src/app/lawnchair/qsb/providers/Mull.kt b/lawnchair/src/app/lawnchair/qsb/providers/Mull.kt new file mode 100644 index 00000000000..7842b101d93 --- /dev/null +++ b/lawnchair/src/app/lawnchair/qsb/providers/Mull.kt @@ -0,0 +1,25 @@ +package app.lawnchair.qsb.providers + +import android.content.Intent +import app.lawnchair.qsb.ThemingMethod +import com.android.launcher3.R + +data object Mull : QsbSearchProvider( + id = "Mull", + name = R.string.search_provider_mull, + icon = R.drawable.ic_mull, + themedIcon = R.drawable.ic_mull_tinted, + themingMethod = ThemingMethod.TINT, + packageName = "us.spotco.fennec_dos", + action = "org.mozilla.fenix.OPEN_TAB", + className = "org.mozilla.fenix.IntentReceiverActivity", + website = "gitlab.com/divested-mobile/mull-fenix", + type = QsbSearchProviderType.APP, + supportVoiceIntent = true, +) { + + override fun handleCreateVoiceIntent(): Intent = + Intent(action) + .addFlags(INTENT_FLAGS) + .setClassName(packageName, "org.chromium.chrome.browser.VoiceSearchActivity") +} diff --git a/lawnchair/src/app/lawnchair/qsb/providers/QsbSearchProvider.kt b/lawnchair/src/app/lawnchair/qsb/providers/QsbSearchProvider.kt index 585b8f5f911..1409194c9cb 100644 --- a/lawnchair/src/app/lawnchair/qsb/providers/QsbSearchProvider.kt +++ b/lawnchair/src/app/lawnchair/qsb/providers/QsbSearchProvider.kt @@ -133,7 +133,10 @@ sealed class QsbSearchProvider( Bing, Brave, Yandex, + Firefox, + Iceraven, Startpage, + Mull, ) /** diff --git a/lawnchair/src/app/lawnchair/search/adapter/SearchTargetFactory.kt b/lawnchair/src/app/lawnchair/search/adapter/SearchTargetFactory.kt index 0b270645963..b9a769dde07 100644 --- a/lawnchair/src/app/lawnchair/search/adapter/SearchTargetFactory.kt +++ b/lawnchair/src/app/lawnchair/search/adapter/SearchTargetFactory.kt @@ -37,6 +37,7 @@ import java.io.IOException import java.io.InputStream import java.security.MessageDigest import java.util.Locale +import java.util.UUID import okio.ByteString class SearchTargetFactory( @@ -93,7 +94,8 @@ class SearchTargetFactory( ): SearchTargetCompat { val result = calculation.result val equation = calculation.equation - val id = "calculator:$result" + val uuid = UUID.randomUUID().toString() + val id = "calculator:$uuid" val action = SearchActionCompat.Builder(id, result) .setIcon( Icon.createWithResource(context, R.drawable.calculator) diff --git a/lawnchair/src/app/lawnchair/search/algorithms/data/Calculation.kt b/lawnchair/src/app/lawnchair/search/algorithms/data/Calculation.kt index dcd21f8f084..e05585b32f0 100644 --- a/lawnchair/src/app/lawnchair/search/algorithms/data/Calculation.kt +++ b/lawnchair/src/app/lawnchair/search/algorithms/data/Calculation.kt @@ -1,6 +1,8 @@ package app.lawnchair.search.algorithms.data import app.lawnchair.search.algorithms.data.calculator.Expressions +import java.math.BigDecimal +import java.math.MathContext data class Calculation( val equation: String, @@ -12,9 +14,17 @@ fun calculateEquationFromString( query: String, ): Calculation { return try { - val result = Expressions() - .eval(query) - .toString() + val evaluatedValue = Expressions().eval(query) + val roundedValue = evaluatedValue.round(MathContext.DECIMAL64) + val formattedValue = roundedValue.stripTrailingZeros() + val absoluteValue = formattedValue.abs() + val threshold = BigDecimal("9999999999999999") + + val result = if (absoluteValue > threshold) { + formattedValue.toString() + } else { + formattedValue.toPlainString() + } Calculation( equation = query, diff --git a/lawnchair/src/app/lawnchair/search/algorithms/data/calculator/Expressions.kt b/lawnchair/src/app/lawnchair/search/algorithms/data/calculator/Expressions.kt index 4f258bb73f1..d4e89ea4f7a 100644 --- a/lawnchair/src/app/lawnchair/search/algorithms/data/calculator/Expressions.kt +++ b/lawnchair/src/app/lawnchair/search/algorithms/data/calculator/Expressions.kt @@ -18,8 +18,8 @@ class Expressions { private val evaluator = Evaluator() init { - define("pi", Math.PI) - define("e", Math.E) + define("pi", BigDecimal(Math.PI).setScale(33, RoundingMode.HALF_EVEN)) + define("e", BigDecimal(Math.E).setScale(33, RoundingMode.HALF_EVEN)) evaluator.addFunction("abs") { arguments -> if (arguments.size != 1) { diff --git a/lawnchair/src/app/lawnchair/search/algorithms/data/calculator/internal/Evaluator.kt b/lawnchair/src/app/lawnchair/search/algorithms/data/calculator/internal/Evaluator.kt index 9eb51e91917..8e9ff478ae6 100644 --- a/lawnchair/src/app/lawnchair/search/algorithms/data/calculator/internal/Evaluator.kt +++ b/lawnchair/src/app/lawnchair/search/algorithms/data/calculator/internal/Evaluator.kt @@ -23,7 +23,7 @@ import java.util.Locale import kotlin.math.pow internal class Evaluator : ExprVisitor { - internal var mathContext: MathContext = MathContext.DECIMAL64 + internal var mathContext: MathContext = MathContext.DECIMAL128 private val variables: LinkedHashMap = linkedMapOf() private val functions: MutableMap = mutableMapOf() diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/controls/SliderPreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/controls/SliderPreference.kt index 0b2ae921576..030b0014152 100644 --- a/lawnchair/src/app/lawnchair/ui/preferences/components/controls/SliderPreference.kt +++ b/lawnchair/src/app/lawnchair/ui/preferences/components/controls/SliderPreference.kt @@ -138,10 +138,11 @@ fun SliderPreference( fun getSteps(valueRange: ClosedFloatingPointRange, step: Float): Int { if (step == 0f) return 0 - val start = valueRange.start - val end = valueRange.endInclusive - val steps = ((end - start) / step).toInt() - require(start + step * steps == end) { + val start = valueRange.start.toBigDecimal() + val end = valueRange.endInclusive.toBigDecimal() + val decimalSteps = (end - start) / step.toBigDecimal() + val steps = decimalSteps.toInt() + require(decimalSteps.compareTo(steps.toBigDecimal()) == 0) { "value range must be a multiple of step" } return steps - 1 diff --git a/res/drawable/ic_mull.xml b/res/drawable/ic_mull.xml new file mode 100644 index 00000000000..079ee421235 --- /dev/null +++ b/res/drawable/ic_mull.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + diff --git a/res/drawable/ic_mull_tinted.xml b/res/drawable/ic_mull_tinted.xml new file mode 100644 index 00000000000..44768626f3e --- /dev/null +++ b/res/drawable/ic_mull_tinted.xml @@ -0,0 +1,46 @@ + + + + + + + + + +