Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6e842a73 authored by Galia Peycheva's avatar Galia Peycheva
Browse files

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
parent 7fe1a92c
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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);
  }
+0 −1
Original line number Diff line number Diff line
@@ -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";
+0 −11
Original line number Diff line number Diff line
@@ -3655,17 +3655,6 @@ public abstract class PackageManager {
    @SdkConstant(SdkConstantType.FEATURE)
    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
+137 −0
Original line number Diff line number Diff line
/**
 * 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);
                }
            }
        }
    }
}
+29 −0
Original line number Diff line number Diff line
/*
 * 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);
}
Loading