Merge "Audio Injection respect Enterprise Policy"

This commit is contained in:
TreeHugger Robot
2022-02-10 07:52:02 +00:00
committed by Android (Google) Code Review
3 changed files with 122 additions and 5 deletions

View File

@@ -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;

View File

@@ -0,0 +1,96 @@
/*
* 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);
}
}
}
}

View File

@@ -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) {