diff options
6 files changed, 107 insertions, 8 deletions
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index 0daf30f25d59..638d81b2f635 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -76,6 +76,9 @@ interface IInputManager { // Registers a tablet mode change listener void registerTabletModeChangedListener(ITabletModeChangedListener listener); + // Queries whether the device's microphone is muted by switch + int isMicMuted(); + // Input device vibrator control. void vibrate(int deviceId, in long[] pattern, int repeat, IBinder token); void cancelVibrate(int deviceId, IBinder token); diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 2a59be28a937..0c0f248e3222 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -520,6 +520,22 @@ public final class InputManager { } /** + * Queries whether the device's microphone is muted + * + * @return The mic mute switch state which is one of {@link #SWITCH_STATE_UNKNOWN}, + * {@link #SWITCH_STATE_OFF} or {@link #SWITCH_STATE_ON}. + * @hide + */ + @SwitchState + public int isMicMuted() { + try { + return mIm.isMicMuted(); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** * Gets information about all supported keyboard layouts. * <p> * The input manager consults the built-in keyboard layouts as well diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 2d6cd242c702..f797da70e7d1 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1857,12 +1857,37 @@ public class AudioManager { } /** + * @hide + * Sets the microphone from switch mute on or off. + * <p> + * This method should only be used by InputManager to notify + * Audio Subsystem about Microphone Mute switch state. + * + * @param on set <var>true</var> to mute the microphone; + * <var>false</var> to turn mute off + */ + @UnsupportedAppUsage + public void setMicrophoneMuteFromSwitch(boolean on) { + final IAudioService service = getService(); + try { + service.setMicrophoneMuteFromSwitch(on); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Checks whether the microphone mute is on or off. * * @return true if microphone is muted, false if it's not */ public boolean isMicrophoneMute() { - return AudioSystem.isMicrophoneMuted(); + final IAudioService service = getService(); + try { + return service.isMicrophoneMuted(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 71f52a1b7d8e..fc056109baa4 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -106,8 +106,12 @@ interface IAudioService { List<AudioProductStrategy> getAudioProductStrategies(); + boolean isMicrophoneMuted(); + void setMicrophoneMute(boolean on, String callingPackage, int userId); + oneway void setMicrophoneMuteFromSwitch(boolean on); + void setRingerModeExternal(int ringerMode, String caller); void setRingerModeInternal(int ringerMode, String caller); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 77b3feec700e..7f7ef172f14d 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -59,6 +59,7 @@ import android.hardware.hdmi.HdmiAudioSystemClient; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiPlaybackClient; import android.hardware.hdmi.HdmiTvClient; +import android.hardware.input.InputManager; import android.hardware.usb.UsbManager; import android.media.AudioAttributes; import android.media.AudioFocusInfo; @@ -545,6 +546,10 @@ public class AudioService extends IAudioService.Stub private String mEnabledSurroundFormats; private boolean mSurroundModeChanged; + private boolean mMicMuteFromSwitch; + private boolean mMicMuteFromApi; + private boolean mMicMuteFromRestrictions; + @GuardedBy("mSettingsLock") private int mAssistantUid; @@ -882,6 +887,8 @@ public class AudioService extends IAudioService.Stub mRoleObserver.register(); onIndicateSystemReady(); + + setMicMuteFromSwitchInput(); } RoleObserver mRoleObserver; @@ -1021,6 +1028,8 @@ public class AudioService extends IAudioService.Stub sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE, SENDMSG_QUEUE, 1, 0, null, 0); + + setMicMuteFromSwitchInput(); } private void onDispatchAudioServerStateChange(boolean state) { @@ -2837,20 +2846,45 @@ public class AudioService extends IAudioService.Stub != PackageManager.PERMISSION_GRANTED) { return; } - setMicrophoneMuteNoCallerCheck(on, userId); + mMicMuteFromApi = on; + setMicrophoneMuteNoCallerCheck(userId); + } + + /** @see AudioManager#setMicrophoneMuteFromSwitch(boolean) */ + public void setMicrophoneMuteFromSwitch(boolean on) { + int userId = Binder.getCallingUid(); + if (userId != android.os.Process.SYSTEM_UID) { + Log.e(TAG, "setMicrophoneMuteFromSwitch() called from non system user!"); + return; + } + mMicMuteFromSwitch = on; + setMicrophoneMuteNoCallerCheck(userId); + } + + private void setMicMuteFromSwitchInput() { + InputManager im = mContext.getSystemService(InputManager.class); + final int isMicMuted = im.isMicMuted(); + if (isMicMuted != InputManager.SWITCH_STATE_UNKNOWN) { + setMicrophoneMuteFromSwitch(im.isMicMuted() != InputManager.SWITCH_STATE_OFF); + } + } + + public boolean isMicrophoneMuted() { + return mMicMuteFromSwitch || mMicMuteFromRestrictions || mMicMuteFromApi; } - private void setMicrophoneMuteNoCallerCheck(boolean on, int userId) { + private void setMicrophoneMuteNoCallerCheck(int userId) { + final boolean muted = isMicrophoneMuted(); if (DEBUG_VOL) { - Log.d(TAG, String.format("Mic mute %s, user=%d", on, userId)); + Log.d(TAG, String.format("Mic mute %d, user=%d", muted, userId)); } // only mute for the current user - if (getCurrentUserId() == userId) { + if (getCurrentUserId() == userId || userId == android.os.Process.SYSTEM_UID) { final boolean currentMute = AudioSystem.isMicrophoneMuted(); final long identity = Binder.clearCallingIdentity(); - AudioSystem.muteMicrophone(on); + AudioSystem.muteMicrophone(muted); Binder.restoreCallingIdentity(identity); - if (on != currentMute) { + if (muted != currentMute) { mContext.sendBroadcastAsUser( new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED) .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL); @@ -5378,7 +5412,8 @@ public class AudioService extends IAudioService.Stub final boolean isRestricted = newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE); if (wasRestricted != isRestricted) { - setMicrophoneMuteNoCallerCheck(isRestricted, userId); + mMicMuteFromRestrictions = isRestricted; + setMicrophoneMuteNoCallerCheck(userId); } } diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 75b9705e1045..b33870559f59 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -47,6 +47,7 @@ import android.hardware.input.InputManager; import android.hardware.input.InputManagerInternal; import android.hardware.input.KeyboardLayout; import android.hardware.input.TouchCalibration; +import android.media.AudioManager; import android.os.Binder; import android.os.Bundle; import android.os.Environment; @@ -294,6 +295,9 @@ public class InputManagerService extends IInputManager.Stub /** Switch code: Camera lens cover. When set the lens is covered. */ public static final int SW_CAMERA_LENS_COVER = 0x09; + /** Switch code: Microphone. When set it is off. */ + public static final int SW_MUTE_DEVICE = 0x0e; + public static final int SW_LID_BIT = 1 << SW_LID; public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE; public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE; @@ -304,6 +308,7 @@ public class InputManagerService extends IInputManager.Stub public static final int SW_JACK_BITS = SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT; public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER; + public static final int SW_MUTE_DEVICE_BIT = 1 << SW_MUTE_DEVICE; /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */ final boolean mUseDevInputEventForAudioJack; @@ -970,6 +975,11 @@ public class InputManagerService extends IInputManager.Stub } @Override // Binder call + public int isMicMuted() { + return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MUTE_DEVICE); + } + + @Override // Binder call public void registerTabletModeChangedListener(ITabletModeChangedListener listener) { if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE, "registerTabletModeChangedListener()")) { @@ -1779,6 +1789,12 @@ public class InputManagerService extends IInputManager.Stub mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED, args).sendToTarget(); } + + if ((switchMask & SW_MUTE_DEVICE_BIT) != 0) { + final boolean micMute = ((switchValues & SW_MUTE_DEVICE_BIT) != 0); + AudioManager audioManager = mContext.getSystemService(AudioManager.class); + audioManager.setMicrophoneMuteFromSwitch(micMute); + } } // Native callback. |