Merge "Fixing surface blur when using multiple surfaces" into tm-qpr-dev am: 0c0fb6bc08

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Launcher3/+/19222535

Change-Id: Icbae40f77402af53ae1190f3d6a21bf554483fa7
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Sunny Goyal
2022-08-06 01:49:15 +00:00
committed by Automerger Merge Worker
4 changed files with 223 additions and 255 deletions
@@ -110,7 +110,7 @@ import java.util.stream.Stream;
*/ */
public abstract class BaseQuickstepLauncher extends Launcher { public abstract class BaseQuickstepLauncher extends Launcher {
private DepthController mDepthController = new DepthController(this); private DepthController mDepthController;
private QuickstepTransitionManager mAppTransitionManager; private QuickstepTransitionManager mAppTransitionManager;
/** /**
@@ -247,7 +247,6 @@ public abstract class BaseQuickstepLauncher extends Launcher {
@Override @Override
public void onScrollChanged(float progress) { public void onScrollChanged(float progress) {
super.onScrollChanged(progress); super.onScrollChanged(progress);
mDepthController.onOverlayScrollChanged(progress);
onTaskbarInAppDisplayProgressUpdate(progress, MINUS_ONE_PAGE_PROGRESS_INDEX); onTaskbarInAppDisplayProgressUpdate(progress, MINUS_ONE_PAGE_PROGRESS_INDEX);
} }
@@ -345,6 +344,7 @@ public abstract class BaseQuickstepLauncher extends Launcher {
mAppTransitionManager.registerRemoteTransitions(); mAppTransitionManager.registerRemoteTransitions();
mTISBindHelper = new TISBindHelper(this, this::onTISConnected); mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
mDepthController = new DepthController(this);
} }
private void onTISConnected(TISBinder binder) { private void onTISConnected(TISBinder binder) {
@@ -78,6 +78,7 @@ import android.os.UserHandle;
import android.provider.Settings; import android.provider.Settings;
import android.util.Pair; import android.util.Pair;
import android.util.Size; import android.util.Size;
import android.view.CrossWindowBlurListeners;
import android.view.SurfaceControl; import android.view.SurfaceControl;
import android.view.View; import android.view.View;
import android.view.ViewRootImpl; import android.view.ViewRootImpl;
@@ -93,6 +94,7 @@ import androidx.core.graphics.ColorUtils;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory; import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.icons.FastBitmapDrawable; import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.shortcuts.DeepShortcutView;
@@ -143,8 +145,6 @@ import java.util.List;
*/ */
public class QuickstepTransitionManager implements OnDeviceProfileChangeListener { public class QuickstepTransitionManager implements OnDeviceProfileChangeListener {
private static final String TAG = "QuickstepTransition";
private static final boolean ENABLE_SHELL_STARTING_SURFACE = private static final boolean ENABLE_SHELL_STARTING_SURFACE =
SystemProperties.getBoolean("persist.debug.shell_starting_surface", true); SystemProperties.getBoolean("persist.debug.shell_starting_surface", true);
@@ -1044,54 +1044,37 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
private ObjectAnimator getBackgroundAnimator() { private ObjectAnimator getBackgroundAnimator() {
// When launching an app from overview that doesn't map to a task, we still want to just // 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 // blur the wallpaper instead of the launcher surface as well
boolean allowBlurringLauncher = mLauncher.getStateManager().getState() != OVERVIEW; boolean allowBlurringLauncher = mLauncher.getStateManager().getState() != OVERVIEW
DepthController depthController = mLauncher.getDepthController(); && BlurUtils.supportsBlursOnWindows();
MyDepthController depthController = new MyDepthController(mLauncher);
ObjectAnimator backgroundRadiusAnim = ObjectAnimator.ofFloat(depthController, DEPTH, ObjectAnimator backgroundRadiusAnim = ObjectAnimator.ofFloat(depthController, DEPTH,
BACKGROUND_APP.getDepth(mLauncher)) BACKGROUND_APP.getDepth(mLauncher))
.setDuration(APP_LAUNCH_DURATION); .setDuration(APP_LAUNCH_DURATION);
if (allowBlurringLauncher) { if (allowBlurringLauncher) {
final SurfaceControl dimLayer; // Create a temporary effect layer, that lives on top of launcher, so we can apply
if (BlurUtils.supportsBlursOnWindows()) { // the blur to it. The EffectLayer will be fullscreen, which will help with caching
// Create a temporary effect layer, that lives on top of launcher, so we can apply // optimizations on the SurfaceFlinger side:
// the blur to it. The EffectLayer will be fullscreen, which will help with caching // - Results would be able to be cached as a texture
// optimizations on the SurfaceFlinger side: // - There won't be texture allocation overhead, because EffectLayers don't have
// - Results would be able to be cached as a texture // buffers
// - There won't be texture allocation overhead, because EffectLayers don't have ViewRootImpl viewRootImpl = mLauncher.getDragLayer().getViewRootImpl();
// buffers SurfaceControl parent = viewRootImpl != null
ViewRootImpl viewRootImpl = mLauncher.getDragLayer().getViewRootImpl(); ? viewRootImpl.getSurfaceControl()
SurfaceControl parent = viewRootImpl != null : null;
? viewRootImpl.getSurfaceControl() SurfaceControl dimLayer = new SurfaceControl.Builder()
: null; .setName("Blur layer")
dimLayer = new SurfaceControl.Builder() .setParent(parent)
.setName("Blur layer") .setOpaque(false)
.setParent(parent) .setHidden(false)
.setOpaque(false) .setEffectLayer()
.setHidden(false) .build();
.setEffectLayer()
.build();
} else {
dimLayer = null;
}
depthController.setSurface(dimLayer); backgroundRadiusAnim.addListener(AnimatorListeners.forEndCallback(() ->
backgroundRadiusAnim.addListener(new AnimatorListenerAdapter() { new SurfaceControl.Transaction().remove(dimLayer).apply()));
@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();
}
}
});
} }
return backgroundRadiusAnim; return backgroundRadiusAnim;
} }
@@ -1936,4 +1919,17 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5); 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);
}
}
} }
@@ -23,13 +23,8 @@ import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTR
import android.animation.Animator; import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator; import android.animation.ObjectAnimator;
import android.app.WallpaperManager;
import android.os.IBinder;
import android.os.SystemProperties;
import android.util.FloatProperty; import android.util.FloatProperty;
import android.view.AttachedSurfaceControl;
import android.view.CrossWindowBlurListeners; import android.view.CrossWindowBlurListeners;
import android.view.SurfaceControl;
import android.view.View; import android.view.View;
import android.view.ViewRootImpl; import android.view.ViewRootImpl;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
@@ -37,12 +32,11 @@ import android.view.ViewTreeObserver;
import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseActivity;
import com.android.launcher3.Launcher; import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities; import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig; 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.io.PrintWriter;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -50,23 +44,9 @@ import java.util.function.Consumer;
/** /**
* Controls blur and wallpaper zoom, for the Launcher surface only. * 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 { 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 * 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). * animator goes beyond 0..1, the interpolated value will still be bounded).
@@ -92,96 +72,46 @@ public class DepthController implements StateHandler<LauncherState>,
} }
} }
private final ViewTreeObserver.OnDrawListener mOnDrawListener = private final ViewTreeObserver.OnDrawListener mOnDrawListener = this::onLauncherDraw;
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 Consumer<Boolean> mCrossWindowBlurListener = new Consumer<Boolean>() { private final Consumer<Boolean> mCrossWindowBlurListener = this::setCrossWindowBlursEnabled;
@Override
public void accept(Boolean enabled) {
mCrossWindowBlursEnabled = enabled;
dispatchTransactionSurface(mDepth);
}
};
private final Runnable mOpaquenessListener = new Runnable() { private final Runnable mOpaquenessListener = this::applyDepthAndBlur;
@Override
public void run() {
dispatchTransactionSurface(mDepth);
}
};
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. * If we're launching and app and should not be blurring the screen for performance reasons.
*/ */
private boolean mBlurDisabledForAppLaunch; private boolean mBlurDisabledForAppLaunch;
/**
* If we requested early wake-up offsets to SurfaceFlinger.
*/
private boolean mInEarlyWakeUp;
// Workaround for animating the depth when multiwindow mode changes. // Workaround for animating the depth when multiwindow mode changes.
private boolean mIgnoreStateChangesDuringMultiWindowAnimation = false; 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; private View.OnAttachStateChangeListener mOnAttachListener;
public DepthController(Launcher l) { 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() { 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) { if (mLauncher.getRootView() != null && mOnAttachListener == null) {
View rootView = mLauncher.getRootView();
mOnAttachListener = new View.OnAttachStateChangeListener() { mOnAttachListener = new View.OnAttachStateChangeListener() {
@Override @Override
public void onViewAttachedToWindow(View view) { 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. // To handle the case where window token is invalid during last setDepth call.
IBinder windowToken = mLauncher.getRootView().getWindowToken(); applyDepthAndBlur();
if (windowToken != null) {
mWallpaperManager.setWallpaperZoomOut(windowToken, mDepth);
}
onAttached();
} }
@Override @Override
@@ -190,23 +120,13 @@ public class DepthController implements StateHandler<LauncherState>,
mLauncher.getScrimView().removeOpaquenessListener(mOpaquenessListener); mLauncher.getScrimView().removeOpaquenessListener(mOpaquenessListener);
} }
}; };
mLauncher.getRootView().addOnAttachStateChangeListener(mOnAttachListener); rootView.addOnAttachStateChangeListener(mOnAttachListener);
if (mLauncher.getRootView().isAttachedToWindow()) { if (rootView.isAttachedToWindow()) {
onAttached(); 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 * Sets if the underlying activity is started or not
*/ */
@@ -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 @Override
public void setState(LauncherState toState) { public void setState(LauncherState toState) {
if (mSurface == null || mIgnoreStateChangesDuringMultiWindowAnimation) { if (mSurface == null || mIgnoreStateChangesDuringMultiWindowAnimation) {
@@ -249,7 +149,7 @@ public class DepthController implements StateHandler<LauncherState>,
if (Float.compare(mDepth, toDepth) != 0) { if (Float.compare(mDepth, toDepth) != 0) {
setDepth(toDepth); setDepth(toDepth);
} else if (toState == LauncherState.OVERVIEW) { } else if (toState == LauncherState.OVERVIEW) {
dispatchTransactionSurface(mDepth); applyDepthAndBlur();
} else if (toState == LauncherState.BACKGROUND_APP) { } else if (toState == LauncherState.BACKGROUND_APP) {
mLauncher.getDragLayer().getViewTreeObserver().addOnDrawListener(mOnDrawListener); mLauncher.getDragLayer().getViewTreeObserver().addOnDrawListener(mOnDrawListener);
} }
@@ -269,90 +169,10 @@ public class DepthController implements StateHandler<LauncherState>,
} }
} }
/** @Override
* If we're launching an app from the home screen. protected void applyDepthAndBlur() {
*/
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;
}
ensureDependencies(); ensureDependencies();
depth = Math.max(depth, mOverlayScrollProgress); super.applyDepthAndBlur();
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;
} }
@Override @Override
@@ -377,7 +197,6 @@ public class DepthController implements StateHandler<LauncherState>,
writer.println(prefix + "\tmMaxBlurRadius=" + mMaxBlurRadius); writer.println(prefix + "\tmMaxBlurRadius=" + mMaxBlurRadius);
writer.println(prefix + "\tmCrossWindowBlursEnabled=" + mCrossWindowBlursEnabled); writer.println(prefix + "\tmCrossWindowBlursEnabled=" + mCrossWindowBlursEnabled);
writer.println(prefix + "\tmSurface=" + mSurface); writer.println(prefix + "\tmSurface=" + mSurface);
writer.println(prefix + "\tmOverlayScrollProgress=" + mOverlayScrollProgress);
writer.println(prefix + "\tmDepth=" + mDepth); writer.println(prefix + "\tmDepth=" + mDepth);
writer.println(prefix + "\tmCurrentBlur=" + mCurrentBlur); writer.println(prefix + "\tmCurrentBlur=" + mCurrentBlur);
writer.println(prefix + "\tmBlurDisabledForAppLaunch=" + mBlurDisabledForAppLaunch); writer.println(prefix + "\tmBlurDisabledForAppLaunch=" + mBlurDisabledForAppLaunch);
@@ -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<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();
}
}
}