From ced159075c31541bec101548f28168e692e86e8d Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 8 Jul 2022 13:14:50 -0700 Subject: [PATCH] Fixing surface blur when using multiple surfaces Separating the depth controller logic into a base class so that different controllers can be used for different surfaces Bug: 236780815 Test: Verified locally Change-Id: I2bd7ed50438453d6e41c73c8001a0d6a73091653 --- .../launcher3/BaseQuickstepLauncher.java | 4 +- .../launcher3/QuickstepTransitionManager.java | 86 +++---- .../statehandlers/DepthController.java | 235 ++---------------- .../quickstep/util/BaseDepthController.java | 153 ++++++++++++ 4 files changed, 223 insertions(+), 255 deletions(-) create mode 100644 quickstep/src/com/android/quickstep/util/BaseDepthController.java diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index ec497ef1f9..3755f705bd 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -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; /** @@ -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); } @@ -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) { diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index bb79c1ba10..6776c322bd 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -80,6 +80,7 @@ import android.provider.Settings; import android.util.Log; import android.util.Pair; import android.util.Size; +import android.view.CrossWindowBlurListeners; import android.view.SurfaceControl; import android.view.View; import android.view.ViewRootImpl; @@ -95,6 +96,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; @@ -145,8 +147,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); @@ -1066,54 +1066,37 @@ 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)) + 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: - // - Results would be able to be cached as a texture - // - There won't be texture allocation overhead, because EffectLayers don't have - // buffers - ViewRootImpl viewRootImpl = mLauncher.getDragLayer().getViewRootImpl(); - SurfaceControl parent = viewRootImpl != null - ? viewRootImpl.getSurfaceControl() - : null; - dimLayer = new SurfaceControl.Builder() - .setName("Blur layer") - .setParent(parent) - .setOpaque(false) - .setHidden(false) - .setEffectLayer() - .build(); - } else { - dimLayer = null; - } + // 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: + // - Results would be able to be cached as a texture + // - There won't be texture allocation overhead, because EffectLayers don't have + // buffers + ViewRootImpl viewRootImpl = mLauncher.getDragLayer().getViewRootImpl(); + SurfaceControl parent = viewRootImpl != null + ? viewRootImpl.getSurfaceControl() + : null; + SurfaceControl dimLayer = new SurfaceControl.Builder() + .setName("Blur layer") + .setParent(parent) + .setOpaque(false) + .setHidden(false) + .setEffectLayer() + .build(); - depthController.setSurface(dimLayer); - backgroundRadiusAnim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - depthController.setIsInLaunchTransition(true); - } - - @Override - public void onAnimationEnd(Animator animation) { - depthController.setIsInLaunchTransition(false); - depthController.setSurface(null); - if (dimLayer != null) { - new SurfaceControl.Transaction() - .remove(dimLayer) - .apply(); - } - } - }); + backgroundRadiusAnim.addListener(AnimatorListeners.forEndCallback(() -> + new SurfaceControl.Transaction().remove(dimLayer).apply())); } + return backgroundRadiusAnim; } @@ -1958,4 +1941,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); + } + } } diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java index eda08239d6..1311b1d629 100644 --- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java +++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java @@ -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; @@ -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; @@ -50,23 +44,9 @@ import java.util.function.Consumer; /** * Controls blur and wallpaper zoom, for the Launcher surface only. */ -public class DepthController implements StateHandler, +public class DepthController extends BaseDepthController implements StateHandler, BaseActivity.MultiWindowModeChangedListener { - private static final boolean OVERLAY_SCROLL_ENABLED = false; - public static final FloatProperty DEPTH = - new FloatProperty("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). @@ -92,96 +72,46 @@ public class DepthController implements StateHandler, } } - 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 mCrossWindowBlurListener = new Consumer() { - @Override - public void accept(Boolean enabled) { - mCrossWindowBlursEnabled = enabled; - dispatchTransactionSurface(mDepth); - } - }; + private final Consumer 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 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 (mWallpaperManager == null) { - mMaxBlurRadius = mLauncher.getResources().getInteger(R.integer.max_depth_blur_radius); - mWallpaperManager = mLauncher.getSystemService(WallpaperManager.class); - } - 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 @@ -190,23 +120,13 @@ public class DepthController implements StateHandler, 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; - } - /** * Sets if the underlying activity is started or not */ @@ -219,26 +139,6 @@ public class DepthController implements StateHandler, } } - /** - * 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) { @@ -249,7 +149,7 @@ public class DepthController implements StateHandler, 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); } @@ -269,90 +169,10 @@ public class DepthController implements StateHandler, } } - /** - * 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 @@ -377,7 +197,6 @@ public class DepthController implements StateHandler, 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); diff --git a/quickstep/src/com/android/quickstep/util/BaseDepthController.java b/quickstep/src/com/android/quickstep/util/BaseDepthController.java new file mode 100644 index 0000000000..40306307a2 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/BaseDepthController.java @@ -0,0 +1,153 @@ +/* + * 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 DEPTH = + new FloatProperty("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(); + } + } +}