mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-20 11:18:21 +00:00
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:
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
|
||||
@@ -1044,54 +1044,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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<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).
|
||||
@@ -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 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<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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
public void setState(LauncherState toState) {
|
||||
if (mSurface == null || mIgnoreStateChangesDuringMultiWindowAnimation) {
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user