Fix volume key handling for key press repeat
The original code for translating volume key presses into CEC commands was sending the equivalent of a key up / key down for each call to adjustSuggestedStreamVolume. This behavior caused CEC commands to pile up in HdmiControlService, and a repeated key press (user keeping finger on volume button on remote) would cause volume to still change on the CEC device handling volume even after the key was released. The fix consists in changing how PhoneWindowManager communicates with AudioService, by passing the key event directly, so AudioService can communicate the key up / key down information to the CEC library, which already deals with repeated commands on the CEC bus. Bug: 137311120 Test: connect DUT to CEC TV or receiver capable of handling vol cmds, keep pressing on vol key, verify releasing key stops volume changes on TV/receiver. Change-Id: I7a75af651b6b424129515a8991b5afb15c62dba3 Merged-In: I7a75af651b6b424129515a8991b5afb15c62dba3 (cherry picked from commit 12ba113894ec8ad7c24913a0a09ea70047d25353) (cherry picked from commit 7e58c9145d71ba92053ad6629f910456566cfea9)
This commit is contained in:
committed by
Robin Lee
parent
1d22ea4eca
commit
7c7016071a
@@ -40,6 +40,7 @@ import android.media.audiopolicy.AudioVolumeGroup;
|
||||
import android.media.audiopolicy.IAudioPolicyCallback;
|
||||
import android.media.projection.IMediaProjection;
|
||||
import android.net.Uri;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
@@ -78,6 +79,9 @@ interface IAudioService {
|
||||
@UnsupportedAppUsage
|
||||
void setStreamVolume(int streamType, int index, int flags, String callingPackage);
|
||||
|
||||
oneway void handleVolumeKey(in KeyEvent event, boolean isOnTv,
|
||||
String callingPackage, String caller);
|
||||
|
||||
boolean isStreamMute(int streamType);
|
||||
|
||||
void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb);
|
||||
|
||||
@@ -1852,6 +1852,57 @@ public class AudioService extends IAudioService.Stub
|
||||
return AudioSystem.getDevicesForAttributes(attributes);
|
||||
}
|
||||
|
||||
/** Indicates no special treatment in the handling of the volume adjustement */
|
||||
private static final int VOL_ADJUST_NORMAL = 0;
|
||||
/** Indicates the start of a volume adjustement */
|
||||
private static final int VOL_ADJUST_START = 1;
|
||||
/** Indicates the end of a volume adjustment */
|
||||
private static final int VOL_ADJUST_END = 2;
|
||||
|
||||
// pre-condition: event.getKeyCode() is one of KeyEvent.KEYCODE_VOLUME_UP,
|
||||
// KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_MUTE
|
||||
public void handleVolumeKey(@NonNull KeyEvent event, boolean isOnTv,
|
||||
@NonNull String callingPackage, @NonNull String caller) {
|
||||
int keyEventMode = VOL_ADJUST_NORMAL;
|
||||
if (isOnTv) {
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
keyEventMode = VOL_ADJUST_START;
|
||||
} else { // may catch more than ACTION_UP, but will end vol adjustement
|
||||
// the vol key is either released (ACTION_UP), or multiple keys are pressed
|
||||
// (ACTION_MULTIPLE) and we don't know what to do for volume control on CEC, end
|
||||
// the repeated volume adjustement
|
||||
keyEventMode = VOL_ADJUST_END;
|
||||
}
|
||||
} else if (event.getAction() != KeyEvent.ACTION_DOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
int flags = AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_PLAY_SOUND
|
||||
| AudioManager.FLAG_FROM_KEY;
|
||||
|
||||
switch (event.getKeyCode()) {
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE,
|
||||
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
|
||||
Binder.getCallingUid(), true, keyEventMode);
|
||||
break;
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER,
|
||||
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
|
||||
Binder.getCallingUid(), true, keyEventMode);
|
||||
break;
|
||||
case KeyEvent.KEYCODE_VOLUME_MUTE:
|
||||
if (event.getRepeatCount() == 0) {
|
||||
adjustSuggestedStreamVolume(AudioManager.ADJUST_TOGGLE_MUTE,
|
||||
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
|
||||
Binder.getCallingUid(), true, VOL_ADJUST_NORMAL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Invalid key code " + event.getKeyCode() + " sent by " + callingPackage);
|
||||
return; // not needed but added if code gets added below this switch statement
|
||||
}
|
||||
}
|
||||
|
||||
/** @see AudioManager#adjustVolume(int, int) */
|
||||
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
|
||||
@@ -1879,12 +1930,13 @@ public class AudioService extends IAudioService.Stub
|
||||
mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
|
||||
caller, Binder.getCallingUid(), hasModifyAudioSettings);
|
||||
caller, Binder.getCallingUid(), hasModifyAudioSettings, VOL_ADJUST_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
|
||||
String callingPackage, String caller, int uid, boolean hasModifyAudioSettings) {
|
||||
String callingPackage, String caller, int uid, boolean hasModifyAudioSettings,
|
||||
int keyEventMode) {
|
||||
if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
|
||||
+ ", flags=" + flags + ", caller=" + caller
|
||||
+ ", volControlStream=" + mVolumeControlStream
|
||||
@@ -1939,7 +1991,7 @@ public class AudioService extends IAudioService.Stub
|
||||
}
|
||||
|
||||
adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid,
|
||||
hasModifyAudioSettings);
|
||||
hasModifyAudioSettings, keyEventMode);
|
||||
}
|
||||
|
||||
/** @see AudioManager#adjustStreamVolume(int, int, int)
|
||||
@@ -1957,11 +2009,12 @@ public class AudioService extends IAudioService.Stub
|
||||
sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_STREAM_VOL, streamType,
|
||||
direction/*val1*/, flags/*val2*/, callingPackage));
|
||||
adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
|
||||
Binder.getCallingUid(), hasModifyAudioSettings);
|
||||
Binder.getCallingUid(), hasModifyAudioSettings, VOL_ADJUST_NORMAL);
|
||||
}
|
||||
|
||||
protected void adjustStreamVolume(int streamType, int direction, int flags,
|
||||
String callingPackage, String caller, int uid, boolean hasModifyAudioSettings) {
|
||||
String callingPackage, String caller, int uid, boolean hasModifyAudioSettings,
|
||||
int keyEventMode) {
|
||||
if (mUseFixedVolume) {
|
||||
return;
|
||||
}
|
||||
@@ -2195,8 +2248,21 @@ public class AudioService extends IAudioService.Stub
|
||||
if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mHdmiPlaybackClient.sendVolumeKeyEvent(keyCode, true);
|
||||
mHdmiPlaybackClient.sendVolumeKeyEvent(keyCode, false);
|
||||
final long time = java.lang.System.currentTimeMillis();
|
||||
switch (keyEventMode) {
|
||||
case VOL_ADJUST_NORMAL:
|
||||
mHdmiPlaybackClient.sendVolumeKeyEvent(keyCode, true);
|
||||
mHdmiPlaybackClient.sendVolumeKeyEvent(keyCode, false);
|
||||
break;
|
||||
case VOL_ADJUST_START:
|
||||
mHdmiPlaybackClient.sendVolumeKeyEvent(keyCode, true);
|
||||
break;
|
||||
case VOL_ADJUST_END:
|
||||
mHdmiPlaybackClient.sendVolumeKeyEvent(keyCode, false);
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Invalid keyEventMode " + keyEventMode);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
@@ -7560,7 +7626,7 @@ public class AudioService extends IAudioService.Stub
|
||||
// direction and stream type swap here because the public
|
||||
// adjustSuggested has a different order than the other methods.
|
||||
adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
|
||||
callingPackage, uid, hasModifyAudioSettings);
|
||||
callingPackage, uid, hasModifyAudioSettings, VOL_ADJUST_NORMAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -7575,7 +7641,7 @@ public class AudioService extends IAudioService.Stub
|
||||
mContext.checkPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS, pid, uid)
|
||||
== PackageManager.PERMISSION_GRANTED;
|
||||
adjustStreamVolume(streamType, direction, flags, callingPackage,
|
||||
callingPackage, uid, hasModifyAudioSettings);
|
||||
callingPackage, uid, hasModifyAudioSettings, VOL_ADJUST_NORMAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4200,6 +4200,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
return false;
|
||||
}
|
||||
|
||||
// pre-condition: event.getKeyCode() is one of KeyEvent.KEYCODE_VOLUME_UP,
|
||||
// KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_MUTE
|
||||
private void dispatchDirectAudioEvent(KeyEvent event) {
|
||||
// When System Audio Mode is off, volume keys received by AVR can be either consumed by AVR
|
||||
// or forwarded to the TV. It's up to Amplifier manufacturer’s implementation.
|
||||
@@ -4214,42 +4216,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (event.getAction() != KeyEvent.ACTION_DOWN) {
|
||||
return;
|
||||
}
|
||||
int keyCode = event.getKeyCode();
|
||||
int flags = AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_PLAY_SOUND
|
||||
| AudioManager.FLAG_FROM_KEY;
|
||||
String pkgName = mContext.getOpPackageName();
|
||||
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
try {
|
||||
getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE,
|
||||
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName, TAG);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error dispatching volume up in dispatchTvAudioEvent.", e);
|
||||
}
|
||||
break;
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
try {
|
||||
getAudioService().adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER,
|
||||
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName, TAG);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error dispatching volume down in dispatchTvAudioEvent.", e);
|
||||
}
|
||||
break;
|
||||
case KeyEvent.KEYCODE_VOLUME_MUTE:
|
||||
try {
|
||||
if (event.getRepeatCount() == 0) {
|
||||
getAudioService().adjustSuggestedStreamVolume(
|
||||
AudioManager.ADJUST_TOGGLE_MUTE,
|
||||
AudioManager.USE_DEFAULT_STREAM_TYPE, flags, pkgName, TAG);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error dispatching mute in dispatchTvAudioEvent.", e);
|
||||
}
|
||||
break;
|
||||
try {
|
||||
getAudioService().handleVolumeKey(event, mUseTvRouting,
|
||||
mContext.getOpPackageName(), TAG);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error dispatching volume key in handleVolumeKey for event:"
|
||||
+ event, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user