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

Commit 2ffa2cc0 authored by Ján Sebechlebský's avatar Ján Sebechlebský Committed by Android (Google) Code Review
Browse files

Merge "Add listener to sound effects played on VirtualDevice."

parents b65e1af6 6f97640b
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -3010,8 +3010,13 @@ package android.companion.virtual {
    method public void onIntentIntercepted(@NonNull android.content.Intent);
  }
  public static interface VirtualDeviceManager.SoundEffectListener {
    method public void onPlaySoundEffect(int);
  }
  public static class VirtualDeviceManager.VirtualDevice implements java.lang.AutoCloseable {
    method public void addActivityListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
    method public void addSoundEffectListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.SoundEffectListener);
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
    method @NonNull public android.content.Context createContext();
    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.audio.VirtualAudioDevice createVirtualAudioDevice(@NonNull android.hardware.display.VirtualDisplay, @Nullable java.util.concurrent.Executor, @Nullable android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback);
@@ -3030,6 +3035,7 @@ package android.companion.virtual {
    method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void registerIntentInterceptor(@NonNull android.content.IntentFilter, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
    method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
    method public void removeSoundEffectListener(@NonNull android.companion.virtual.VirtualDeviceManager.SoundEffectListener);
    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setShowPointerIcon(boolean);
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void unregisterIntentInterceptor(@NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
  }
+13 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.companion.virtual;

import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceActivityListener;
import android.companion.virtual.IVirtualDeviceSoundEffectListener;
import android.companion.virtual.VirtualDevice;
import android.companion.virtual.VirtualDeviceParams;
import android.hardware.display.IVirtualDisplayCallback;
@@ -41,10 +42,12 @@ interface IVirtualDeviceManager {
     * @param params The parameters for creating this virtual device. See {@link
     *   VirtualDeviceManager.VirtualDeviceParams}.
     * @param activityListener The listener to listen for activity changes in a virtual device.
     * @param soundEffectListener The listener to listen for sound effect playback requests.
     */
    IVirtualDevice createVirtualDevice(
            in IBinder token, String packageName, int associationId,
            in VirtualDeviceParams params, in IVirtualDeviceActivityListener activityListener);
            in VirtualDeviceParams params, in IVirtualDeviceActivityListener activityListener,
            in IVirtualDeviceSoundEffectListener soundEffectListener);

    /**
     * Returns the details of all available virtual devices.
@@ -92,4 +95,13 @@ interface IVirtualDeviceManager {
     * if there's none.
     */
    int getAudioRecordingSessionId(int deviceId);

    /**
     * Triggers sound effect playback on virtual device.
     *
     * @param deviceId id of the virtual device.
     * @param sound effect type corresponding to
     *     {@code android.media.AudioManager.SystemSoundEffect}
     */
    void playSoundEffect(int deviceId, int effectType);
}
+34 −0
Original line number Diff line number Diff line
/*
 * 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 android.companion.virtual;

/**
 * Interface to listen for sound effect playback on Virtual Device.
 *
 * @hide
 */
oneway interface IVirtualDeviceSoundEffectListener {


    /**
     * Called when there's sound effect to be played on Virtual Device.
     *
     * @param sound effect type corresponding to
     *     {@code android.media.AudioManager.SystemSoundEffect}
     */
    void onPlaySoundEffect(int effectType);
}
+96 −5
Original line number Diff line number Diff line
@@ -69,6 +69,8 @@ import android.util.ArrayMap;
import android.util.Log;
import android.view.Surface;

import com.android.internal.annotations.GuardedBy;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -333,10 +335,15 @@ public final class VirtualDeviceManager {
     * @hide
     */
    public void playSoundEffect(int deviceId, @AudioManager.SystemSoundEffect int effectType) {
        //TODO - handle requests to play sound effects by custom callbacks or SoundPool asociated
        // with device session id.
        // For now, this is intentionally left empty and effectively disables sound effects for
        // virtual devices with custom device audio policy.
        if (mService == null) {
            Log.w(TAG, "Failed to dispatch sound effect; no virtual device manager service.");
            return;
        }
        try {
            mService.playSoundEffect(deviceId, effectType);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
@@ -359,6 +366,10 @@ public final class VirtualDeviceManager {
        private final ArrayMap<IntentInterceptorCallback,
                     VirtualIntentInterceptorDelegate> mIntentInterceptorListeners =
                new ArrayMap<>();
        private final Object mSoundEffectListenersLock = new Object();
        @GuardedBy("mSoundEffectListenersLock")
        private final ArrayMap<SoundEffectListener, SoundEffectListenerDelegate>
                mSoundEffectListeners = new ArrayMap<>();
        private final IVirtualDeviceActivityListener mActivityListenerBinder =
                new IVirtualDeviceActivityListener.Stub() {

@@ -387,6 +398,22 @@ public final class VirtualDeviceManager {
                        }
                    }
                };
        private final IVirtualDeviceSoundEffectListener mSoundEffectListener =
                new IVirtualDeviceSoundEffectListener.Stub() {
                    @Override
                    public void onPlaySoundEffect(int soundEffect) {
                        final long token = Binder.clearCallingIdentity();
                        try {
                            synchronized (mSoundEffectListenersLock) {
                                for (int i = 0; i < mSoundEffectListeners.size(); i++) {
                                    mSoundEffectListeners.valueAt(i).onPlaySoundEffect(soundEffect);
                                }
                            }
                        } finally {
                            Binder.restoreCallingIdentity(token);
                        }
                    }
                };
        @Nullable
        private VirtualCameraDevice mVirtualCameraDevice;
        @NonNull
@@ -407,7 +434,8 @@ public final class VirtualDeviceManager {
                    mContext.getPackageName(),
                    associationId,
                    params,
                    mActivityListenerBinder);
                    mActivityListenerBinder,
                    mSoundEffectListener);
            final List<VirtualSensorConfig> virtualSensorConfigs = params.getVirtualSensorConfigs();
            for (int i = 0; i < virtualSensorConfigs.size(); ++i) {
                mVirtualSensors.add(createVirtualSensor(virtualSensorConfigs.get(i)));
@@ -946,6 +974,35 @@ public final class VirtualDeviceManager {
            mActivityListeners.remove(listener);
        }

        /**
         * Adds a sound effect listener.
         *
         * @param executor The executor where the listener is executed on.
         * @param soundEffectListener The listener to add.
         * @see #removeActivityListener(ActivityListener)
         */
        public void addSoundEffectListener(@CallbackExecutor @NonNull Executor executor,
                @NonNull SoundEffectListener soundEffectListener) {
            final SoundEffectListenerDelegate delegate =
                    new SoundEffectListenerDelegate(Objects.requireNonNull(executor),
                            Objects.requireNonNull(soundEffectListener));
            synchronized (mSoundEffectListenersLock) {
                mSoundEffectListeners.put(soundEffectListener, delegate);
            }
        }

        /**
         * Removes a sound effect listener previously added with {@link #addActivityListener}.
         *
         * @param soundEffectListener The listener to remove.
         * @see #addActivityListener(Executor, ActivityListener)
         */
        public void removeSoundEffectListener(@NonNull SoundEffectListener soundEffectListener) {
            synchronized (mSoundEffectListenersLock) {
                mSoundEffectListeners.remove(soundEffectListener);
            }
        }

        /**
         * Registers an intent interceptor that will intercept an intent attempting to launch
         * when matching the provided IntentFilter and calls the callback with the intercepted
@@ -1090,4 +1147,38 @@ public final class VirtualDeviceManager {
            }
        }
    }

    /**
     * Listener for system sound effect playback on virtual device.
     * @hide
     */
    @SystemApi
    public interface SoundEffectListener {

        /**
         * Called when there's a system sound effect to be played on virtual device.
         *
         * @param effectType - system sound effect type, see
         *     {@code android.media.AudioManager.SystemSoundEffect}
         */
        void onPlaySoundEffect(@AudioManager.SystemSoundEffect int effectType);
    }

    /**
     * A wrapper for {@link SoundEffectListener} that executes callbacks on the given executor.
     */
    private static class SoundEffectListenerDelegate {
        @NonNull private final SoundEffectListener mSoundEffectListener;
        @NonNull private final Executor mExecutor;

        private SoundEffectListenerDelegate(Executor executor,
                SoundEffectListener soundEffectCallback) {
            mSoundEffectListener = soundEffectCallback;
            mExecutor = executor;
        }

        public void onPlaySoundEffect(@AudioManager.SystemSoundEffect int effectType) {
            mExecutor.execute(() -> mSoundEffectListener.onPlaySoundEffect(effectType));
        }
    }
}
+14 −0
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.companion.AssociationInfo;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceActivityListener;
import android.companion.virtual.IVirtualDeviceIntentInterceptor;
import android.companion.virtual.IVirtualDeviceSoundEffectListener;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceManager.ActivityListener;
import android.companion.virtual.VirtualDeviceParams;
@@ -119,6 +120,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
    private final VirtualDeviceParams mParams;
    private final Map<Integer, PowerManager.WakeLock> mPerDisplayWakelocks = new ArrayMap<>();
    private final IVirtualDeviceActivityListener mActivityListener;
    private final IVirtualDeviceSoundEffectListener mSoundEffectListener;
    @GuardedBy("mVirtualDeviceLock")
    private final Map<IBinder, IntentFilter> mIntentInterceptors = new ArrayMap<>();
    @NonNull
@@ -170,6 +172,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
            OnDeviceCloseListener onDeviceCloseListener,
            PendingTrampolineCallback pendingTrampolineCallback,
            IVirtualDeviceActivityListener activityListener,
            IVirtualDeviceSoundEffectListener soundEffectListener,
            Consumer<ArraySet<Integer>> runningAppsChangedCallback,
            VirtualDeviceParams params) {
        this(
@@ -184,6 +187,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
                onDeviceCloseListener,
                pendingTrampolineCallback,
                activityListener,
                soundEffectListener,
                runningAppsChangedCallback,
                params);
    }
@@ -201,6 +205,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
            OnDeviceCloseListener onDeviceCloseListener,
            PendingTrampolineCallback pendingTrampolineCallback,
            IVirtualDeviceActivityListener activityListener,
            IVirtualDeviceSoundEffectListener soundEffectListener,
            Consumer<ArraySet<Integer>> runningAppsChangedCallback,
            VirtualDeviceParams params) {
        super(PermissionEnforcer.fromContext(context));
@@ -209,6 +214,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
        mAssociationInfo = associationInfo;
        mPendingTrampolineCallback = pendingTrampolineCallback;
        mActivityListener = activityListener;
        mSoundEffectListener = soundEffectListener;
        mRunningAppsChangedCallback = runningAppsChangedCallback;
        mOwnerUid = ownerUid;
        mDeviceId = deviceId;
@@ -937,6 +943,14 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
                Toast.LENGTH_LONG, mContext.getMainLooper());
    }

    void playSoundEffect(int effectType) {
        try {
            mSoundEffectListener.onPlaySoundEffect(effectType);
        } catch (RemoteException exception) {
            Slog.w(TAG, "Unable to invoke sound effect listener", exception);
        }
    }

    /**
     * Intercepts intent when matching any of the IntentFilter of any interceptor. Returns true if
     * the intent matches any filter notifying the DisplayPolicyController to abort the
Loading