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

Commit 8cb4fa9e authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Audio Injection respect Enterprise Policy"

parents 894c6a9d f45b4796
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -43,13 +43,20 @@ public final class AudioInjection {
    private static final String TAG = "AudioInjection";

    private final Object mLock = new Object();

    @GuardedBy("mLock")
    @Nullable
    private AudioTrack mAudioTrack;

    @GuardedBy("mLock")
    private int mPlayState = PLAYSTATE_STOPPED;
    @GuardedBy("mLock")
    private boolean mIsSilent;

    /** Sets if the injected microphone sound is silent. */
    void setSilent(boolean isSilent) {
        synchronized (mLock) {
            mIsSilent = isSilent;
        }
    }

    /**
     * Sets the {@link AudioTrack} to handle audio injection.
@@ -86,7 +93,7 @@ public final class AudioInjection {
    public int write(@NonNull ByteBuffer audioBuffer, int sizeInBytes, int writeMode) {
        final int sizeWrite;
        synchronized (mLock) {
            if (mAudioTrack != null) {
            if (mAudioTrack != null && !mIsSilent) {
                sizeWrite = mAudioTrack.write(audioBuffer, sizeInBytes, writeMode);
            } else {
                sizeWrite = 0;
+96 −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.audio;

import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.UserManager;

import com.android.internal.annotations.GuardedBy;

/**
 * Class to detect the user restrictions change for microphone usage.
 */
final class UserRestrictionsDetector extends BroadcastReceiver {
    private static final String TAG = "UserRestrictionsDetector";

    /** Interface for listening user restrictions change. */
    interface UserRestrictionsCallback {

        /** Notifies when value of {@link UserManager#DISALLOW_UNMUTE_MICROPHONE} is changed. */
        void onMicrophoneRestrictionChanged(boolean isUnmuteMicDisallowed);
    }

    private final Context mContext;
    private final UserManager mUserManager;
    private final Object mLock = new Object();
    @GuardedBy("mLock")
    private boolean mIsUnmuteMicDisallowed;
    private UserRestrictionsCallback mUserRestrictionsCallback;

    UserRestrictionsDetector(Context context) {
        mContext = context;
        mUserManager = context.getSystemService(UserManager.class);
    }

    /** Returns value of {@link UserManager#DISALLOW_UNMUTE_MICROPHONE}. */
    boolean isUnmuteMicrophoneDisallowed() {
        Bundle bundle = mUserManager.getUserRestrictions();
        return bundle.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
    }

    /** Registers user restrictions change. */
    void register(@NonNull UserRestrictionsCallback callback) {
        mUserRestrictionsCallback = callback;

        IntentFilter filter = new IntentFilter();
        filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
        mContext.registerReceiver(/* receiver= */ this, filter);

        synchronized (mLock) {
            // Gets initial value.
            mIsUnmuteMicDisallowed = isUnmuteMicrophoneDisallowed();
        }
    }

    /** Unregisters user restrictions change. */
    void unregister() {
        mUserRestrictionsCallback = null;
        mContext.unregisterReceiver(/* receiver= */ this);
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        if (UserManager.ACTION_USER_RESTRICTIONS_CHANGED.equals(action)) {
            boolean isUnmuteMicDisallowed = isUnmuteMicrophoneDisallowed();
            synchronized (mLock) {
                if (isUnmuteMicDisallowed == mIsUnmuteMicDisallowed) {
                    return;
                }
                mIsUnmuteMicDisallowed = isUnmuteMicDisallowed;
            }
            if (mUserRestrictionsCallback != null) {
                mUserRestrictionsCallback.onMicrophoneRestrictionChanged(isUnmuteMicDisallowed);
            }
        }
    }
}
+16 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.companion.virtual.audio;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.companion.virtual.audio.UserRestrictionsDetector.UserRestrictionsCallback;
import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback;
import android.content.Context;
import android.media.AudioFormat;
@@ -50,10 +51,11 @@ import java.util.concurrent.Executor;
 */
@VisibleForTesting
public final class VirtualAudioSession extends IAudioSessionCallback.Stub implements
        Closeable {
        UserRestrictionsCallback, Closeable {
    private static final String TAG = "VirtualAudioSession";

    private final Context mContext;
    private final UserRestrictionsDetector mUserRestrictionsDetector;
    /** The {@link Executor} for sending {@link AudioConfigurationChangeCallback} to the caller */
    private final Executor mExecutor;
    @Nullable
@@ -81,6 +83,7 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem
    public VirtualAudioSession(Context context,
            @Nullable AudioConfigurationChangeCallback callback, @Nullable Executor executor) {
        mContext = context;
        mUserRestrictionsDetector = new UserRestrictionsDetector(context);
        mCallback = callback;
        mExecutor = executor != null ? executor : context.getMainExecutor();
    }
@@ -117,7 +120,7 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem
    @NonNull
    public AudioInjection startAudioInjection(@NonNull AudioFormat injectionFormat) {
        Objects.requireNonNull(injectionFormat, "injectionFormat must not be null");

        mUserRestrictionsDetector.register(/* callback= */ this);
        synchronized (mLock) {
            if (mAudioInjection != null) {
                throw new IllegalStateException(
@@ -127,6 +130,7 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem
            mInjectionFormat = injectionFormat;
            mAudioInjection = new AudioInjection();
            mAudioInjection.play();
            mAudioInjection.setSilent(mUserRestrictionsDetector.isUnmuteMicrophoneDisallowed());
            return mAudioInjection;
        }
    }
@@ -170,6 +174,7 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem
    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
    @Override
    public void close() {
        mUserRestrictionsDetector.unregister();
        releaseAudioStreams();
        synchronized (mLock) {
            mAudioCapture = null;
@@ -179,6 +184,15 @@ public final class VirtualAudioSession extends IAudioSessionCallback.Stub implem
        }
    }

    @Override
    public void onMicrophoneRestrictionChanged(boolean isUnmuteMicDisallowed) {
        synchronized (mLock) {
            if (mAudioInjection != null) {
                mAudioInjection.setSilent(isUnmuteMicDisallowed);
            }
        }
    }

    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
    private void createAudioStreams(int[] appUids) {
        synchronized (mLock) {