Loading quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +2 −2 Original line number Diff line number Diff line Loading @@ -110,7 +110,7 @@ import java.util.stream.Stream; */ public abstract class BaseQuickstepLauncher extends Launcher { private DepthController mDepthController = new DepthController(this); private DepthController mDepthController; private QuickstepTransitionManager mAppTransitionManager; /** Loading Loading @@ -247,7 +247,6 @@ public abstract class BaseQuickstepLauncher extends Launcher { @Override public void onScrollChanged(float progress) { super.onScrollChanged(progress); mDepthController.onOverlayScrollChanged(progress); onTaskbarInAppDisplayProgressUpdate(progress, MINUS_ONE_PAGE_PROGRESS_INDEX); } Loading Loading @@ -345,6 +344,7 @@ public abstract class BaseQuickstepLauncher extends Launcher { mAppTransitionManager.registerRemoteTransitions(); mTISBindHelper = new TISBindHelper(this, this::onTISConnected); mDepthController = new DepthController(this); } private void onTISConnected(TISBinder binder) { Loading quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +42 −46 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.Pair; import android.util.Size; import android.view.CrossWindowBlurListeners; import android.view.SurfaceControl; import android.view.View; import android.view.ViewRootImpl; Loading @@ -93,6 +94,7 @@ import androidx.core.graphics.ColorUtils; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.shortcuts.DeepShortcutView; Loading Loading @@ -143,8 +145,6 @@ import java.util.List; */ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener { private static final String TAG = "QuickstepTransition"; private static final boolean ENABLE_SHELL_STARTING_SURFACE = SystemProperties.getBoolean("persist.debug.shell_starting_surface", true); Loading Loading @@ -1044,14 +1044,15 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener private ObjectAnimator getBackgroundAnimator() { // When launching an app from overview that doesn't map to a task, we still want to just // blur the wallpaper instead of the launcher surface as well boolean allowBlurringLauncher = mLauncher.getStateManager().getState() != OVERVIEW; DepthController depthController = mLauncher.getDepthController(); boolean allowBlurringLauncher = mLauncher.getStateManager().getState() != OVERVIEW && BlurUtils.supportsBlursOnWindows(); MyDepthController depthController = new MyDepthController(mLauncher); ObjectAnimator backgroundRadiusAnim = ObjectAnimator.ofFloat(depthController, DEPTH, BACKGROUND_APP.getDepth(mLauncher)) .setDuration(APP_LAUNCH_DURATION); if (allowBlurringLauncher) { final SurfaceControl dimLayer; if (BlurUtils.supportsBlursOnWindows()) { // Create a temporary effect layer, that lives on top of launcher, so we can apply // the blur to it. The EffectLayer will be fullscreen, which will help with caching // optimizations on the SurfaceFlinger side: Loading @@ -1062,36 +1063,18 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener SurfaceControl parent = viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null; dimLayer = new SurfaceControl.Builder() SurfaceControl dimLayer = new SurfaceControl.Builder() .setName("Blur layer") .setParent(parent) .setOpaque(false) .setHidden(false) .setEffectLayer() .build(); } else { dimLayer = null; } depthController.setSurface(dimLayer); backgroundRadiusAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { depthController.setIsInLaunchTransition(true); backgroundRadiusAnim.addListener(AnimatorListeners.forEndCallback(() -> new SurfaceControl.Transaction().remove(dimLayer).apply())); } @Override public void onAnimationEnd(Animator animation) { depthController.setIsInLaunchTransition(false); depthController.setSurface(null); if (dimLayer != null) { new SurfaceControl.Transaction() .remove(dimLayer) .apply(); } } }); } return backgroundRadiusAnim; } Loading Loading @@ -1936,4 +1919,17 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5); } } private static class MyDepthController extends DepthController { MyDepthController(Launcher l) { super(l); setCrossWindowBlursEnabled( CrossWindowBlurListeners.getInstance().isCrossWindowBlurEnabled()); } @Override public void setSurface(SurfaceControl surface) { super.setSurface(surface); } } } quickstep/src/com/android/launcher3/statehandlers/DepthController.java +27 −208 Original line number Diff line number Diff line Loading @@ -23,13 +23,8 @@ import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTR import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.app.WallpaperManager; import android.os.IBinder; import android.os.SystemProperties; import android.util.FloatProperty; import android.view.AttachedSurfaceControl; import android.view.CrossWindowBlurListeners; import android.view.SurfaceControl; import android.view.View; import android.view.ViewRootImpl; import android.view.ViewTreeObserver; Loading @@ -37,12 +32,11 @@ import android.view.ViewTreeObserver; import com.android.launcher3.BaseActivity; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.states.StateAnimationConfig; import com.android.systemui.shared.system.BlurUtils; import com.android.quickstep.util.BaseDepthController; import java.io.PrintWriter; import java.util.function.Consumer; Loading @@ -50,23 +44,9 @@ import java.util.function.Consumer; /** * Controls blur and wallpaper zoom, for the Launcher surface only. */ public class DepthController implements StateHandler<LauncherState>, public class DepthController extends BaseDepthController implements StateHandler<LauncherState>, BaseActivity.MultiWindowModeChangedListener { private static final boolean OVERLAY_SCROLL_ENABLED = false; public static final FloatProperty<DepthController> DEPTH = new FloatProperty<DepthController>("depth") { @Override public void setValue(DepthController depthController, float depth) { depthController.setDepth(depth); } @Override public Float get(DepthController depthController) { return depthController.mDepth; } }; /** * A property that updates the background blur within a given range of values (ie. even if the * animator goes beyond 0..1, the interpolated value will still be bounded). Loading @@ -92,96 +72,46 @@ public class DepthController implements StateHandler<LauncherState>, } } private final ViewTreeObserver.OnDrawListener mOnDrawListener = new ViewTreeObserver.OnDrawListener() { @Override public void onDraw() { View view = mLauncher.getDragLayer(); ViewRootImpl viewRootImpl = view.getViewRootImpl(); boolean applied = setSurface( viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null); if (!applied) { dispatchTransactionSurface(mDepth); } view.post(() -> view.getViewTreeObserver().removeOnDrawListener(this)); } }; private final ViewTreeObserver.OnDrawListener mOnDrawListener = this::onLauncherDraw; private final Consumer<Boolean> mCrossWindowBlurListener = new Consumer<Boolean>() { @Override public void accept(Boolean enabled) { mCrossWindowBlursEnabled = enabled; dispatchTransactionSurface(mDepth); } }; private final Consumer<Boolean> mCrossWindowBlurListener = this::setCrossWindowBlursEnabled; private final Runnable mOpaquenessListener = new Runnable() { @Override public void run() { dispatchTransactionSurface(mDepth); } }; private final Runnable mOpaquenessListener = this::applyDepthAndBlur; private final Launcher mLauncher; /** * Blur radius when completely zoomed out, in pixels. */ private int mMaxBlurRadius; private boolean mCrossWindowBlursEnabled; private WallpaperManager mWallpaperManager; private SurfaceControl mSurface; /** * How visible the -1 overlay is, from 0 to 1. */ private float mOverlayScrollProgress; /** * Ratio from 0 to 1, where 0 is fully zoomed out, and 1 is zoomed in. * @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float) */ private float mDepth; /** * Last blur value, in pixels, that was applied. * For debugging purposes. */ private int mCurrentBlur; /** * If we're launching and app and should not be blurring the screen for performance reasons. */ private boolean mBlurDisabledForAppLaunch; /** * If we requested early wake-up offsets to SurfaceFlinger. */ private boolean mInEarlyWakeUp; // Workaround for animating the depth when multiwindow mode changes. private boolean mIgnoreStateChangesDuringMultiWindowAnimation = false; // Hints that there is potentially content behind Launcher and that we shouldn't optimize by // marking the launcher surface as opaque. Only used in certain Launcher states. private boolean mHasContentBehindLauncher; private View.OnAttachStateChangeListener mOnAttachListener; public DepthController(Launcher l) { mLauncher = l; super(l); } private void ensureDependencies() { if (mWallpaperManager == null) { mMaxBlurRadius = mLauncher.getResources().getInteger(R.integer.max_depth_blur_radius); mWallpaperManager = mLauncher.getSystemService(WallpaperManager.class); private void onLauncherDraw() { View view = mLauncher.getDragLayer(); ViewRootImpl viewRootImpl = view.getViewRootImpl(); setSurface(viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null); view.post(() -> view.getViewTreeObserver().removeOnDrawListener(mOnDrawListener)); } private void ensureDependencies() { if (mLauncher.getRootView() != null && mOnAttachListener == null) { View rootView = mLauncher.getRootView(); mOnAttachListener = new View.OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View view) { CrossWindowBlurListeners.getInstance().addListener(mLauncher.getMainExecutor(), mCrossWindowBlurListener); mLauncher.getScrimView().addOpaquenessListener(mOpaquenessListener); // To handle the case where window token is invalid during last setDepth call. IBinder windowToken = mLauncher.getRootView().getWindowToken(); if (windowToken != null) { mWallpaperManager.setWallpaperZoomOut(windowToken, mDepth); } onAttached(); applyDepthAndBlur(); } @Override Loading @@ -190,21 +120,11 @@ public class DepthController implements StateHandler<LauncherState>, mLauncher.getScrimView().removeOpaquenessListener(mOpaquenessListener); } }; mLauncher.getRootView().addOnAttachStateChangeListener(mOnAttachListener); if (mLauncher.getRootView().isAttachedToWindow()) { onAttached(); } rootView.addOnAttachStateChangeListener(mOnAttachListener); if (rootView.isAttachedToWindow()) { mOnAttachListener.onViewAttachedToWindow(rootView); } } private void onAttached() { CrossWindowBlurListeners.getInstance().addListener(mLauncher.getMainExecutor(), mCrossWindowBlurListener); mLauncher.getScrimView().addOpaquenessListener(mOpaquenessListener); } public void setHasContentBehindLauncher(boolean hasContentBehindLauncher) { mHasContentBehindLauncher = hasContentBehindLauncher; } /** Loading @@ -219,26 +139,6 @@ public class DepthController implements StateHandler<LauncherState>, } } /** * Sets the specified app target surface to apply the blur to. * @return true when surface was valid and transaction was dispatched. */ public boolean setSurface(SurfaceControl surface) { // Set launcher as the SurfaceControl when we don't need an external target anymore. if (surface == null) { ViewRootImpl viewRootImpl = mLauncher.getDragLayer().getViewRootImpl(); surface = viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null; } if (mSurface != surface) { mSurface = surface; if (surface != null) { dispatchTransactionSurface(mDepth); return true; } } return false; } @Override public void setState(LauncherState toState) { if (mSurface == null || mIgnoreStateChangesDuringMultiWindowAnimation) { Loading @@ -249,7 +149,7 @@ public class DepthController implements StateHandler<LauncherState>, if (Float.compare(mDepth, toDepth) != 0) { setDepth(toDepth); } else if (toState == LauncherState.OVERVIEW) { dispatchTransactionSurface(mDepth); applyDepthAndBlur(); } else if (toState == LauncherState.BACKGROUND_APP) { mLauncher.getDragLayer().getViewTreeObserver().addOnDrawListener(mOnDrawListener); } Loading @@ -269,90 +169,10 @@ public class DepthController implements StateHandler<LauncherState>, } } /** * If we're launching an app from the home screen. */ public void setIsInLaunchTransition(boolean inLaunchTransition) { boolean blurEnabled = SystemProperties.getBoolean("ro.launcher.blur.appLaunch", true); mBlurDisabledForAppLaunch = inLaunchTransition && !blurEnabled; if (!inLaunchTransition) { // Reset depth at the end of the launch animation, so the wallpaper won't be // zoomed out if an app crashes. setDepth(0f); } } private void setDepth(float depth) { depth = Utilities.boundToRange(depth, 0, 1); // Round out the depth to dedupe frequent, non-perceptable updates int depthI = (int) (depth * 256); float depthF = depthI / 256f; if (Float.compare(mDepth, depthF) == 0) { return; } dispatchTransactionSurface(depthF); mDepth = depthF; } public void onOverlayScrollChanged(float progress) { if (!OVERLAY_SCROLL_ENABLED) { return; } // Add some padding to the progress, such we don't change the depth on the last frames of // the animation. It's possible that a user flinging the feed quickly would scroll // horizontally by accident, causing the device to enter client composition unnecessarily. progress = Math.min(progress * 1.1f, 1f); // Round out the progress to dedupe frequent, non-perceptable updates int progressI = (int) (progress * 256); float progressF = Utilities.boundToRange(progressI / 256f, 0f, 1f); if (Float.compare(mOverlayScrollProgress, progressF) == 0) { return; } mOverlayScrollProgress = progressF; dispatchTransactionSurface(mDepth); } private boolean dispatchTransactionSurface(float depth) { boolean supportsBlur = BlurUtils.supportsBlursOnWindows(); if (supportsBlur && (mSurface == null || !mSurface.isValid())) { return false; } @Override protected void applyDepthAndBlur() { ensureDependencies(); depth = Math.max(depth, mOverlayScrollProgress); IBinder windowToken = mLauncher.getRootView().getWindowToken(); if (windowToken != null) { mWallpaperManager.setWallpaperZoomOut(windowToken, depth); } if (supportsBlur) { boolean hasOpaqueBg = mLauncher.getScrimView().isFullyOpaque(); boolean isSurfaceOpaque = !mHasContentBehindLauncher && hasOpaqueBg; mCurrentBlur = !mCrossWindowBlursEnabled || mBlurDisabledForAppLaunch || hasOpaqueBg ? 0 : (int) (depth * mMaxBlurRadius); SurfaceControl.Transaction transaction = new SurfaceControl.Transaction() .setBackgroundBlurRadius(mSurface, mCurrentBlur) .setOpaque(mSurface, isSurfaceOpaque); // Set early wake-up flags when we know we're executing an expensive operation, this way // SurfaceFlinger will adjust its internal offsets to avoid jank. boolean wantsEarlyWakeUp = depth > 0 && depth < 1; if (wantsEarlyWakeUp && !mInEarlyWakeUp) { transaction.setEarlyWakeupStart(); mInEarlyWakeUp = true; } else if (!wantsEarlyWakeUp && mInEarlyWakeUp) { transaction.setEarlyWakeupEnd(); mInEarlyWakeUp = false; } AttachedSurfaceControl rootSurfaceControl = mLauncher.getRootView().getRootSurfaceControl(); if (rootSurfaceControl != null) { rootSurfaceControl.applyTransactionOnDraw(transaction); } } return true; super.applyDepthAndBlur(); } @Override Loading @@ -377,7 +197,6 @@ public class DepthController implements StateHandler<LauncherState>, writer.println(prefix + "\tmMaxBlurRadius=" + mMaxBlurRadius); writer.println(prefix + "\tmCrossWindowBlursEnabled=" + mCrossWindowBlursEnabled); writer.println(prefix + "\tmSurface=" + mSurface); writer.println(prefix + "\tmOverlayScrollProgress=" + mOverlayScrollProgress); writer.println(prefix + "\tmDepth=" + mDepth); writer.println(prefix + "\tmCurrentBlur=" + mCurrentBlur); writer.println(prefix + "\tmBlurDisabledForAppLaunch=" + mBlurDisabledForAppLaunch); Loading quickstep/src/com/android/quickstep/util/BaseDepthController.java 0 → 100644 +153 −0 Original line number Diff line number Diff line /* * 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.quickstep.util; import android.app.WallpaperManager; import android.os.IBinder; import android.util.FloatProperty; import android.view.AttachedSurfaceControl; import android.view.SurfaceControl; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.systemui.shared.system.BlurUtils; /** * Utility class for applying depth effect */ public class BaseDepthController { public static final FloatProperty<BaseDepthController> DEPTH = new FloatProperty<BaseDepthController>("depth") { @Override public void setValue(BaseDepthController depthController, float depth) { depthController.setDepth(depth); } @Override public Float get(BaseDepthController depthController) { return depthController.mDepth; } }; protected final Launcher mLauncher; /** * Blur radius when completely zoomed out, in pixels. */ protected final int mMaxBlurRadius; protected final WallpaperManager mWallpaperManager; protected boolean mCrossWindowBlursEnabled; /** * Ratio from 0 to 1, where 0 is fully zoomed out, and 1 is zoomed in. * @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float) */ protected float mDepth; protected SurfaceControl mSurface; // Hints that there is potentially content behind Launcher and that we shouldn't optimize by // marking the launcher surface as opaque. Only used in certain Launcher states. private boolean mHasContentBehindLauncher; /** * Last blur value, in pixels, that was applied. * For debugging purposes. */ protected int mCurrentBlur; /** * If we requested early wake-up offsets to SurfaceFlinger. */ protected boolean mInEarlyWakeUp; public BaseDepthController(Launcher activity) { mLauncher = activity; mMaxBlurRadius = activity.getResources().getInteger(R.integer.max_depth_blur_radius); mWallpaperManager = activity.getSystemService(WallpaperManager.class); } protected void setCrossWindowBlursEnabled(boolean isEnabled) { mCrossWindowBlursEnabled = isEnabled; applyDepthAndBlur(); } public void setHasContentBehindLauncher(boolean hasContentBehindLauncher) { mHasContentBehindLauncher = hasContentBehindLauncher; } protected void applyDepthAndBlur() { float depth = mDepth; IBinder windowToken = mLauncher.getRootView().getWindowToken(); if (windowToken != null) { mWallpaperManager.setWallpaperZoomOut(windowToken, depth); } if (!BlurUtils.supportsBlursOnWindows()) { return; } if (mSurface == null || !mSurface.isValid()) { return; } boolean hasOpaqueBg = mLauncher.getScrimView().isFullyOpaque(); boolean isSurfaceOpaque = !mHasContentBehindLauncher && hasOpaqueBg; mCurrentBlur = !mCrossWindowBlursEnabled || hasOpaqueBg ? 0 : (int) (depth * mMaxBlurRadius); SurfaceControl.Transaction transaction = new SurfaceControl.Transaction() .setBackgroundBlurRadius(mSurface, mCurrentBlur) .setOpaque(mSurface, isSurfaceOpaque); // Set early wake-up flags when we know we're executing an expensive operation, this way // SurfaceFlinger will adjust its internal offsets to avoid jank. boolean wantsEarlyWakeUp = depth > 0 && depth < 1; if (wantsEarlyWakeUp && !mInEarlyWakeUp) { transaction.setEarlyWakeupStart(); mInEarlyWakeUp = true; } else if (!wantsEarlyWakeUp && mInEarlyWakeUp) { transaction.setEarlyWakeupEnd(); mInEarlyWakeUp = false; } AttachedSurfaceControl rootSurfaceControl = mLauncher.getRootView().getRootSurfaceControl(); if (rootSurfaceControl != null) { rootSurfaceControl.applyTransactionOnDraw(transaction); } } protected void setDepth(float depth) { depth = Utilities.boundToRange(depth, 0, 1); // Round out the depth to dedupe frequent, non-perceptable updates int depthI = (int) (depth * 256); float depthF = depthI / 256f; if (Float.compare(mDepth, depthF) == 0) { return; } mDepth = depthF; applyDepthAndBlur(); } /** * Sets the specified app target surface to apply the blur to. */ protected void setSurface(SurfaceControl surface) { if (mSurface != surface) { mSurface = surface; applyDepthAndBlur(); } } } Loading
quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +2 −2 Original line number Diff line number Diff line Loading @@ -110,7 +110,7 @@ import java.util.stream.Stream; */ public abstract class BaseQuickstepLauncher extends Launcher { private DepthController mDepthController = new DepthController(this); private DepthController mDepthController; private QuickstepTransitionManager mAppTransitionManager; /** Loading Loading @@ -247,7 +247,6 @@ public abstract class BaseQuickstepLauncher extends Launcher { @Override public void onScrollChanged(float progress) { super.onScrollChanged(progress); mDepthController.onOverlayScrollChanged(progress); onTaskbarInAppDisplayProgressUpdate(progress, MINUS_ONE_PAGE_PROGRESS_INDEX); } Loading Loading @@ -345,6 +344,7 @@ public abstract class BaseQuickstepLauncher extends Launcher { mAppTransitionManager.registerRemoteTransitions(); mTISBindHelper = new TISBindHelper(this, this::onTISConnected); mDepthController = new DepthController(this); } private void onTISConnected(TISBinder binder) { Loading
quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +42 −46 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.Pair; import android.util.Size; import android.view.CrossWindowBlurListeners; import android.view.SurfaceControl; import android.view.View; import android.view.ViewRootImpl; Loading @@ -93,6 +94,7 @@ import androidx.core.graphics.ColorUtils; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.shortcuts.DeepShortcutView; Loading Loading @@ -143,8 +145,6 @@ import java.util.List; */ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener { private static final String TAG = "QuickstepTransition"; private static final boolean ENABLE_SHELL_STARTING_SURFACE = SystemProperties.getBoolean("persist.debug.shell_starting_surface", true); Loading Loading @@ -1044,14 +1044,15 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener private ObjectAnimator getBackgroundAnimator() { // When launching an app from overview that doesn't map to a task, we still want to just // blur the wallpaper instead of the launcher surface as well boolean allowBlurringLauncher = mLauncher.getStateManager().getState() != OVERVIEW; DepthController depthController = mLauncher.getDepthController(); boolean allowBlurringLauncher = mLauncher.getStateManager().getState() != OVERVIEW && BlurUtils.supportsBlursOnWindows(); MyDepthController depthController = new MyDepthController(mLauncher); ObjectAnimator backgroundRadiusAnim = ObjectAnimator.ofFloat(depthController, DEPTH, BACKGROUND_APP.getDepth(mLauncher)) .setDuration(APP_LAUNCH_DURATION); if (allowBlurringLauncher) { final SurfaceControl dimLayer; if (BlurUtils.supportsBlursOnWindows()) { // Create a temporary effect layer, that lives on top of launcher, so we can apply // the blur to it. The EffectLayer will be fullscreen, which will help with caching // optimizations on the SurfaceFlinger side: Loading @@ -1062,36 +1063,18 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener SurfaceControl parent = viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null; dimLayer = new SurfaceControl.Builder() SurfaceControl dimLayer = new SurfaceControl.Builder() .setName("Blur layer") .setParent(parent) .setOpaque(false) .setHidden(false) .setEffectLayer() .build(); } else { dimLayer = null; } depthController.setSurface(dimLayer); backgroundRadiusAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { depthController.setIsInLaunchTransition(true); backgroundRadiusAnim.addListener(AnimatorListeners.forEndCallback(() -> new SurfaceControl.Transaction().remove(dimLayer).apply())); } @Override public void onAnimationEnd(Animator animation) { depthController.setIsInLaunchTransition(false); depthController.setSurface(null); if (dimLayer != null) { new SurfaceControl.Transaction() .remove(dimLayer) .apply(); } } }); } return backgroundRadiusAnim; } Loading Loading @@ -1936,4 +1919,17 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5); } } private static class MyDepthController extends DepthController { MyDepthController(Launcher l) { super(l); setCrossWindowBlursEnabled( CrossWindowBlurListeners.getInstance().isCrossWindowBlurEnabled()); } @Override public void setSurface(SurfaceControl surface) { super.setSurface(surface); } } }
quickstep/src/com/android/launcher3/statehandlers/DepthController.java +27 −208 Original line number Diff line number Diff line Loading @@ -23,13 +23,8 @@ import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTR import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.app.WallpaperManager; import android.os.IBinder; import android.os.SystemProperties; import android.util.FloatProperty; import android.view.AttachedSurfaceControl; import android.view.CrossWindowBlurListeners; import android.view.SurfaceControl; import android.view.View; import android.view.ViewRootImpl; import android.view.ViewTreeObserver; Loading @@ -37,12 +32,11 @@ import android.view.ViewTreeObserver; import com.android.launcher3.BaseActivity; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.states.StateAnimationConfig; import com.android.systemui.shared.system.BlurUtils; import com.android.quickstep.util.BaseDepthController; import java.io.PrintWriter; import java.util.function.Consumer; Loading @@ -50,23 +44,9 @@ import java.util.function.Consumer; /** * Controls blur and wallpaper zoom, for the Launcher surface only. */ public class DepthController implements StateHandler<LauncherState>, public class DepthController extends BaseDepthController implements StateHandler<LauncherState>, BaseActivity.MultiWindowModeChangedListener { private static final boolean OVERLAY_SCROLL_ENABLED = false; public static final FloatProperty<DepthController> DEPTH = new FloatProperty<DepthController>("depth") { @Override public void setValue(DepthController depthController, float depth) { depthController.setDepth(depth); } @Override public Float get(DepthController depthController) { return depthController.mDepth; } }; /** * A property that updates the background blur within a given range of values (ie. even if the * animator goes beyond 0..1, the interpolated value will still be bounded). Loading @@ -92,96 +72,46 @@ public class DepthController implements StateHandler<LauncherState>, } } private final ViewTreeObserver.OnDrawListener mOnDrawListener = new ViewTreeObserver.OnDrawListener() { @Override public void onDraw() { View view = mLauncher.getDragLayer(); ViewRootImpl viewRootImpl = view.getViewRootImpl(); boolean applied = setSurface( viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null); if (!applied) { dispatchTransactionSurface(mDepth); } view.post(() -> view.getViewTreeObserver().removeOnDrawListener(this)); } }; private final ViewTreeObserver.OnDrawListener mOnDrawListener = this::onLauncherDraw; private final Consumer<Boolean> mCrossWindowBlurListener = new Consumer<Boolean>() { @Override public void accept(Boolean enabled) { mCrossWindowBlursEnabled = enabled; dispatchTransactionSurface(mDepth); } }; private final Consumer<Boolean> mCrossWindowBlurListener = this::setCrossWindowBlursEnabled; private final Runnable mOpaquenessListener = new Runnable() { @Override public void run() { dispatchTransactionSurface(mDepth); } }; private final Runnable mOpaquenessListener = this::applyDepthAndBlur; private final Launcher mLauncher; /** * Blur radius when completely zoomed out, in pixels. */ private int mMaxBlurRadius; private boolean mCrossWindowBlursEnabled; private WallpaperManager mWallpaperManager; private SurfaceControl mSurface; /** * How visible the -1 overlay is, from 0 to 1. */ private float mOverlayScrollProgress; /** * Ratio from 0 to 1, where 0 is fully zoomed out, and 1 is zoomed in. * @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float) */ private float mDepth; /** * Last blur value, in pixels, that was applied. * For debugging purposes. */ private int mCurrentBlur; /** * If we're launching and app and should not be blurring the screen for performance reasons. */ private boolean mBlurDisabledForAppLaunch; /** * If we requested early wake-up offsets to SurfaceFlinger. */ private boolean mInEarlyWakeUp; // Workaround for animating the depth when multiwindow mode changes. private boolean mIgnoreStateChangesDuringMultiWindowAnimation = false; // Hints that there is potentially content behind Launcher and that we shouldn't optimize by // marking the launcher surface as opaque. Only used in certain Launcher states. private boolean mHasContentBehindLauncher; private View.OnAttachStateChangeListener mOnAttachListener; public DepthController(Launcher l) { mLauncher = l; super(l); } private void ensureDependencies() { if (mWallpaperManager == null) { mMaxBlurRadius = mLauncher.getResources().getInteger(R.integer.max_depth_blur_radius); mWallpaperManager = mLauncher.getSystemService(WallpaperManager.class); private void onLauncherDraw() { View view = mLauncher.getDragLayer(); ViewRootImpl viewRootImpl = view.getViewRootImpl(); setSurface(viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null); view.post(() -> view.getViewTreeObserver().removeOnDrawListener(mOnDrawListener)); } private void ensureDependencies() { if (mLauncher.getRootView() != null && mOnAttachListener == null) { View rootView = mLauncher.getRootView(); mOnAttachListener = new View.OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View view) { CrossWindowBlurListeners.getInstance().addListener(mLauncher.getMainExecutor(), mCrossWindowBlurListener); mLauncher.getScrimView().addOpaquenessListener(mOpaquenessListener); // To handle the case where window token is invalid during last setDepth call. IBinder windowToken = mLauncher.getRootView().getWindowToken(); if (windowToken != null) { mWallpaperManager.setWallpaperZoomOut(windowToken, mDepth); } onAttached(); applyDepthAndBlur(); } @Override Loading @@ -190,21 +120,11 @@ public class DepthController implements StateHandler<LauncherState>, mLauncher.getScrimView().removeOpaquenessListener(mOpaquenessListener); } }; mLauncher.getRootView().addOnAttachStateChangeListener(mOnAttachListener); if (mLauncher.getRootView().isAttachedToWindow()) { onAttached(); } rootView.addOnAttachStateChangeListener(mOnAttachListener); if (rootView.isAttachedToWindow()) { mOnAttachListener.onViewAttachedToWindow(rootView); } } private void onAttached() { CrossWindowBlurListeners.getInstance().addListener(mLauncher.getMainExecutor(), mCrossWindowBlurListener); mLauncher.getScrimView().addOpaquenessListener(mOpaquenessListener); } public void setHasContentBehindLauncher(boolean hasContentBehindLauncher) { mHasContentBehindLauncher = hasContentBehindLauncher; } /** Loading @@ -219,26 +139,6 @@ public class DepthController implements StateHandler<LauncherState>, } } /** * Sets the specified app target surface to apply the blur to. * @return true when surface was valid and transaction was dispatched. */ public boolean setSurface(SurfaceControl surface) { // Set launcher as the SurfaceControl when we don't need an external target anymore. if (surface == null) { ViewRootImpl viewRootImpl = mLauncher.getDragLayer().getViewRootImpl(); surface = viewRootImpl != null ? viewRootImpl.getSurfaceControl() : null; } if (mSurface != surface) { mSurface = surface; if (surface != null) { dispatchTransactionSurface(mDepth); return true; } } return false; } @Override public void setState(LauncherState toState) { if (mSurface == null || mIgnoreStateChangesDuringMultiWindowAnimation) { Loading @@ -249,7 +149,7 @@ public class DepthController implements StateHandler<LauncherState>, if (Float.compare(mDepth, toDepth) != 0) { setDepth(toDepth); } else if (toState == LauncherState.OVERVIEW) { dispatchTransactionSurface(mDepth); applyDepthAndBlur(); } else if (toState == LauncherState.BACKGROUND_APP) { mLauncher.getDragLayer().getViewTreeObserver().addOnDrawListener(mOnDrawListener); } Loading @@ -269,90 +169,10 @@ public class DepthController implements StateHandler<LauncherState>, } } /** * If we're launching an app from the home screen. */ public void setIsInLaunchTransition(boolean inLaunchTransition) { boolean blurEnabled = SystemProperties.getBoolean("ro.launcher.blur.appLaunch", true); mBlurDisabledForAppLaunch = inLaunchTransition && !blurEnabled; if (!inLaunchTransition) { // Reset depth at the end of the launch animation, so the wallpaper won't be // zoomed out if an app crashes. setDepth(0f); } } private void setDepth(float depth) { depth = Utilities.boundToRange(depth, 0, 1); // Round out the depth to dedupe frequent, non-perceptable updates int depthI = (int) (depth * 256); float depthF = depthI / 256f; if (Float.compare(mDepth, depthF) == 0) { return; } dispatchTransactionSurface(depthF); mDepth = depthF; } public void onOverlayScrollChanged(float progress) { if (!OVERLAY_SCROLL_ENABLED) { return; } // Add some padding to the progress, such we don't change the depth on the last frames of // the animation. It's possible that a user flinging the feed quickly would scroll // horizontally by accident, causing the device to enter client composition unnecessarily. progress = Math.min(progress * 1.1f, 1f); // Round out the progress to dedupe frequent, non-perceptable updates int progressI = (int) (progress * 256); float progressF = Utilities.boundToRange(progressI / 256f, 0f, 1f); if (Float.compare(mOverlayScrollProgress, progressF) == 0) { return; } mOverlayScrollProgress = progressF; dispatchTransactionSurface(mDepth); } private boolean dispatchTransactionSurface(float depth) { boolean supportsBlur = BlurUtils.supportsBlursOnWindows(); if (supportsBlur && (mSurface == null || !mSurface.isValid())) { return false; } @Override protected void applyDepthAndBlur() { ensureDependencies(); depth = Math.max(depth, mOverlayScrollProgress); IBinder windowToken = mLauncher.getRootView().getWindowToken(); if (windowToken != null) { mWallpaperManager.setWallpaperZoomOut(windowToken, depth); } if (supportsBlur) { boolean hasOpaqueBg = mLauncher.getScrimView().isFullyOpaque(); boolean isSurfaceOpaque = !mHasContentBehindLauncher && hasOpaqueBg; mCurrentBlur = !mCrossWindowBlursEnabled || mBlurDisabledForAppLaunch || hasOpaqueBg ? 0 : (int) (depth * mMaxBlurRadius); SurfaceControl.Transaction transaction = new SurfaceControl.Transaction() .setBackgroundBlurRadius(mSurface, mCurrentBlur) .setOpaque(mSurface, isSurfaceOpaque); // Set early wake-up flags when we know we're executing an expensive operation, this way // SurfaceFlinger will adjust its internal offsets to avoid jank. boolean wantsEarlyWakeUp = depth > 0 && depth < 1; if (wantsEarlyWakeUp && !mInEarlyWakeUp) { transaction.setEarlyWakeupStart(); mInEarlyWakeUp = true; } else if (!wantsEarlyWakeUp && mInEarlyWakeUp) { transaction.setEarlyWakeupEnd(); mInEarlyWakeUp = false; } AttachedSurfaceControl rootSurfaceControl = mLauncher.getRootView().getRootSurfaceControl(); if (rootSurfaceControl != null) { rootSurfaceControl.applyTransactionOnDraw(transaction); } } return true; super.applyDepthAndBlur(); } @Override Loading @@ -377,7 +197,6 @@ public class DepthController implements StateHandler<LauncherState>, writer.println(prefix + "\tmMaxBlurRadius=" + mMaxBlurRadius); writer.println(prefix + "\tmCrossWindowBlursEnabled=" + mCrossWindowBlursEnabled); writer.println(prefix + "\tmSurface=" + mSurface); writer.println(prefix + "\tmOverlayScrollProgress=" + mOverlayScrollProgress); writer.println(prefix + "\tmDepth=" + mDepth); writer.println(prefix + "\tmCurrentBlur=" + mCurrentBlur); writer.println(prefix + "\tmBlurDisabledForAppLaunch=" + mBlurDisabledForAppLaunch); Loading
quickstep/src/com/android/quickstep/util/BaseDepthController.java 0 → 100644 +153 −0 Original line number Diff line number Diff line /* * 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.quickstep.util; import android.app.WallpaperManager; import android.os.IBinder; import android.util.FloatProperty; import android.view.AttachedSurfaceControl; import android.view.SurfaceControl; import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.systemui.shared.system.BlurUtils; /** * Utility class for applying depth effect */ public class BaseDepthController { public static final FloatProperty<BaseDepthController> DEPTH = new FloatProperty<BaseDepthController>("depth") { @Override public void setValue(BaseDepthController depthController, float depth) { depthController.setDepth(depth); } @Override public Float get(BaseDepthController depthController) { return depthController.mDepth; } }; protected final Launcher mLauncher; /** * Blur radius when completely zoomed out, in pixels. */ protected final int mMaxBlurRadius; protected final WallpaperManager mWallpaperManager; protected boolean mCrossWindowBlursEnabled; /** * Ratio from 0 to 1, where 0 is fully zoomed out, and 1 is zoomed in. * @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float) */ protected float mDepth; protected SurfaceControl mSurface; // Hints that there is potentially content behind Launcher and that we shouldn't optimize by // marking the launcher surface as opaque. Only used in certain Launcher states. private boolean mHasContentBehindLauncher; /** * Last blur value, in pixels, that was applied. * For debugging purposes. */ protected int mCurrentBlur; /** * If we requested early wake-up offsets to SurfaceFlinger. */ protected boolean mInEarlyWakeUp; public BaseDepthController(Launcher activity) { mLauncher = activity; mMaxBlurRadius = activity.getResources().getInteger(R.integer.max_depth_blur_radius); mWallpaperManager = activity.getSystemService(WallpaperManager.class); } protected void setCrossWindowBlursEnabled(boolean isEnabled) { mCrossWindowBlursEnabled = isEnabled; applyDepthAndBlur(); } public void setHasContentBehindLauncher(boolean hasContentBehindLauncher) { mHasContentBehindLauncher = hasContentBehindLauncher; } protected void applyDepthAndBlur() { float depth = mDepth; IBinder windowToken = mLauncher.getRootView().getWindowToken(); if (windowToken != null) { mWallpaperManager.setWallpaperZoomOut(windowToken, depth); } if (!BlurUtils.supportsBlursOnWindows()) { return; } if (mSurface == null || !mSurface.isValid()) { return; } boolean hasOpaqueBg = mLauncher.getScrimView().isFullyOpaque(); boolean isSurfaceOpaque = !mHasContentBehindLauncher && hasOpaqueBg; mCurrentBlur = !mCrossWindowBlursEnabled || hasOpaqueBg ? 0 : (int) (depth * mMaxBlurRadius); SurfaceControl.Transaction transaction = new SurfaceControl.Transaction() .setBackgroundBlurRadius(mSurface, mCurrentBlur) .setOpaque(mSurface, isSurfaceOpaque); // Set early wake-up flags when we know we're executing an expensive operation, this way // SurfaceFlinger will adjust its internal offsets to avoid jank. boolean wantsEarlyWakeUp = depth > 0 && depth < 1; if (wantsEarlyWakeUp && !mInEarlyWakeUp) { transaction.setEarlyWakeupStart(); mInEarlyWakeUp = true; } else if (!wantsEarlyWakeUp && mInEarlyWakeUp) { transaction.setEarlyWakeupEnd(); mInEarlyWakeUp = false; } AttachedSurfaceControl rootSurfaceControl = mLauncher.getRootView().getRootSurfaceControl(); if (rootSurfaceControl != null) { rootSurfaceControl.applyTransactionOnDraw(transaction); } } protected void setDepth(float depth) { depth = Utilities.boundToRange(depth, 0, 1); // Round out the depth to dedupe frequent, non-perceptable updates int depthI = (int) (depth * 256); float depthF = depthI / 256f; if (Float.compare(mDepth, depthF) == 0) { return; } mDepth = depthF; applyDepthAndBlur(); } /** * Sets the specified app target surface to apply the blur to. */ protected void setSurface(SurfaceControl surface) { if (mSurface != surface) { mSurface = surface; applyDepthAndBlur(); } } }