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

Commit 917cfdf9 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi Committed by Aaron Kling
Browse files

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)
parent 90a5c103
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -38,6 +38,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}
@@ -76,6 +77,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);
+75 −9
Original line number Diff line number Diff line
@@ -1663,6 +1663,58 @@ public class AudioService extends IAudioService.Stub
    ///////////////////////////////////////////////////////////////////////////
    // IPC methods
    ///////////////////////////////////////////////////////////////////////////
    /** 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(), keyEventMode);
                break;
            case KeyEvent.KEYCODE_VOLUME_DOWN:
                    adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER,
                            AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller,
                            Binder.getCallingUid(), 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(), 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,
            String callingPackage, String caller) {
@@ -1676,12 +1728,12 @@ public class AudioService extends IAudioService.Stub
                    extVolCtlr, 0 /*delay*/);
        } else {
            adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
                    caller, Binder.getCallingUid());
                    caller, Binder.getCallingUid(), VOL_ADJUST_NORMAL);
        }
    }

    private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
            String callingPackage, String caller, int uid) {
            String callingPackage, String caller, int uid, int keyEventMode) {
        if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
                + ", flags=" + flags + ", caller=" + caller
                + ", volControlStream=" + mVolumeControlStream
@@ -1735,7 +1787,8 @@ public class AudioService extends IAudioService.Stub
            if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
        }

        adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
        adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid,
                keyEventMode);
    }

    /** @see AudioManager#adjustStreamVolume(int, int, int) */
@@ -1749,11 +1802,11 @@ 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());
                Binder.getCallingUid(), VOL_ADJUST_NORMAL);
    }

    protected void adjustStreamVolume(int streamType, int direction, int flags,
            String callingPackage, String caller, int uid) {
            String callingPackage, String caller, int uid, int keyEventMode) {
        if (mUseFixedVolume) {
            return;
        }
@@ -1976,8 +2029,21 @@ public class AudioService extends IAudioService.Stub
                        if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
                            final long ident = Binder.clearCallingIdentity();
                            try {
                                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);
                            }
@@ -6795,7 +6861,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);
                    callingPackage, uid, VOL_ADJUST_NORMAL);
        }

        @Override
@@ -6807,7 +6873,7 @@ public class AudioService extends IAudioService.Stub
                        .append(" uid:").append(uid).toString()));
            }
            adjustStreamVolume(streamType, direction, flags, callingPackage,
                    callingPackage, uid);
                    callingPackage, uid, VOL_ADJUST_NORMAL);
        }

        @Override
+8 −36
Original line number Diff line number Diff line
@@ -5014,6 +5014,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.
@@ -5028,42 +5030,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);
            getAudioService().handleVolumeKey(event, mUseTvRouting,
                    mContext.getOpPackageName(), 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;
            Log.e(TAG, "Error dispatching volume key in handleVolumeKey for event:"
                    + event, e);
        }
    }