Skip to content
Snippets Groups Projects
Commit f20a6afc authored by Nate Myren's avatar Nate Myren
Browse files

Observe mic mute changes, consider recordingss paused when muted

Listen for the microphone mute state to change, and when it changes,
update the paused status of all audio recordings. If the mic is muted, then
every stream is considered paused.

Fixes: 168553482
Test: Get a call, then screen it. The "mic in use" icon should be
replaced by the mute icon

Change-Id: I5fad1f359c7009c924e8f7cce9c09f8ea299522a
parent 969e1943
No related branches found
No related tags found
No related merge requests found
......@@ -16,8 +16,13 @@
package com.android.systemui.appops;
import static android.media.AudioManager.ACTION_MICROPHONE_MUTE_CHANGED;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.media.AudioManager;
......@@ -34,6 +39,7 @@ import androidx.annotation.WorkerThread;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dumpable;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dump.DumpManager;
......@@ -54,7 +60,7 @@ import javax.inject.Inject;
* NotificationPresenter to be displayed to the user.
*/
@SysUISingleton
public class AppOpsControllerImpl implements AppOpsController,
public class AppOpsControllerImpl extends BroadcastReceiver implements AppOpsController,
AppOpsManager.OnOpActiveChangedInternalListener,
AppOpsManager.OnOpNotedListener, Dumpable {
......@@ -65,6 +71,7 @@ public class AppOpsControllerImpl implements AppOpsController,
private static final String TAG = "AppOpsControllerImpl";
private static final boolean DEBUG = false;
private final BroadcastDispatcher mDispatcher;
private final AppOpsManager mAppOps;
private final AudioManager mAudioManager;
private final LocationManager mLocationManager;
......@@ -79,6 +86,7 @@ public class AppOpsControllerImpl implements AppOpsController,
private final SparseArray<Set<Callback>> mCallbacksByCode = new SparseArray<>();
private final PermissionFlagsCache mFlagsCache;
private boolean mListening;
private boolean mMicMuted;
@GuardedBy("mActiveItems")
private final List<AppOpItem> mActiveItems = new ArrayList<>();
......@@ -105,8 +113,10 @@ public class AppOpsControllerImpl implements AppOpsController,
@Background Looper bgLooper,
DumpManager dumpManager,
PermissionFlagsCache cache,
AudioManager audioManager
AudioManager audioManager,
BroadcastDispatcher dispatcher
) {
mDispatcher = dispatcher;
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
mFlagsCache = cache;
mBGHandler = new H(bgLooper);
......@@ -115,6 +125,7 @@ public class AppOpsControllerImpl implements AppOpsController,
mCallbacksByCode.put(OPS[i], new ArraySet<>());
}
mAudioManager = audioManager;
mMicMuted = audioManager.isMicrophoneMute();
mLocationManager = context.getSystemService(LocationManager.class);
dumpManager.registerDumpable(TAG, this);
}
......@@ -133,6 +144,8 @@ public class AppOpsControllerImpl implements AppOpsController,
mAudioManager.registerAudioRecordingCallback(mAudioRecordingCallback, mBGHandler);
mBGHandler.post(() -> mAudioRecordingCallback.onRecordingConfigChanged(
mAudioManager.getActiveRecordingConfigurations()));
mDispatcher.registerReceiverWithHandler(this,
new IntentFilter(ACTION_MICROPHONE_MUTE_CHANGED), mBGHandler);
} else {
mAppOps.stopWatchingActive(this);
......@@ -140,6 +153,7 @@ public class AppOpsControllerImpl implements AppOpsController,
mAudioManager.unregisterAudioRecordingCallback(mAudioRecordingCallback);
mBGHandler.removeCallbacksAndMessages(null); // null removes all
mDispatcher.unregisterReceiver(this);
synchronized (mActiveItems) {
mActiveItems.clear();
mRecordingsByUid.clear();
......@@ -468,6 +482,9 @@ public class AppOpsControllerImpl implements AppOpsController,
}
private boolean isAnyRecordingPausedLocked(int uid) {
if (mMicMuted) {
return true;
}
List<AudioRecordingConfiguration> configs = mRecordingsByUid.get(uid);
if (configs == null) return false;
int configsNum = configs.size();
......@@ -522,6 +539,12 @@ public class AppOpsControllerImpl implements AppOpsController,
}
};
@Override
public void onReceive(Context context, Intent intent) {
mMicMuted = mAudioManager.isMicrophoneMute();
updateRecordingPausedStatus();
}
protected class H extends Handler {
H(Looper looper) {
super(looper);
......
......@@ -47,6 +47,7 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
import org.junit.Before;
......@@ -82,6 +83,8 @@ public class AppOpsControllerTest extends SysuiTestCase {
private PackageManager mPackageManager;
@Mock(stubOnly = true)
private AudioManager mAudioManager;
@Mock()
private BroadcastDispatcher mDispatcher;
@Mock(stubOnly = true)
private AudioManager.AudioRecordingCallback mRecordingCallback;
@Mock(stubOnly = true)
......@@ -120,7 +123,8 @@ public class AppOpsControllerTest extends SysuiTestCase {
mTestableLooper.getLooper(),
mDumpManager,
mFlagsCache,
mAudioManager
mAudioManager,
mDispatcher
);
}
......@@ -128,12 +132,14 @@ public class AppOpsControllerTest extends SysuiTestCase {
public void testOnlyListenForFewOps() {
mController.setListening(true);
verify(mAppOpsManager, times(1)).startWatchingActive(AppOpsControllerImpl.OPS, mController);
verify(mDispatcher, times(1)).registerReceiverWithHandler(eq(mController), any(), any());
}
@Test
public void testStopListening() {
mController.setListening(false);
verify(mAppOpsManager, times(1)).stopWatchingActive(mController);
verify(mDispatcher, times(1)).unregisterReceiver(mController);
}
@Test
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment