diff options
| author | 2021-02-16 16:39:57 +0100 | |
|---|---|---|
| committer | 2021-03-01 22:23:22 +0100 | |
| commit | 6e842a730c67ec9884efea514bbca5a2cb1d9ef9 (patch) | |
| tree | 8a3207ffff6e15555a9ce1efc7f66dbf016a9b82 | |
| parent | 7fe1a92c601961562d55251d944f59e773cd6b38 (diff) | |
Create listener for dynamic blurEnabled changes
This CL exposes an API to let apps know when the blur has been enabled
or disabled dynamically.
This could be due to battery saving mode turned on, tunnel mode being
used, minimal post processing requested, etc.
This adds a WindowManager.addCrossWindowBlurEnabledListener, which allows
apps to add/remove a listener for blur enabled state changes. The
listeners are registered in a CrossWindowBlurListeners, which receives
updates from WindowManagerService when blurEnabled changes.
CrossWindowBlurListeners only registers a remote listener if the client
initializes it. I.e. if the app is not interested in blurs, the
CrossWindowBlurListeners won't get initialized and won't register a
remote listener.
WindowManagerService holds a RemoteCallbackList, which holds listeners
for each client process and notifies them when there are updates. If any
of the listeners' process dies, the entry is removed from the list.
Bug: 177524486
Test: m
CTS-Coverage-Bug: 179990440
Change-Id: I3fe8f2d2008171d6b069e8ee6f3b47e5b5d60cfa
| -rw-r--r-- | core/api/current.txt | 3 | ||||
| -rw-r--r-- | core/api/system-current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageManager.java | 11 | ||||
| -rw-r--r-- | core/java/android/view/CrossWindowBlurListeners.java | 137 | ||||
| -rw-r--r-- | core/java/android/view/ICrossWindowBlurEnabledListener.aidl | 29 | ||||
| -rw-r--r-- | core/java/android/view/IWindowManager.aidl | 19 | ||||
| -rw-r--r-- | core/java/android/view/Window.java | 8 | ||||
| -rw-r--r-- | core/java/android/view/WindowManager.java | 71 | ||||
| -rw-r--r-- | core/java/android/view/WindowManagerImpl.java | 16 | ||||
| -rw-r--r-- | core/java/com/android/internal/policy/DecorView.java | 81 | ||||
| -rw-r--r-- | core/java/com/android/internal/policy/PhoneWindow.java | 11 | ||||
| -rw-r--r-- | core/java/com/android/server/SystemConfig.java | 7 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/BlurController.java | 76 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/WindowManagerService.java | 16 | ||||
| -rw-r--r-- | services/core/java/com/android/server/wm/WindowState.java | 9 |
15 files changed, 444 insertions, 51 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index cb7fc24e3977..ed357d7a3228 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -50154,9 +50154,12 @@ package android.view { } public interface WindowManager extends android.view.ViewManager { + method public default void addCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>); method @NonNull public default android.view.WindowMetrics getCurrentWindowMetrics(); method @Deprecated public android.view.Display getDefaultDisplay(); method @NonNull public default android.view.WindowMetrics getMaximumWindowMetrics(); + method public default boolean isCrossWindowBlurEnabled(); + method public default void removeCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>); method public void removeViewImmediate(android.view.View); } diff --git a/core/api/system-current.txt b/core/api/system-current.txt index c62b808b00b4..c9f8da2b350e 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2555,7 +2555,6 @@ package android.content.pm { field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio"; field public static final String FEATURE_CAMERA_TOGGLE = "android.hardware.camera.toggle"; field public static final String FEATURE_CONTEXT_HUB = "android.hardware.context_hub"; - field public static final String FEATURE_CROSS_LAYER_BLUR = "android.software.cross_layer_blur"; field @Deprecated public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery"; field public static final String FEATURE_INCREMENTAL_DELIVERY_VERSION = "android.software.incremental_delivery_version"; field public static final String FEATURE_MICROPHONE_TOGGLE = "android.hardware.microphone.toggle"; diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index ca882417394e..993f09e83ebd 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3656,17 +3656,6 @@ public abstract class PackageManager { public static final String FEATURE_APP_ENUMERATION = "android.software.app_enumeration"; /** - * Feature for {@link android.view.WindowManager.LayoutParams.backgroundBlurRedius} and - * {@link android.graphics.drawable.BackgroundBlurDrawable}: the device supports cross-layer - * blurring. - * - * @hide - */ - @SystemApi - @SdkConstant(SdkConstantType.FEATURE) - public static final String FEATURE_CROSS_LAYER_BLUR = "android.software.cross_layer_blur"; - - /** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has * a Keystore implementation that can only enforce limited use key in hardware with max usage * count equals to 1. diff --git a/core/java/android/view/CrossWindowBlurListeners.java b/core/java/android/view/CrossWindowBlurListeners.java new file mode 100644 index 000000000000..5a1b850133cb --- /dev/null +++ b/core/java/android/view/CrossWindowBlurListeners.java @@ -0,0 +1,137 @@ +/** + * Copyright (C) 2021 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 android.view; + +import android.os.Handler; +import android.os.Looper; +import android.os.RemoteException; +import android.os.SystemProperties; +import android.util.ArraySet; +import android.util.Log; + +import java.util.function.Consumer; + +/** + * Class that holds all registered {@link CrossWindowBlurEnabledListener}s. It listens + * for updates from the WindowManagerService and updates all registered listeners. + * @hide + */ +public final class CrossWindowBlurListeners { + private static final String TAG = "CrossWindowBlurListeners"; + + // property for background blur support in surface flinger + private static final String BLUR_PROPERTY = "ro.surface_flinger.supports_background_blur"; + public static final boolean CROSS_WINDOW_BLUR_SUPPORTED = + SystemProperties.get(BLUR_PROPERTY, "default").equals("1"); + + private static volatile CrossWindowBlurListeners sInstance; + private static final Object sLock = new Object(); + + private final BlurEnabledListenerInternal mListenerInternal = new BlurEnabledListenerInternal(); + private final ArraySet<Consumer<Boolean>> mListeners = new ArraySet(); + private final Handler mMainHandler = new Handler(Looper.getMainLooper()); + private boolean mInternalListenerAttached = false; + private boolean mCrossWindowBlurEnabled; + + private CrossWindowBlurListeners() {} + + /** + * Returns a CrossWindowBlurListeners instance + */ + public static CrossWindowBlurListeners getInstance() { + CrossWindowBlurListeners instance = sInstance; + if (instance == null) { + + synchronized (sLock) { + instance = sInstance; + if (instance == null) { + instance = new CrossWindowBlurListeners(); + sInstance = instance; + } + } + } + return instance; + } + + boolean isCrossWindowBlurEnabled() { + synchronized (sLock) { + attachInternalListenerIfNeededLocked(); + return mCrossWindowBlurEnabled; + } + } + + void addListener(Consumer<Boolean> listener) { + if (listener == null) return; + + synchronized (sLock) { + attachInternalListenerIfNeededLocked(); + + mListeners.add(listener); + notifyListenerOnMain(listener, mCrossWindowBlurEnabled); + } + } + + + void removeListener(Consumer<Boolean> listener) { + if (listener == null) return; + + synchronized (sLock) { + mListeners.remove(listener); + + if (mInternalListenerAttached && mListeners.size() == 0) { + try { + WindowManagerGlobal.getWindowManagerService() + .unregisterCrossWindowBlurEnabledListener(mListenerInternal); + mInternalListenerAttached = false; + } catch (RemoteException e) { + Log.d(TAG, "Could not unregister ICrossWindowBlurEnabledListener"); + } + } + } + } + + private void attachInternalListenerIfNeededLocked() { + if (!mInternalListenerAttached) { + try { + mCrossWindowBlurEnabled = WindowManagerGlobal.getWindowManagerService() + .registerCrossWindowBlurEnabledListener(mListenerInternal); + mInternalListenerAttached = true; + } catch (RemoteException e) { + Log.d(TAG, "Could not register ICrossWindowBlurEnabledListener"); + } + } + } + + private void notifyListenerOnMain(Consumer<Boolean> listener, boolean enabled) { + mMainHandler.post(() -> { + listener.accept(enabled); + }); + } + + private final class BlurEnabledListenerInternal extends ICrossWindowBlurEnabledListener.Stub { + @Override + public void onCrossWindowBlurEnabledChanged(boolean enabled) { + synchronized (sLock) { + mCrossWindowBlurEnabled = enabled; + + for (int i = 0; i < mListeners.size(); i++) { + notifyListenerOnMain(mListeners.valueAt(i), enabled); + } + } + } + } +} diff --git a/core/java/android/view/ICrossWindowBlurEnabledListener.aidl b/core/java/android/view/ICrossWindowBlurEnabledListener.aidl new file mode 100644 index 000000000000..69286e20fe17 --- /dev/null +++ b/core/java/android/view/ICrossWindowBlurEnabledListener.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 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 android.view; + +/** + * Listener to be invoked when cross-window blur is enabled or disabled. + * {@hide} + */ +oneway interface ICrossWindowBlurEnabledListener { + /** + * Method that will be invoked when cross-window blur is enabled or disabled. + * @param enabled True if cross-window blur is enabled. + */ + void onCrossWindowBlurEnabledChanged(boolean enabled); +} diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index afdf798d03ce..54778007c6ff 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -35,6 +35,7 @@ import android.os.ParcelFileDescriptor; import android.view.DisplayCutout; import android.view.IApplicationToken; import android.view.IAppTransitionAnimationSpecsFuture; +import android.view.ICrossWindowBlurEnabledListener; import android.view.IDisplayWindowInsetsController; import android.view.IDisplayWindowListener; import android.view.IDisplayFoldListener; @@ -730,7 +731,7 @@ interface IWindowManager void showGlobalActions(); /** - * Sets layer tracing flags for SurfaceFlingerTrace. + * Sets layer tracing flags for SurfaceFlingerTrace. * * @param flags see definition in SurfaceTracing.cpp */ @@ -799,4 +800,20 @@ interface IWindowManager * @param clientToken the window context's token */ void unregisterWindowContextListener(IBinder clientToken); + + /** + * Registers a listener, which is to be called whenever cross-window blur is enabled/disabled. + * + * @param listener the listener to be registered + * @return true if cross-window blur is currently enabled; false otherwise + */ + boolean registerCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener); + + /** + * Unregisters a listener which was registered with + * {@link #registerCrossWindowBlurEnabledListener()}. + * + * @param listener the listener to be unregistered + */ + void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener); } diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 1e5d7e0c9d2d..db7dcc1965aa 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -1720,10 +1720,18 @@ public abstract class Window { * which blurs the whole screen behind the window. Background blur blurs the screen behind * only within the bounds of the window. * + * Some devices might not support cross-window blur due to GPU limitations. It can also be + * disabled at runtime, e.g. during battery saving mode, when multimedia tunneling is used or + * when minimal post processing is requested. In such situations, no blur will be computed or + * drawn, resulting in a transparent window background. To avoid this, the app might want to + * change its theme to one that does not use blurs. To listen for cross-window blur + * enabled/disabled events, use {@link WindowManager#addCrossWindowBlurEnabledListener}. + * * @param blurRadius The blur radius to use for window background blur in pixels * * @see android.R.styleable#Window_windowBackgroundBlurRadius * @see WindowManager.LayoutParams#setBlurBehindRadius + * @see WindowManager#addCrossWindowBlurEnabledListener */ public void setBackgroundBlurRadius(int blurRadius) {} diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 2889e11e6f1f..2053826d91a9 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -121,6 +121,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.function.Consumer; /** * The interface that apps use to talk to the window manager. @@ -809,6 +810,64 @@ public interface WindowManager extends ViewManager { return DISPLAY_IME_POLICY_FALLBACK_DISPLAY; } + /** + * Returns whether cross-window blur is currently enabled. This affects both window blur behind + * (see {@link LayoutParams#setBlurBehindRadius}) and window background blur (see + * {@link Window#setBackgroundBlurRadius}). + * + * Cross-window blur might not be supported by some devices due to GPU limitations. It can also + * be disabled at runtime, e.g. during battery saving mode, when multimedia tunneling is used or + * when minimal post processing is requested. In such situations, no blur will be computed or + * drawn, so the blur target area will not be blurred. To handle this, the app might want to + * change its theme to one that does not use blurs. To listen for cross-window blur + * enabled/disabled events, use {@link #addCrossWindowBlurEnabledListener}. + * + * @see #addCrossWindowBlurEnabledListener + * @see LayoutParams#setBlurBehindRadius + * @see Window#setBackgroundBlurRadius + */ + default boolean isCrossWindowBlurEnabled() { + return false; + } + + /** + * Adds a listener, which will be called when cross-window blurs are enabled/disabled at + * runtime. This affects both window blur behind (see {@link LayoutParams#setBlurBehindRadius}) + * and window background blur (see {@link Window#setBackgroundBlurRadius}). + * + * Cross-window blur might not be supported by some devices due to GPU limitations. It can also + * be disabled at runtime, e.g. during battery saving mode, when multimedia tunneling is used or + * when minimal post processing is requested. In such situations, no blur will be computed or + * drawn, so the blur target area will not be blurred. To handle this, the app might want to + * change its theme to one that does not use blurs. + * + * The listener will be called on the main thread. + * + * If the listener is added successfully, it will be called immediately with the current + * cross-window blur enabled state. + * + * + * @param listener the listener to be added. It will be called back with a boolean parameter, + * which is true if cross-window blur is enabled and false if it is disabled + * + * @see #removeCrossWindowBlurEnabledListener + * @see #isCrossWindowBlurEnabled + * @see LayoutParams#setBlurBehindRadius + * @see Window#setBackgroundBlurRadius + */ + default void addCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) { + } + + /** + * Removes a listener, previously added with {@link #addCrossWindowBlurEnabledListener} + * + * @param listener the listener to be removed + * + * @see #addCrossWindowBlurEnabledListener + */ + default void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) { + } + public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable { /** * X position for this window. With the default gravity it is ignored. @@ -3537,7 +3596,8 @@ public interface WindowManager extends ViewManager { /** * Blurs the screen behind the window. The effect is similar to that of {@link #dimAmount}, - * but instead of dimmed, the content behind the window will be blurred. + * but instead of dimmed, the content behind the window will be blurred (or combined with + * the dim amount, if such is specified). * * The density of the blur is set by the blur radius. The radius defines the size * of the neighbouring area, from which pixels will be averaged to form the final @@ -3550,10 +3610,19 @@ public interface WindowManager extends ViewManager { * * Requires {@link #FLAG_BLUR_BEHIND} to be set. * + * Cross-window blur might not be supported by some devices due to GPU limitations. It can + * also be disabled at runtime, e.g. during battery saving mode, when multimedia tunneling + * is used or when minimal post processing is requested. In such situations, no blur will + * be computed or drawn, resulting in there being no depth separation between the window + * and the content behind it. To avoid this, the app might want to use more + * {@link #dimAmount} on its window. To listen for cross-window blur enabled/disabled + * events, use {@link #addCrossWindowBlurEnabledListener}. + * * @param blurBehindRadius The blur radius to use for blur behind in pixels * * @see #FLAG_BLUR_BEHIND * @see #getBlurBehindRadius + * @see WindowManager#addCrossWindowBlurEnabledListener * @see Window#setBackgroundBlurRadius */ public void setBlurBehindRadius(@IntRange(from = 0) int blurBehindRadius) { diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index 23842b3a41ac..b39870738d68 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -40,6 +40,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.IResultReceiver; import java.util.List; +import java.util.function.Consumer; /** * Provides low-level communication with the system window manager for @@ -301,4 +302,19 @@ public final class WindowManagerImpl implements WindowManager { throw e.rethrowFromSystemServer(); } } + + @Override + public boolean isCrossWindowBlurEnabled() { + return CrossWindowBlurListeners.getInstance().isCrossWindowBlurEnabled(); + } + + @Override + public void addCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) { + CrossWindowBlurListeners.getInstance().addListener(listener); + } + + @Override + public void removeCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) { + CrossWindowBlurListeners.getInstance().removeListener(listener); + } } diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 9840013935f8..9a91d2028953 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -124,6 +124,7 @@ import com.android.internal.widget.DecorCaptionView; import com.android.internal.widget.FloatingToolbar; import java.util.List; +import java.util.function.Consumer; /** @hide */ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks { @@ -282,14 +283,19 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind private final Paint mLegacyNavigationBarBackgroundPaint = new Paint(); private Insets mBackgroundInsets = Insets.NONE; private Insets mLastBackgroundInsets = Insets.NONE; - private int mLastBackgroundBlurRadius = 0; private boolean mDrawLegacyNavigationBarBackground; private PendingInsetsController mPendingInsetsController = new PendingInsetsController(); + + private int mOriginalBackgroundBlurRadius = 0; + private int mBackgroundBlurRadius = 0; + private int mLastBackgroundBlurRadius = 0; + private boolean mCrossWindowBlurEnabled; private final ViewTreeObserver.OnPreDrawListener mBackgroundBlurOnPreDrawListener = () -> { - updateBackgroundBlur(); + updateBackgroundBlurCorners(); return true; }; + private Consumer<Boolean> mCrossWindowBlurEnabledListener; DecorView(Context context, int featureId, PhoneWindow window, WindowManager.LayoutParams params) { @@ -1272,23 +1278,17 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind } if (mBackgroundInsets.equals(mLastBackgroundInsets) - && mWindow.mBackgroundBlurRadius == mLastBackgroundBlurRadius + && mBackgroundBlurRadius == mLastBackgroundBlurRadius && mLastOriginalBackgroundDrawable == mOriginalBackgroundDrawable) { return; } Drawable destDrawable = mOriginalBackgroundDrawable; - if (mWindow.mBackgroundBlurRadius > 0 && getViewRootImpl() != null - && mWindow.isTranslucent()) { - if (mBackgroundBlurDrawable == null) { - mBackgroundBlurDrawable = getViewRootImpl().createBackgroundBlurDrawable(); - } + if (mBackgroundBlurRadius > 0) { destDrawable = new LayerDrawable(new Drawable[] {mBackgroundBlurDrawable, mOriginalBackgroundDrawable}); - mLastBackgroundBlurRadius = mWindow.mBackgroundBlurRadius; } - if (destDrawable != null && !mBackgroundInsets.equals(Insets.NONE)) { destDrawable = new InsetDrawable(destDrawable, mBackgroundInsets.left, mBackgroundInsets.top, @@ -1309,23 +1309,60 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind super.setBackgroundDrawable(destDrawable); mLastBackgroundInsets = mBackgroundInsets; + mLastBackgroundBlurRadius = mBackgroundBlurRadius; mLastOriginalBackgroundDrawable = mOriginalBackgroundDrawable; } - private void updateBackgroundBlur() { + private void updateBackgroundBlurCorners() { if (mBackgroundBlurDrawable == null) return; + float cornerRadius = 0; // If the blur radius is 0, the blur region won't be sent to surface flinger, so we don't // need to calculate the corner radius. - if (mWindow.mBackgroundBlurRadius > 0) { - if (mOriginalBackgroundDrawable != null) { - final Outline outline = new Outline(); - mOriginalBackgroundDrawable.getOutline(outline); - mBackgroundBlurDrawable.setCornerRadius(outline.mMode == Outline.MODE_ROUND_RECT - ? outline.getRadius() : 0); + if (mBackgroundBlurRadius != 0 && mOriginalBackgroundDrawable != null) { + final Outline outline = new Outline(); + mOriginalBackgroundDrawable.getOutline(outline); + cornerRadius = outline.mMode == Outline.MODE_ROUND_RECT ? outline.getRadius() : 0; + } + mBackgroundBlurDrawable.setCornerRadius(cornerRadius); + } + + private void updateBackgroundBlurRadius() { + if (getViewRootImpl() == null) return; + + mBackgroundBlurRadius = mCrossWindowBlurEnabled && mWindow.isTranslucent() + ? mOriginalBackgroundBlurRadius : 0; + if (mBackgroundBlurDrawable == null && mBackgroundBlurRadius > 0) { + mBackgroundBlurDrawable = getViewRootImpl().createBackgroundBlurDrawable(); + } + + if (mBackgroundBlurDrawable != null) { + mBackgroundBlurDrawable.setBlurRadius(mBackgroundBlurRadius); + updateBackgroundDrawable(); + } + } + + void setBackgroundBlurRadius(int blurRadius) { + mOriginalBackgroundBlurRadius = blurRadius; + if (blurRadius > 0) { + if (mCrossWindowBlurEnabledListener == null) { + mCrossWindowBlurEnabledListener = enabled -> { + mCrossWindowBlurEnabled = enabled; + updateBackgroundBlurRadius(); + }; + getContext().getSystemService(WindowManager.class) + .addCrossWindowBlurEnabledListener(mCrossWindowBlurEnabledListener); + getViewTreeObserver().addOnPreDrawListener(mBackgroundBlurOnPreDrawListener); + } else { + updateBackgroundBlurRadius(); } + } else if (mCrossWindowBlurEnabledListener != null) { + mCrossWindowBlurEnabledListener = null; + getContext().getSystemService(WindowManager.class) + .removeCrossWindowBlurEnabledListener(mCrossWindowBlurEnabledListener); + getViewTreeObserver().removeOnPreDrawListener(mBackgroundBlurOnPreDrawListener); + updateBackgroundBlurRadius(); } - mBackgroundBlurDrawable.setBlurRadius(mWindow.mBackgroundBlurRadius); } @Override @@ -1758,9 +1795,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind cb.onAttachedToWindow(); } - getViewTreeObserver().addOnPreDrawListener(mBackgroundBlurOnPreDrawListener); - updateBackgroundDrawable(); - if (mFeatureId == -1) { /* * The main window has been attached, try to restore any panels @@ -1782,6 +1816,9 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind // renderer about it. mBackdropFrameRenderer.onConfigurationChange(); } + + updateBackgroundBlurRadius(); + mWindow.onViewRootImplSet(getViewRootImpl()); } @@ -1794,8 +1831,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind cb.onDetachedFromWindow(); } - getViewTreeObserver().removeOnPreDrawListener(mBackgroundBlurOnPreDrawListener); - if (mWindow.mDecorContentParent != null) { mWindow.mDecorContentParent.dismissPopups(); } diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index eb9c3a98994e..6049486b380c 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -75,6 +75,7 @@ import android.util.Pair; import android.util.SparseArray; import android.util.TypedValue; import android.view.ContextThemeWrapper; +import android.view.CrossWindowBlurListeners; import android.view.Gravity; import android.view.IRotationWatcher.Stub; import android.view.IScrollCaptureCallbacks; @@ -258,7 +259,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { Drawable mBackgroundDrawable = null; Drawable mBackgroundFallbackDrawable = null; - int mBackgroundBlurRadius = 0; + private int mBackgroundBlurRadius = 0; private boolean mLoadElevation = true; private float mElevation; @@ -1527,9 +1528,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public final void setBackgroundBlurRadius(int blurRadius) { super.setBackgroundBlurRadius(blurRadius); - if (getContext().getPackageManager().hasSystemFeature( - PackageManager.FEATURE_CROSS_LAYER_BLUR)) { - mBackgroundBlurRadius = Math.max(blurRadius, 0); + if (CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED) { + if (mBackgroundBlurRadius != Math.max(blurRadius, 0)) { + mBackgroundBlurRadius = Math.max(blurRadius, 0); + mDecor.setBackgroundBlurRadius(mBackgroundBlurRadius); + } } } diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index b40ffb0136f2..58df2be2b944 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -95,9 +95,6 @@ public class SystemConfig { // property for runtime configuration differentiation in vendor private static final String VENDOR_SKU_PROPERTY = "ro.boot.product.vendor.sku"; - // property for background blur support in surface flinger - private static final String BLUR_PROPERTY = "ro.surface_flinger.supports_background_blur"; - // Group-ids that are given to all packages as read from etc/permissions/*.xml. int[] mGlobalGids = EmptyArray.INT; @@ -1249,10 +1246,6 @@ public class SystemConfig { addFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0); } - if (SystemProperties.get(BLUR_PROPERTY, "default").equals("1")) { - addFeature(PackageManager.FEATURE_CROSS_LAYER_BLUR, 0); - } - if (SensorPrivacyManager.USE_MICROPHONE_TOGGLE) { addFeature(PackageManager.FEATURE_MICROPHONE_TOGGLE, 0); } diff --git a/services/core/java/com/android/server/wm/BlurController.java b/services/core/java/com/android/server/wm/BlurController.java new file mode 100644 index 000000000000..13295e8aca02 --- /dev/null +++ b/services/core/java/com/android/server/wm/BlurController.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2021 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.server.wm; + +import static android.view.CrossWindowBlurListeners.CROSS_WINDOW_BLUR_SUPPORTED; + +import android.os.RemoteCallbackList; +import android.os.RemoteException; +import android.view.ICrossWindowBlurEnabledListener; + +final class BlurController { + + private final RemoteCallbackList<ICrossWindowBlurEnabledListener> + mBlurEnabledListeners = new RemoteCallbackList<>(); + private final Object mLock = new Object(); + boolean mBlurEnabled; + + BlurController() { + mBlurEnabled = CROSS_WINDOW_BLUR_SUPPORTED; + } + + boolean registerCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener) { + if (listener == null) return false; + mBlurEnabledListeners.register(listener); + synchronized (mLock) { + return mBlurEnabled; + } + } + + void unregisterCrossWindowBlurEnabledListener(ICrossWindowBlurEnabledListener listener) { + if (listener == null) return; + mBlurEnabledListeners.unregister(listener); + } + + private void updateBlurEnabled() { + // TODO: add other factors disabling blurs + final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED; + synchronized (mLock) { + if (mBlurEnabled == newEnabled) { + return; + } + mBlurEnabled = newEnabled; + notifyBlurEnabledChanged(newEnabled); + } + } + + private void notifyBlurEnabledChanged(boolean enabled) { + int i = mBlurEnabledListeners.beginBroadcast(); + while (i > 0) { + i--; + ICrossWindowBlurEnabledListener listener = + mBlurEnabledListeners.getBroadcastItem(i); + try { + listener.onCrossWindowBlurEnabledChanged(enabled); + } catch (RemoteException e) { + } + } + mBlurEnabledListeners.finishBroadcast(); + } + + +} diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index cca85b217a74..aec50f08e227 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -224,6 +224,7 @@ import android.view.Display; import android.view.DisplayInfo; import android.view.Gravity; import android.view.IAppTransitionAnimationSpecsFuture; +import android.view.ICrossWindowBlurEnabledListener; import android.view.IDisplayFoldListener; import android.view.IDisplayWindowInsetsController; import android.view.IDisplayWindowListener; @@ -756,6 +757,8 @@ public class WindowManagerService extends IWindowManager.Stub final TaskSnapshotController mTaskSnapshotController; + final BlurController mBlurController = new BlurController(); + boolean mIsTouchDevice; boolean mIsFakeTouchDevice; @@ -5689,6 +5692,18 @@ public class WindowManagerService extends IWindowManager.Stub return mWindowTracing.isEnabled(); } + @Override + public boolean registerCrossWindowBlurEnabledListener( + ICrossWindowBlurEnabledListener listener) { + return mBlurController.registerCrossWindowBlurEnabledListener(listener); + } + + @Override + public void unregisterCrossWindowBlurEnabledListener( + ICrossWindowBlurEnabledListener listener) { + mBlurController.unregisterCrossWindowBlurEnabledListener(listener); + } + // ------------------------------------------------------------- // Internals // ------------------------------------------------------------- @@ -6428,6 +6443,7 @@ public class WindowManagerService extends IWindowManager.Stub } }); pw.print(" mInTouchMode="); pw.println(mInTouchMode); + pw.print(" mBlurEnabled="); pw.println(mBlurController.mBlurEnabled); pw.print(" mLastDisplayFreezeDuration="); TimeUtils.formatDuration(mLastDisplayFreezeDuration, pw); if ( mLastFinishedFreezeSource != null) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index ae7efcd34019..e9ce90bafafd 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -5265,7 +5265,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (!mAnimatingExit && mAppDied) { mIsDimming = true; getDimmer().dimAbove(getSyncTransaction(), this, DEFAULT_DIM_AMOUNT_DEAD_WINDOW); - } else if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || (mAttrs.flags & FLAG_BLUR_BEHIND) != 0) + } else if (((mAttrs.flags & FLAG_DIM_BEHIND) != 0 || shouldDrawBlurBehind()) && isVisibleNow() && !mHidden) { // Only show the Dimmer when the following is satisfied: // 1. The window has the flag FLAG_DIM_BEHIND or blur behind is requested @@ -5274,12 +5274,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // 4. The WS is not hidden. mIsDimming = true; final float dimAmount = (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? mAttrs.dimAmount : 0; - final int blurRadius = - (mAttrs.flags & FLAG_BLUR_BEHIND) != 0 ? mAttrs.getBlurBehindRadius() : 0; + final int blurRadius = shouldDrawBlurBehind() ? mAttrs.getBlurBehindRadius() : 0; getDimmer().dimBelow(getSyncTransaction(), this, mAttrs.dimAmount, blurRadius); } } + private boolean shouldDrawBlurBehind() { + return (mAttrs.flags & FLAG_BLUR_BEHIND) != 0 && mWmService.mBlurController.mBlurEnabled; + } + /** * Notifies SF about the priority of the window, if it changed. SF then uses this information * to decide which window's desired rendering rate should have a priority when deciding about |