diff --git a/app/src/main/java/com/sevtinge/hyperceiler/module/app/Home/Phone/HomeT.java b/app/src/main/java/com/sevtinge/hyperceiler/module/app/Home/Phone/HomeT.java
index cccd79cf51..9c0c617c77 100644
--- a/app/src/main/java/com/sevtinge/hyperceiler/module/app/Home/Phone/HomeT.java
+++ b/app/src/main/java/com/sevtinge/hyperceiler/module/app/Home/Phone/HomeT.java
@@ -110,6 +110,7 @@
import com.sevtinge.hyperceiler.module.hook.home.recent.TaskViewVertical;
import com.sevtinge.hyperceiler.module.hook.home.recent.UnlockPin;
import com.sevtinge.hyperceiler.module.hook.home.title.AnimParamCustom;
+import com.sevtinge.hyperceiler.module.hook.home.title.AppBlurAnim;
import com.sevtinge.hyperceiler.module.hook.home.title.BigIconCorner;
import com.sevtinge.hyperceiler.module.hook.home.title.DisableHideFile;
import com.sevtinge.hyperceiler.module.hook.home.title.DisableHideTheme;
@@ -202,7 +203,7 @@ public void handleLoadPackage() {
initHook(new PinyinArrangement(), mPrefsMap.getBoolean("home_drawer_pinyin"));
// 最近任务
- initHook(BlurLevel.INSTANCE, mPrefsMap.getStringAsInt("home_recent_blur_level", 6) != 6);
+ initHook(BlurLevel.INSTANCE, mPrefsMap.getStringAsInt("home_recent_blur_level", 6) != 6 && !mPrefsMap.getBoolean("home_title_app_blur_enable"));
initHook(DisableRecentViewWallpaperDarken.INSTANCE, mPrefsMap.getBoolean("home_recent_disable_wallpaper_dimming"));
initHook(HideStatusBarWhenEnterRecent.INSTANCE, mPrefsMap.getBoolean("home_recent_hide_status_bar_in_task_view"));
initHook(RemoveCardAnim.INSTANCE, mPrefsMap.getBoolean("home_recent_modify_animation"));
@@ -232,6 +233,7 @@ public void handleLoadPackage() {
initHook(DisableHideGoogle.INSTANCE, mPrefsMap.getBoolean("home_title_disable_hide_google"));
initHook(new FakeNonDefaultIcon(), mPrefsMap.getBoolean("fake_non_default_icon"));
initHook(new AnimParamCustom(), mPrefsMap.getBoolean("home_title_custom_anim_param_main"));
+ initHook(AppBlurAnim.INSTANCE, mPrefsMap.getBoolean("home_title_app_blur_enable"));
// initHook(new IconScaleHook()/*, mPrefsMap.getInt("home_title_icon_scale", 100) != 100*/);
// 标题
@@ -285,7 +287,7 @@ public void handleLoadPackage() {
// 实验性功能
initHook(BlurWhenShowShortcutMenu.INSTANCE, mPrefsMap.getBoolean("home_other_shortcut_background_blur"));
- initHook(FolderBlur.INSTANCE, mPrefsMap.getBoolean("home_folder_blur"));
+ initHook(FolderBlur.INSTANCE, mPrefsMap.getBoolean("home_folder_blur") && !mPrefsMap.getBoolean("home_title_app_blur_enable"));
initHook(new FoldDock(), mPrefsMap.getBoolean("home_other_fold_dock"));
// initHook(new AllAppsBlur); // ??
initHook(new FixAnimation(), mPrefsMap.getBoolean("home_title_fix_animation"));
diff --git a/app/src/main/java/com/sevtinge/hyperceiler/module/hook/home/title/AppBlurAnim.kt b/app/src/main/java/com/sevtinge/hyperceiler/module/hook/home/title/AppBlurAnim.kt
new file mode 100644
index 0000000000..230ecd5bd6
--- /dev/null
+++ b/app/src/main/java/com/sevtinge/hyperceiler/module/hook/home/title/AppBlurAnim.kt
@@ -0,0 +1,333 @@
+package com.sevtinge.hyperceiler.module.hook.home.title
+
+import android.app.*
+import android.view.*
+import android.view.animation.*
+import com.github.kyuubiran.ezxhelper.ClassUtils.loadClass
+import com.github.kyuubiran.ezxhelper.finders.MethodFinder.`-Static`.methodFinder
+import com.sevtinge.hyperceiler.module.base.*
+import com.sevtinge.hyperceiler.utils.*
+import com.sevtinge.hyperceiler.utils.blur.*
+import com.sevtinge.hyperceiler.utils.log.*
+import de.robv.android.xposed.*
+import java.util.concurrent.*
+
+object AppBlurAnim : BaseHook() {
+ private val appsBlurRadius by lazy {
+ mPrefsMap.getInt("home_title_app_blur_radius", 100)
+ }
+ private val appsDimAlpha by lazy {
+ mPrefsMap.getInt("home_title_app_dim_alpha", 50)
+ }
+ private val wallBlurRadius by lazy {
+ mPrefsMap.getInt("home_title_app_blur_radius", 100)
+ }
+ private val wallDimAlpha by lazy {
+ mPrefsMap.getInt("home_title_app_dim_alpha", 50)
+ }
+ private val minusBlurRadius by lazy {
+ mPrefsMap.getInt("home_title_app_blur_radius", 100)
+ }
+ private val minusDimAlpha by lazy {
+ mPrefsMap.getInt("home_title_app_dim_alpha", 50)
+ }
+ private val minusOverlapMode by lazy {
+ true
+ }
+ private val minusShowLaunch by lazy {
+ true
+ }
+ private val fixSmallWindowAnim by lazy {
+ mPrefsMap.getBoolean("home_title_fix_small_window")
+ }
+ private var isStartingApp: Boolean = false
+
+ private val blurUtil by lazy {
+ loadClass("com.miui.home.launcher.common.BlurUtilities")
+ }
+ private val blur by lazy {
+ loadClass("com.miui.home.launcher.common.BlurUtils")
+ }
+ private val mainThreadExecutor by lazy {
+ loadClass("com.miui.home.recents.TouchInteractionService")
+ .getStaticObjectFieldOrNull("MAIN_THREAD_EXECUTOR") as Executor
+ }
+ private val overviewState by lazy {
+ loadClass("com.miui.home.launcher.LauncherState")
+ .getStaticObjectFieldOrNull("OVERVIEW")
+ }
+
+ // by HyperHelper
+ override fun init() {
+ var transitionBlurView : MiBlurView? = null
+ var wallpaperBlurView : MiBlurView? = null
+ var minusBlurView : MiBlurView? = null
+
+ blurUtil.methodFinder().filterByName("setBackgroundBlurEnabled")
+ .filterStatic().first()
+ .hookAfterMethod { param ->
+ val launcher = param.args[0]
+ transitionBlurView = MiBlurView(launcher as Activity)
+ transitionBlurView?.let {
+ it.setBlur(appsBlurRadius)
+ it.setDim(appsDimAlpha)
+ //it.setBackgroundColor(1204495145)
+ it.setPassWindowBlur(true)
+ }
+
+ wallpaperBlurView = MiBlurView(launcher)
+ wallpaperBlurView?.let {
+ it.setBlur(wallBlurRadius)
+ it.setDim(wallDimAlpha)
+ //it.setBackgroundColor(1204495145)
+ it.setPassWindowBlur(true)
+ }
+
+ minusBlurView = MiBlurView(launcher)
+ minusBlurView?.let {
+ it.setBlur(minusBlurRadius)
+ it.setDim(minusDimAlpha)
+ it.setNonlinear(false, LinearInterpolator())
+ it.setPassWindowBlur(true)
+ }
+
+ val viewGroup = XposedHelpers.getObjectField(launcher, "mLauncherView") as ViewGroup
+ viewGroup.addView(transitionBlurView, viewGroup.indexOfChild(
+ XposedHelpers.getObjectField(launcher, "mOverviewPanel") as View
+ ).coerceAtLeast(0))
+ viewGroup.addView(wallpaperBlurView, 0)
+ if (minusOverlapMode) {
+ viewGroup.addView(minusBlurView)
+ }
+ else {
+ viewGroup.addView(minusBlurView, 0)
+ }
+ }
+
+ // Remove blur view from Launcher
+ loadClass("com.miui.home.recents.views.FloatingIconView").methodFinder()
+ .filterByName("onLauncherDestroy").first()
+ .hookAfterMethod {
+ val viewGroup =
+ XposedHelpers.getObjectField(it.args[0], "mLauncherView") as ViewGroup
+ if (transitionBlurView?.isAttachedToWindow == true) {
+ viewGroup.removeView(transitionBlurView)
+ }
+ if (wallpaperBlurView?.isAttachedToWindow == true) {
+ viewGroup.removeView(wallpaperBlurView)
+ }
+ if (minusBlurView?.isAttachedToWindow == true) {
+ viewGroup.removeView(minusBlurView)
+ }
+ transitionBlurView = null
+ wallpaperBlurView = null
+ minusBlurView = null
+ }
+
+ blur.methodFinder().filterByName("fastBlur").filterByParamCount(3)
+ .first().hookBeforeMethod {
+ wallpaperBlurView?.show(it.args[2] as Boolean, it.args[0] as Float)
+ it.result = null
+ }
+
+ blur.methodFinder().filterByName("fastBlur").filterByParamCount(4)
+ .first().hookBeforeMethod {
+ wallpaperBlurView?.showWithDuration(it.args[2] as Boolean, it.args[0] as Float, 350)
+ it.result = null
+ }
+
+ // Blur when launching app
+ blur.methodFinder().filterByName("fastBlurWhenStartOpenOrCloseApp")
+ .first().hookBeforeMethod {
+ val isOpen = it.args[0] as Boolean
+ if (isOpen) {
+ XposedLogUtils.logD("111")
+ transitionBlurView?.show(true)
+ isStartingApp = true
+ }
+ else {
+ XposedLogUtils.logD("222")
+ // "isOpen" seems to always be true
+ if (shouldBlurWallpaper(it.args[1] ?: return@hookBeforeMethod)) {
+ wallpaperBlurView?.show(false)
+ }
+ transitionBlurView?.show(false)
+ transitionBlurView?.hide(true)
+ }
+ it.result = null
+ }
+
+ blur.methodFinder().filterByName("fastBlurWhenFinishOpenOrCloseApp")
+ .first().replaceMethod {
+ transitionBlurView?.hide(false)
+ if (shouldBlurWallpaper(it.args[0] ?: return@replaceMethod null)) {
+ wallpaperBlurView?.show(false)
+ }
+ else {
+ wallpaperBlurView?.hide(false)
+ }
+ if (isStartingApp) {
+ isStartingApp = false
+ } else {
+
+ }
+ }
+
+ // Widely used
+ blur.methodFinder().filterByName("fastBlurWhenUseCompleteRecentsBlur")
+ .first().replaceMethod {
+ val useAnim = it.args[2] as Boolean
+ mainThreadExecutor.execute {
+ if (useAnim) {
+ transitionBlurView?.show(true, it.args[1] as Float)
+
+ isStartingApp = false
+ } else if (isStartingApp) {
+ transitionBlurView?.restore()
+ } else {
+ transitionBlurView?.show(false, it.args[1] as Float)
+ }
+ }
+ }
+
+ // Use with "fastBlurWhenUseCompleteRecentsBlur"
+ blur.methodFinder().filterByName("resetBlurWhenUseCompleteRecentsBlur")
+ .first().replaceMethod {
+ mainThreadExecutor.execute {
+ val useAnim = it.args[1] as Boolean
+ if (shouldBlurWallpaper(it.args[0] ?: return@execute)) {
+ wallpaperBlurView?.show(false)
+ }
+ transitionBlurView?.hide(useAnim)
+ }
+ }
+
+ // Blur when entering recent tasks
+ // Skip when triggered by a gesture in the app
+ blur.methodFinder().filterByName("fastBlurWhenEnterRecents")
+ .first().replaceMethod {
+ if (XposedHelpers.getBooleanField(it.args[1], "mIsFromFsGesture")) {
+ return@replaceMethod null
+ }
+ transitionBlurView?.show(it.args[2] as Boolean)
+ }
+
+ // Reset blur when exiting recent tasks
+ // Skip when triggered by a gesture in the app
+ blur.methodFinder().filterByName("fastBlurWhenExitRecents")
+ .first().replaceMethod {
+ if (XposedHelpers.getBooleanField(it.args[1], "mIsFromFsGesture")) {
+ return@replaceMethod null
+ }
+ val useAnim = it.args[2] as Boolean
+ if (shouldBlurWallpaper(it.args[0] ?: return@replaceMethod null)) {
+ wallpaperBlurView?.show(false)
+ }
+ // Forced animation to avoid flickering when opening a small window
+ // not sure if it has a negative effect for now
+ transitionBlurView?.hide(useAnim || fixSmallWindowAnim)
+ }
+
+
+ blur.methodFinder().filterByName("resetBlur")
+ .first().replaceMethod {
+ mainThreadExecutor.execute {
+ val useAnim = it.args[1] as Boolean
+ if (shouldBlurWallpaper(it.args[0] ?: return@execute)) {
+ wallpaperBlurView?.show(false)
+ }
+// if (useAnim) {
+// transitionBlurView.show(false)
+// }
+ if (isStartingApp && !useAnim) {
+ transitionBlurView?.hide(true)
+ }
+ else {
+ transitionBlurView?.hide(useAnim)
+ }
+ isStartingApp = false
+ }
+ }
+
+ blur.methodFinder().filterByName("fastBlurWhenEnterFolderPicker")
+ .first().replaceMethod {
+ wallpaperBlurView?.showWithDuration(
+ it.args[2] as Boolean, it.args[1] as Float, it.args[3] as Int
+ )
+ }
+
+ blur.methodFinder().filterByName("fastBlurWhenExitFolderPicker")
+ .first().replaceMethod {
+ val useAnim = it.args[2] as Boolean
+ if (shouldBlurWallpaper(it.args[0] ?: return@replaceMethod null)) {
+ return@replaceMethod null
+ }
+ if (
+ XposedHelpers.getObjectField(
+ XposedHelpers.getObjectField(
+ it.args[0],"mStateManager"
+ ),
+ "mState"
+ ) == overviewState
+ ) {
+ return@replaceMethod null
+ }
+ wallpaperBlurView?.showWithDuration(
+ useAnim, it.args[1] as Float, it.args[3] as Int
+ )
+ }
+
+ // Beginning of the uncertainty section
+ blur.methodFinder().filterByName("fastBlurWhenEnterMultiWindowMode")
+ .first().replaceMethod {
+ if (
+ XposedHelpers.getObjectField(
+ XposedHelpers.getObjectField(it.args[0] ?: return@replaceMethod null,"mStateManager"),
+ "mState"
+ ) == overviewState
+ ) {
+ transitionBlurView?.show(it.args[1] as Boolean)
+ } else {
+ // 原逻辑没有 else 分支
+ }
+ }
+
+ blur.methodFinder().filterByName("fastBlurWhenGestureResetTaskView")
+ .first().replaceMethod {
+ if (
+ XposedHelpers.getObjectField(
+ XposedHelpers.getObjectField(it.args[0] ?: return@replaceMethod null,"mStateManager"),
+ "mState"
+ ) == overviewState
+ ) {
+ transitionBlurView?.show(it.args[1] as Boolean)
+ } else {
+ // 原逻辑没有 else 分支
+ }
+ }
+
+ blur.methodFinder().filterByName("restoreBlurRatioAfterAndroidS")
+ .first().replaceMethod {
+ transitionBlurView?.restore(true)
+ }
+
+ blur.methodFinder().filterByName("fastBlurWhenOpenOrCloseFolder")
+ .first().replaceMethod {
+ val useAnim = it.args[1] as Boolean
+ if (shouldBlurWallpaper(it.args[0] ?: return@replaceMethod null)) {
+ wallpaperBlurView?.show(useAnim)
+ }
+ else {
+ wallpaperBlurView?.hide(useAnim)
+ }
+ }
+
+ // 模糊缺失暂时不写.png
+ }
+
+ private fun shouldBlurWallpaper(launcher: Any): Boolean {
+// val isInNormalEditing = XposedHelpers.callMethod(launcher, "isInNormalEditing") as Boolean
+// val isFoldShowing = XposedHelpers.callMethod(launcher, "isFolderShowing") as Boolean
+ return (XposedHelpers.callMethod(launcher, "isShouldBlur") as Boolean)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/sevtinge/hyperceiler/ui/fragment/home/HomeTitleSettings.java b/app/src/main/java/com/sevtinge/hyperceiler/ui/fragment/home/HomeTitleSettings.java
index 21dd62ca3d..5e3217e454 100644
--- a/app/src/main/java/com/sevtinge/hyperceiler/ui/fragment/home/HomeTitleSettings.java
+++ b/app/src/main/java/com/sevtinge/hyperceiler/ui/fragment/home/HomeTitleSettings.java
@@ -20,6 +20,7 @@
import static com.sevtinge.hyperceiler.utils.devicesdk.MiDeviceAppUtilsKt.isPad;
import static com.sevtinge.hyperceiler.utils.devicesdk.SystemSDKKt.isMoreAndroidVersion;
+import static com.sevtinge.hyperceiler.utils.devicesdk.SystemSDKKt.isMoreHyperOSVersion;
import android.content.Intent;
import android.os.Bundle;
@@ -33,6 +34,7 @@
import com.sevtinge.hyperceiler.ui.fragment.sub.AppPicker;
import moralnorm.preference.Preference;
+import moralnorm.preference.PreferenceCategory;
import moralnorm.preference.SwitchPreference;
public class HomeTitleSettings extends SettingsPreferenceFragment {
@@ -42,6 +44,7 @@ public class HomeTitleSettings extends SettingsPreferenceFragment {
SwitchPreference mDisableHideTheme;
Preference mIconTitleCustomization;
RecommendPreference mRecommend;
+ PreferenceCategory mAppBlur;
@Override
public int getContentResId() {
@@ -60,6 +63,8 @@ public View.OnClickListener addRestartListener() {
public void initPrefs() {
mIconTitleCustomization = findPreference("prefs_key_home_title_title_icontitlecustomization");
mDisableMonoChrome = findPreference("prefs_key_home_other_icon_mono_chrome");
+ mAppBlur = findPreference("prefs_key_home_title_app_blur_hyper");
+
mDisableMonoChrome.setVisible(isMoreAndroidVersion(33));
mDisableMonoChrome.setOnPreferenceChangeListener((preference, o) -> true);
mDisableMonetColor = findPreference("prefs_key_home_other_icon_monet_color");
@@ -67,6 +72,8 @@ public void initPrefs() {
mDisableMonetColor.setOnPreferenceChangeListener((preference, o) -> true);
mDisableHideTheme = findPreference("prefs_key_home_title_disable_hide_theme");
mDisableHideTheme.setVisible(isPad());
+ mAppBlur.setVisible(isMoreHyperOSVersion(1f));
+
mIconTitleCustomization.setOnPreferenceClickListener(preference -> {
Intent intent = new Intent(getActivity(), SubPickerActivity.class);
intent.putExtra("mode", AppPicker.INPUT_MODE);
diff --git a/app/src/main/java/com/sevtinge/hyperceiler/utils/api/HyperHelperApis.kt b/app/src/main/java/com/sevtinge/hyperceiler/utils/api/HyperHelperApis.kt
new file mode 100644
index 0000000000..fbcec383dc
--- /dev/null
+++ b/app/src/main/java/com/sevtinge/hyperceiler/utils/api/HyperHelperApis.kt
@@ -0,0 +1,11 @@
+package com.sevtinge.hyperceiler.utils.api
+
+object HyperHelperApis {
+ fun linearInterpolate(start: Float, stop: Float, amount: Float): Float {
+ return start + (stop - start) * amount
+ }
+
+ fun linearInterpolate(start: Int, stop: Int, amount: Float): Int {
+ return start + ((stop - start) * amount).toInt()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/sevtinge/hyperceiler/utils/blur/MiBlurView.kt b/app/src/main/java/com/sevtinge/hyperceiler/utils/blur/MiBlurView.kt
new file mode 100644
index 0000000000..63fc0105c3
--- /dev/null
+++ b/app/src/main/java/com/sevtinge/hyperceiler/utils/blur/MiBlurView.kt
@@ -0,0 +1,190 @@
+/*
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * This file is part of XiaomiHelper project
+ * Copyright (C) 2023 HowieHChen, howie.dev@outlook.com
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.sevtinge.hyperceiler.utils.blur
+
+import android.animation.*
+import android.content.*
+import android.graphics.*
+import android.view.*
+import android.view.animation.*
+import android.view.animation.Interpolator
+import android.widget.*
+import com.sevtinge.hyperceiler.utils.api.HyperHelperApis.linearInterpolate
+import com.sevtinge.hyperceiler.utils.blur.MiBlurUtils.*
+import com.sevtinge.hyperceiler.utils.blur.MiBlurUtilsKt.clearAllBlur
+import com.sevtinge.hyperceiler.utils.blur.MiBlurUtilsKt.setMiBackgroundBlurRadius
+import kotlin.math.*
+
+class MiBlurView(context: Context): View(context) {
+ companion object {
+ const val DEFAULT_ANIM_DURATION = 250
+ const val DEFAULT_BLUR_ENABLED = true
+ const val DEFAULT_BLUR_MAX_RADIUS = 100
+ const val DEFAULT_DIM_ENABLED = true
+ const val DEFAULT_DIM_MAX_ALPHA = 64
+ const val DEFAULT_NONLINEAR_ENABLED = false
+ }
+
+ private var mainAnimator: ValueAnimator? = null
+ private var animCurrentRatio = 0.0f
+ private var animCount = 0
+ private var allowRestoreDirectly = false
+ private var isBlurInitialized = false
+ // Personalized Configurations
+ private var blurEnabled = DEFAULT_BLUR_ENABLED
+ private var blurMaxRadius = DEFAULT_BLUR_MAX_RADIUS
+ private var dimEnabled = DEFAULT_DIM_ENABLED
+ private var dimMaxAlpha = DEFAULT_DIM_MAX_ALPHA
+ private var nonlinearEnabled = DEFAULT_NONLINEAR_ENABLED
+ private var nonlinearInterpolator: Interpolator = LinearInterpolator()
+ private var passWindowBlurEnabled = false
+
+ init {
+ this.layoutParams = FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT
+ )
+ this.setBackgroundColor(Color.TRANSPARENT)
+ this.visibility = GONE
+ }
+
+ fun setPassWindowBlur(enabled: Boolean) {
+ passWindowBlurEnabled = enabled
+ }
+
+ fun setBlur(maxRadius: Int) {
+ blurMaxRadius = maxRadius
+ if (blurMaxRadius <= 0) {
+ blurEnabled = false
+ }
+ }
+
+ fun setDim(maxAlpha: Int) {
+ dimMaxAlpha = maxAlpha
+ if (maxAlpha <= 0) {
+ dimEnabled = false
+ }
+ }
+
+ fun setNonlinear(useNonlinear: Boolean, interpolator: Interpolator) {
+ nonlinearEnabled = useNonlinear
+ nonlinearInterpolator = interpolator
+ }
+
+ fun show(useAnim: Boolean, targetRatio: Float = 1.0f) {
+ this.visibility = VISIBLE
+ applyBlur(targetRatio, useAnim)
+ }
+
+ fun hide(useAnim: Boolean, targetRatio: Float = 0.0f) {
+ this.visibility = VISIBLE
+ applyBlur(targetRatio, useAnim)
+ }
+
+ fun restore(directly: Boolean = false) {
+ this.visibility = VISIBLE
+ if (!directly) {
+ applyBlur(animCurrentRatio, false)
+ }
+ else if (allowRestoreDirectly) {
+ allowRestoreDirectly = false
+ if (blurEnabled && !isBlurInitialized) {
+ initBlur()
+ }
+ applyBlurDirectly(animCurrentRatio)
+ }
+ }
+
+ fun showWithDuration(useAnim: Boolean, targetRatio: Float, duration: Int) {
+ this.visibility = VISIBLE
+ applyBlur(targetRatio, useAnim, duration)
+ }
+
+ private fun applyBlur(ratio: Float, useAnim: Boolean, duration: Int = DEFAULT_ANIM_DURATION) {
+ val targetRatio = ratio.coerceIn(0.0f, 1.0f)
+ if (mainAnimator?.isRunning == true) {
+ mainAnimator?.cancel()
+ }
+ if (blurEnabled && !isBlurInitialized) {
+ initBlur()
+ }
+ if (!useAnim || animCurrentRatio == targetRatio) {
+ applyBlurDirectly(targetRatio)
+ }
+ else {
+ val currentRatio = animCurrentRatio
+ if (mainAnimator == null) {
+ mainAnimator = ValueAnimator()
+ }
+ mainAnimator?.let {
+ it.setFloatValues(currentRatio, targetRatio)
+ it.duration = (abs(currentRatio - targetRatio) * duration).toLong()
+ it.interpolator = LinearInterpolator()
+ it.removeAllUpdateListeners()
+ it.addUpdateListener { animator ->
+ animCount++
+ val animaValue = animator.animatedValue as Float
+ if ((animCount % 2 != 1 || animaValue == currentRatio) && animaValue != targetRatio) {
+ return@addUpdateListener
+ }
+ applyBlurDirectly(
+ if (nonlinearEnabled) { nonlinearInterpolator.getInterpolation(animaValue) }
+ else { animaValue }
+ )
+ }
+ animCount = 0
+ it.start()
+ }
+ }
+ }
+
+ private fun applyBlurDirectly(ratio: Float) {
+ val blurRadius = linearInterpolate(0, blurMaxRadius, ratio)
+ if (blurEnabled) {
+ this.setMiBackgroundBlurRadius(blurRadius)
+ }
+ if (dimEnabled) {
+ this.setBackgroundColor(
+ linearInterpolate(0, dimMaxAlpha, ratio).shl(24)
+ )
+ }
+ animCurrentRatio = ratio
+ allowRestoreDirectly = true
+ if (ratio == 0.0f || blurRadius == 0) {
+ releaseBlur()
+ }
+ }
+
+ private fun initBlur() {
+ if (isBlurInitialized) return
+ this.clearAllBlur()
+ setPassWindowBlurEnabled(this, passWindowBlurEnabled)
+ setMiBackgroundBlurMode(this, 1)
+ setMiViewBlurMode(this, 1)
+ isBlurInitialized = true
+ }
+
+ private fun releaseBlur() {
+ if (!isBlurInitialized) return
+ isBlurInitialized = false
+ this.visibility = GONE
+ this.clearAllBlur()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index 73cbcb3dd3..b00c8cedfd 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -1200,6 +1200,14 @@
图标与标题
图标
图标动画
+ 应用模糊
+ 应用动画背景模糊
+ 一次模糊遮罩模糊半径
+ 一次模糊遮罩背景不透明度
+ 二次模糊遮罩模糊半径
+ 二次模糊遮罩背景不透明度
+ 额外修复小窗动画
+ 实验性功能,强制使用动画以避免拖动应用进入小窗时闪烁,不介意勿用
标题
文字滚动
过长的应用名称将以滚动进行显示,不再使用换行
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6a23922477..a37df0c2ea 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1171,6 +1171,14 @@
Icon and Title
Icon
Icon Animation
+ App Blur
+ Enable app animated background blur
+ App animation background blur radius
+ App animation background mask transparency
+ Wallpaper blur radius
+ Wallpaper mask transparency
+ Additional fix for small window animation
+ Experimental function, force the use of animation to avoid flickering when dragging the application into a small window, don\'t use it if you don\'t mind
Title
Text scroll
App names that are too long will be scrolled instead of wrapping
diff --git a/app/src/main/res/xml/home_title.xml b/app/src/main/res/xml/home_title.xml
index cbd0e67979..9c5fce5d39 100644
--- a/app/src/main/res/xml/home_title.xml
+++ b/app/src/main/res/xml/home_title.xml
@@ -115,6 +115,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+