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

Commit fe952b8d authored by Jean-Michel Trivi's avatar Jean-Michel Trivi Committed by Android (Google) Code Review
Browse files

Merge "Utilities for managing event listeners from AudioService 2/2"

parents df24328f 54d129f9
Loading
Loading
Loading
Loading
+24 −62
Original line number Diff line number Diff line
@@ -2995,19 +2995,17 @@ public class AudioManager {
        void onModeChanged(@AudioMode int mode);
    }

    private final Object mModeListenerLock = new Object();
    /**
     * List of listeners for audio mode and their associated Executor.
     * List is lazy-initialized on first registration
     * manages the OnModeChangedListener listeners and the ModeDispatcherStub
     */
    @GuardedBy("mModeListenerLock")
    private @Nullable ArrayList<ListenerInfo<OnModeChangedListener>> mModeListeners;
    private final CallbackUtil.LazyListenerManager<OnModeChangedListener> mModeChangedListenerMgr =
            new CallbackUtil.LazyListenerManager();

    @GuardedBy("mModeListenerLock")
    private ModeDispatcherStub mModeDispatcherStub;

    private final class ModeDispatcherStub extends IAudioModeDispatcher.Stub {
    final class ModeDispatcherStub extends IAudioModeDispatcher.Stub
            implements CallbackUtil.DispatcherStub {

        @Override
        public void register(boolean register) {
            try {
                if (register) {
@@ -3021,10 +3019,8 @@ public class AudioManager {
        }

        @Override
        @SuppressLint("GuardedBy") // lock applied inside callListeners method
        public void dispatchAudioModeChanged(int mode) {
            CallbackUtil.callListeners(mModeListeners, mModeListenerLock,
                    (listener) -> listener.onModeChanged(mode));
            mModeChangedListenerMgr.callListeners((listener) -> listener.onModeChanged(mode));
        }
    }

@@ -3037,15 +3033,8 @@ public class AudioManager {
    public void addOnModeChangedListener(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull OnModeChangedListener listener) {
        synchronized (mModeListenerLock) {
            final Pair<ArrayList<ListenerInfo<OnModeChangedListener>>, ModeDispatcherStub> res =
                    CallbackUtil.addListener("addOnModeChangedListener",
                            executor, listener, mModeListeners, mModeDispatcherStub,
                            () -> new ModeDispatcherStub(),
                            stub -> stub.register(true));
            mModeListeners = res.first;
            mModeDispatcherStub = res.second;
        }
        mModeChangedListenerMgr.addListener(executor, listener, "addOnModeChangedListener",
                () -> new ModeDispatcherStub());
    }

    /**
@@ -3054,14 +3043,7 @@ public class AudioManager {
     * @param listener
     */
    public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) {
        synchronized (mModeListenerLock) {
            final Pair<ArrayList<ListenerInfo<OnModeChangedListener>>, ModeDispatcherStub> res =
                    CallbackUtil.removeListener("removeOnModeChangedListener",
                            listener, mModeListeners, mModeDispatcherStub,
                            stub -> stub.register(false));
            mModeListeners = res.first;
            mModeDispatcherStub = res.second;
        }
        mModeChangedListenerMgr.removeListener(listener, "removeOnModeChangedListener");
    }

    /**
@@ -7717,6 +7699,12 @@ public class AudioManager {
        void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device);
    }

    /**
     * manages the OnCommunicationDeviceChangedListener listeners and the
     * CommunicationDeviceDispatcherStub
     */
    private final CallbackUtil.LazyListenerManager<OnCommunicationDeviceChangedListener>
            mCommDeviceChangedListenerMgr = new CallbackUtil.LazyListenerManager();
    /**
     * Adds a listener for being notified of changes to the communication audio device.
     * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
@@ -7726,16 +7714,9 @@ public class AudioManager {
    public void addOnCommunicationDeviceChangedListener(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull OnCommunicationDeviceChangedListener listener) {
        synchronized (mCommDevListenerLock) {
            final Pair<ArrayList<ListenerInfo<OnCommunicationDeviceChangedListener>>,
                    CommunicationDeviceDispatcherStub> res =
                    CallbackUtil.addListener("addOnCommunicationDeviceChangedListener",
                            executor, listener, mCommDevListeners, mCommDevDispatcherStub,
                            () -> new CommunicationDeviceDispatcherStub(),
                            stub -> stub.register(true));
            mCommDevListeners = res.first;
            mCommDevDispatcherStub = res.second;
        }
        mCommDeviceChangedListenerMgr.addListener(
                            executor, listener, "addOnCommunicationDeviceChangedListener",
                            () -> new CommunicationDeviceDispatcherStub());
    }

    /**
@@ -7745,32 +7726,14 @@ public class AudioManager {
     */
    public void removeOnCommunicationDeviceChangedListener(
            @NonNull OnCommunicationDeviceChangedListener listener) {
        synchronized (mCommDevListenerLock) {
            final Pair<ArrayList<ListenerInfo<OnCommunicationDeviceChangedListener>>,
                    CommunicationDeviceDispatcherStub> res =
                    CallbackUtil.removeListener("removeOnCommunicationDeviceChangedListener",
                            listener, mCommDevListeners, mCommDevDispatcherStub,
                            stub -> stub.register(false));
            mCommDevListeners = res.first;
            mCommDevDispatcherStub = res.second;
        }
        mCommDeviceChangedListenerMgr.removeListener(listener,
                "removeOnCommunicationDeviceChangedListener");
    }

    private final Object mCommDevListenerLock = new Object();
    /**
     * List of listeners for preferred device for strategy and their associated Executor.
     * List is lazy-initialized on first registration
     */
    @GuardedBy("mCommDevListenerLock")
    private @Nullable
            ArrayList<ListenerInfo<OnCommunicationDeviceChangedListener>> mCommDevListeners;

    @GuardedBy("mCommDevListenerLock")
    private CommunicationDeviceDispatcherStub mCommDevDispatcherStub;

    private final class CommunicationDeviceDispatcherStub
            extends ICommunicationDeviceDispatcher.Stub {
            extends ICommunicationDeviceDispatcher.Stub implements CallbackUtil.DispatcherStub {

        @Override
        public void register(boolean register) {
            try {
                if (register) {
@@ -7784,10 +7747,9 @@ public class AudioManager {
        }

        @Override
        @SuppressLint("GuardedBy") // lock applied inside callListeners method
        public void dispatchCommunicationDeviceChanged(int portId) {
            AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
            CallbackUtil.callListeners(mCommDevListeners, mCommDevListenerLock,
            mCommDeviceChangedListenerMgr.callListeners(
                    (listener) -> listener.onCommunicationDeviceChanged(device));
        }
    }
+86 −0
Original line number Diff line number Diff line
@@ -18,11 +18,14 @@ package android.media;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.media.permission.ClearCallingIdentityContext;
import android.media.permission.SafeCloseable;
import android.util.Log;
import android.util.Pair;

import com.android.internal.annotations.GuardedBy;

import java.util.ArrayList;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -221,4 +224,87 @@ import java.util.concurrent.Executor;
        }

    }

    /**
     * Interface to be implemented by stub implementation for the events received from a server
     * to the class managing the listener API.
     * For an example see {@link AudioManager#ModeDispatcherStub} which registers with AudioService.
     */
    interface DispatcherStub {
        /**
         * Register/unregister the stub as a listener of the events to be forwarded to the listeners
         * managed by LazyListenerManager.
         * @param register true for registering, false to unregister
         */
        void register(boolean register);
    }

    /**
     * Class to manage a list of listeners and their callback, and the associated stub which
     * receives the events to be forwarded to the listeners.
     * The list of listeners and the stub and its registration are lazily initialized and registered
     * @param <T> the listener class
     */
    static class LazyListenerManager<T> {
        private final Object mListenerLock = new Object();

        @GuardedBy("mListenerLock")
        private @Nullable ArrayList<ListenerInfo<T>> mListeners;

        @GuardedBy("mListenerLock")
        private @Nullable DispatcherStub mDispatcherStub;

        LazyListenerManager() {
            // nothing to initialize as instances of dispatcher and list of listeners
            // are lazily initialized
        }

        /**
         * Add a new listener / executor pair for the configured listener
         * @param executor Executor for the callback
         * @param listener the listener to register
         * @param methodName the name of the method calling this utility method for easier to read
         *          exception messages
         * @param newStub how to build a new instance of the stub receiving the events when the
         *          number of listeners goes from 0 to 1, not called until then.
         */
        void addListener(@NonNull Executor executor, @NonNull T listener, String methodName,
                @NonNull java.util.function.Supplier<DispatcherStub> newStub) {
            synchronized (mListenerLock) {
                final Pair<ArrayList<ListenerInfo<T>>, DispatcherStub> res =
                        CallbackUtil.addListener(methodName,
                                executor, listener, mListeners, mDispatcherStub,
                                newStub,
                                stub -> stub.register(true));
                mListeners = res.first;
                mDispatcherStub = res.second;
            }
        }

        /**
         * Remove a previously registered listener
         * @param listener the listener to unregister
         * @param methodName the name of the method calling this utility method for easier to read
         *          exception messages
         */
        void removeListener(@NonNull T listener, String methodName) {
            synchronized (mListenerLock) {
                final Pair<ArrayList<ListenerInfo<T>>, DispatcherStub> res =
                        CallbackUtil.removeListener(methodName,
                                listener, mListeners, mDispatcherStub,
                                stub -> stub.register(false));
                mListeners = res.first;
                mDispatcherStub = res.second;
            }
        }

        /**
         * Call the registered listeners with the given callback method
         * @param callback the listener method to invoke
         */
        @SuppressLint("GuardedBy") // lock applied inside callListeners method
        void callListeners(CallbackMethod<T> callback) {
            CallbackUtil.callListeners(mListeners, mListenerLock, callback);
        }
    }
}
+26 −62
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import android.media.permission.ClearCallingIdentityContext;
import android.media.permission.SafeCloseable;
import android.os.RemoteException;
import android.util.Log;
import android.util.Pair;

import com.android.internal.annotations.GuardedBy;

@@ -376,16 +375,8 @@ public class Spatializer {
    public void addOnSpatializerStateChangedListener(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull OnSpatializerStateChangedListener listener) {
        synchronized (mStateListenerLock) {
            final Pair<ArrayList<ListenerInfo<OnSpatializerStateChangedListener>>,
                    SpatializerInfoDispatcherStub> res =
                    CallbackUtil.addListener("addOnSpatializerStateChangedListener",
                            executor, listener, mStateListeners, mInfoDispatcherStub,
                            () -> new SpatializerInfoDispatcherStub(),
                            stub -> stub.register(true));
            mStateListeners = res.first;
            mInfoDispatcherStub = res.second;
        }
        mStateListenerMgr.addListener(executor, listener, "addOnSpatializerStateChangedListener",
                () -> new SpatializerInfoDispatcherStub());
    }

    /**
@@ -396,15 +387,7 @@ public class Spatializer {
     */
    public void removeOnSpatializerStateChangedListener(
            @NonNull OnSpatializerStateChangedListener listener) {
        synchronized (mStateListenerLock) {
            final Pair<ArrayList<ListenerInfo<OnSpatializerStateChangedListener>>,
                    SpatializerInfoDispatcherStub> res =
                    CallbackUtil.removeListener("removeOnSpatializerStateChangedListener",
                            listener, mStateListeners, mInfoDispatcherStub,
                            stub -> stub.register(false));
            mStateListeners = res.first;
            mInfoDispatcherStub = res.second;
        }
        mStateListenerMgr.removeListener(listener, "removeOnSpatializerStateChangedListener");
    }

    /**
@@ -459,18 +442,16 @@ public class Spatializer {
        }
    }

    private final Object mStateListenerLock = new Object();
    /**
     * List of listeners for state listener and their associated Executor.
     * List is lazy-initialized on first registration
     * manages the OnSpatializerStateChangedListener listeners and the
     * SpatializerInfoDispatcherStub
     */
    @GuardedBy("mStateListenerLock")
    private @Nullable ArrayList<ListenerInfo<OnSpatializerStateChangedListener>> mStateListeners;
    private final CallbackUtil.LazyListenerManager<OnSpatializerStateChangedListener>
            mStateListenerMgr = new CallbackUtil.LazyListenerManager();

    @GuardedBy("mStateListenerLock")
    private @Nullable SpatializerInfoDispatcherStub mInfoDispatcherStub;

    private final class SpatializerInfoDispatcherStub extends ISpatializerCallback.Stub {
    private final class SpatializerInfoDispatcherStub extends ISpatializerCallback.Stub
            implements CallbackUtil.DispatcherStub {
        @Override
        public void register(boolean register) {
            try {
                if (register) {
@@ -486,7 +467,7 @@ public class Spatializer {
        @Override
        @SuppressLint("GuardedBy") // lock applied inside callListeners method
        public void dispatchSpatializerEnabledChanged(boolean enabled) {
            CallbackUtil.callListeners(mStateListeners, mStateListenerLock,
            mStateListenerMgr.callListeners(
                    (listener) -> listener.onSpatializerEnabledChanged(
                            Spatializer.this, enabled));
        }
@@ -494,7 +475,7 @@ public class Spatializer {
        @Override
        @SuppressLint("GuardedBy") // lock applied inside callListeners method
        public void dispatchSpatializerAvailableChanged(boolean available) {
            CallbackUtil.callListeners(mStateListeners, mStateListenerLock,
            mStateListenerMgr.callListeners(
                    (listener) -> listener.onSpatializerAvailableChanged(
                            Spatializer.this, available));
        }
@@ -612,16 +593,9 @@ public class Spatializer {
    public void addOnHeadTrackingModeChangedListener(
            @NonNull @CallbackExecutor Executor executor,
            @NonNull OnHeadTrackingModeChangedListener listener) {
        synchronized (mHeadTrackingListenerLock) {
            final Pair<ArrayList<ListenerInfo<OnHeadTrackingModeChangedListener>>,
                    SpatializerHeadTrackingDispatcherStub> res = CallbackUtil.addListener(
                        "addOnHeadTrackingModeChangedListener", executor, listener,
                        mHeadTrackingListeners, mHeadTrackingDispatcherStub,
                        () -> new SpatializerHeadTrackingDispatcherStub(),
                        stub -> stub.register(true));
            mHeadTrackingListeners = res.first;
            mHeadTrackingDispatcherStub = res.second;
        }
        mHeadTrackingListenerMgr.addListener(executor, listener,
                "addOnHeadTrackingModeChangedListener",
                 () -> new SpatializerHeadTrackingDispatcherStub());
    }

    /**
@@ -634,15 +608,8 @@ public class Spatializer {
    @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
    public void removeOnHeadTrackingModeChangedListener(
            @NonNull OnHeadTrackingModeChangedListener listener) {
        synchronized (mHeadTrackingListenerLock) {
            final Pair<ArrayList<ListenerInfo<OnHeadTrackingModeChangedListener>>,
                    SpatializerHeadTrackingDispatcherStub> res = CallbackUtil.removeListener(
                        "removeOnHeadTrackingModeChangedListener", listener,
                        mHeadTrackingListeners, mHeadTrackingDispatcherStub,
                        stub -> stub.register(false));
            mHeadTrackingListeners = res.first;
            mHeadTrackingDispatcherStub = res.second;
        }
        mHeadTrackingListenerMgr.removeListener(listener,
                "removeOnHeadTrackingModeChangedListener");
    }

    /**
@@ -828,20 +795,17 @@ public class Spatializer {
    //-----------------------------------------------------------------------------
    // head tracking callback management and stub

    private final Object mHeadTrackingListenerLock = new Object();
    /**
     * List of listeners for head tracking mode listener and their associated Executor.
     * List is lazy-initialized on first registration
     * manages the OnHeadTrackingModeChangedListener listeners and the
     * SpatializerHeadTrackingDispatcherStub
     */
    @GuardedBy("mHeadTrackingListenerLock")
    private @Nullable ArrayList<ListenerInfo<OnHeadTrackingModeChangedListener>>
            mHeadTrackingListeners;

    @GuardedBy("mHeadTrackingListenerLock")
    private @Nullable SpatializerHeadTrackingDispatcherStub mHeadTrackingDispatcherStub;
    private final CallbackUtil.LazyListenerManager<OnHeadTrackingModeChangedListener>
            mHeadTrackingListenerMgr = new CallbackUtil.LazyListenerManager();

    private final class SpatializerHeadTrackingDispatcherStub
            extends ISpatializerHeadTrackingModeCallback.Stub {
            extends ISpatializerHeadTrackingModeCallback.Stub
            implements CallbackUtil.DispatcherStub {
        @Override
        public void register(boolean register) {
            try {
                if (register) {
@@ -857,14 +821,14 @@ public class Spatializer {
        @Override
        @SuppressLint("GuardedBy") // lock applied inside callListeners method
        public void dispatchSpatializerActualHeadTrackingModeChanged(int mode) {
            CallbackUtil.callListeners(mHeadTrackingListeners, mHeadTrackingListenerLock,
            mHeadTrackingListenerMgr.callListeners(
                    (listener) -> listener.onHeadTrackingModeChanged(Spatializer.this, mode));
        }

        @Override
        @SuppressLint("GuardedBy") // lock applied inside callListeners method
        public void dispatchSpatializerDesiredHeadTrackingModeChanged(int mode) {
            CallbackUtil.callListeners(mHeadTrackingListeners, mHeadTrackingListenerLock,
            mHeadTrackingListenerMgr.callListeners(
                    (listener) -> listener.onDesiredHeadTrackingModeChanged(
                            Spatializer.this, mode));
        }