diff options
| -rw-r--r-- | core/api/current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/view/CrossWindowBlurListeners.java | 37 | ||||
| -rw-r--r-- | core/java/android/view/WindowManager.java | 29 | ||||
| -rw-r--r-- | core/java/android/view/WindowManagerImpl.java | 10 |
4 files changed, 63 insertions, 14 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index c0940d6b81bc..9f5255b9de98 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -49878,6 +49878,7 @@ package android.view { public interface WindowManager extends android.view.ViewManager { method public default void addCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>); + method public default void addCrossWindowBlurEnabledListener(@NonNull java.util.concurrent.Executor, @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(); diff --git a/core/java/android/view/CrossWindowBlurListeners.java b/core/java/android/view/CrossWindowBlurListeners.java index 5a1b850133cb..55fc4f41f5eb 100644 --- a/core/java/android/view/CrossWindowBlurListeners.java +++ b/core/java/android/view/CrossWindowBlurListeners.java @@ -16,13 +16,19 @@ package android.view; +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; +import android.os.Binder; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.os.SystemProperties; -import android.util.ArraySet; +import android.util.ArrayMap; import android.util.Log; +import com.android.internal.util.Preconditions; + +import java.util.concurrent.Executor; import java.util.function.Consumer; /** @@ -42,7 +48,7 @@ public final class CrossWindowBlurListeners { private static final Object sLock = new Object(); private final BlurEnabledListenerInternal mListenerInternal = new BlurEnabledListenerInternal(); - private final ArraySet<Consumer<Boolean>> mListeners = new ArraySet(); + private final ArrayMap<Consumer<Boolean>, Executor> mListeners = new ArrayMap(); private final Handler mMainHandler = new Handler(Looper.getMainLooper()); private boolean mInternalListenerAttached = false; private boolean mCrossWindowBlurEnabled; @@ -74,20 +80,22 @@ public final class CrossWindowBlurListeners { } } - void addListener(Consumer<Boolean> listener) { - if (listener == null) return; + void addListener(@NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<Boolean> listener) { + Preconditions.checkNotNull(listener, "listener cannot be null"); + Preconditions.checkNotNull(executor, "executor cannot be null"); synchronized (sLock) { attachInternalListenerIfNeededLocked(); - mListeners.add(listener); - notifyListenerOnMain(listener, mCrossWindowBlurEnabled); + mListeners.put(listener, executor); + notifyListener(listener, executor, mCrossWindowBlurEnabled); } } void removeListener(Consumer<Boolean> listener) { - if (listener == null) return; + Preconditions.checkNotNull(listener, "listener cannot be null"); synchronized (sLock) { mListeners.remove(listener); @@ -116,10 +124,8 @@ public final class CrossWindowBlurListeners { } } - private void notifyListenerOnMain(Consumer<Boolean> listener, boolean enabled) { - mMainHandler.post(() -> { - listener.accept(enabled); - }); + private void notifyListener(Consumer<Boolean> listener, Executor executor, boolean enabled) { + executor.execute(() -> listener.accept(enabled)); } private final class BlurEnabledListenerInternal extends ICrossWindowBlurEnabledListener.Stub { @@ -128,8 +134,13 @@ public final class CrossWindowBlurListeners { synchronized (sLock) { mCrossWindowBlurEnabled = enabled; - for (int i = 0; i < mListeners.size(); i++) { - notifyListenerOnMain(mListeners.valueAt(i), enabled); + final long token = Binder.clearCallingIdentity(); + try { + for (int i = 0; i < mListeners.size(); i++) { + notifyListener(mListeners.keyAt(i), mListeners.valueAt(i), enabled); + } + } finally { + Binder.restoreCallingIdentity(token); } } } diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 818a2b04b5c0..04512c9abc0a 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -81,6 +81,7 @@ import static android.view.WindowLayoutParamsProto.X; import static android.view.WindowLayoutParamsProto.Y; import android.Manifest.permission; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -121,6 +122,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.concurrent.Executor; import java.util.function.Consumer; /** @@ -864,6 +866,33 @@ public interface WindowManager extends ViewManager { } /** + * 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. + * + * If the listener is added successfully, it will be called immediately with the current + * cross-window blur enabled state. + * + * @param executor {@link Executor} to handle the listener callback + * @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 @CallbackExecutor Executor executor, + @NonNull Consumer<Boolean> listener) { + } + + /** * Removes a listener, previously added with {@link #addCrossWindowBlurEnabledListener} * * @param listener the listener to be removed diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index e37522bc9986..8dce852a2d62 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -23,6 +23,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; +import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UiContext; @@ -40,6 +41,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.IResultReceiver; import java.util.List; +import java.util.concurrent.Executor; import java.util.function.Consumer; /** @@ -310,7 +312,13 @@ public final class WindowManagerImpl implements WindowManager { @Override public void addCrossWindowBlurEnabledListener(@NonNull Consumer<Boolean> listener) { - CrossWindowBlurListeners.getInstance().addListener(listener); + addCrossWindowBlurEnabledListener(mContext.getMainExecutor(), listener); + } + + @Override + public void addCrossWindowBlurEnabledListener(@NonNull @CallbackExecutor Executor executor, + @NonNull Consumer<Boolean> listener) { + CrossWindowBlurListeners.getInstance().addListener(executor, listener); } @Override |