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

Commit 8566be3c authored by Jinsuk Kim's avatar Jinsuk Kim
Browse files

CEC: Ensure the key transmission finishes all the time

Defined a new timeout AWAIT_RELEASE_KEY_MS used to finish the SendKeyAction
if a release key event goes missing. Press-and-hold is done by utilizing
repeat Android key events, not timer waiting IRT_MS.

Bug: 17761639
Change-Id: I8cf4db899b3d96c5d269e41f3eb7dbbf960d27f8
parent 398de894
Loading
Loading
Loading
Loading
+0 −7
Original line number Original line Diff line number Diff line
@@ -205,13 +205,6 @@ final class Constants {


    static final int UNKNOWN_VOLUME = -1;
    static final int UNKNOWN_VOLUME = -1;


    // IRT(Initiator Repetition Time) in millisecond as recommended in the standard.
    // Outgoing UCP commands, when in 'Press and Hold' mode, should be this much apart
    // from the adjacent one so as not to place unnecessarily heavy load on the CEC line.
    // TODO: This value might need tweaking per product basis. Consider putting it
    //       in config.xml to allow customization.
    static final int IRT_MS = 300;

    static final String PROPERTY_PREFERRED_ADDRESS_PLAYBACK = "persist.sys.hdmi.addr.playback";
    static final String PROPERTY_PREFERRED_ADDRESS_PLAYBACK = "persist.sys.hdmi.addr.playback";
    static final String PROPERTY_PREFERRED_ADDRESS_TV = "persist.sys.hdmi.addr.tv";
    static final String PROPERTY_PREFERRED_ADDRESS_TV = "persist.sys.hdmi.addr.tv";


+35 −16
Original line number Original line Diff line number Diff line
@@ -15,7 +15,7 @@
 */
 */
package com.android.server.hdmi;
package com.android.server.hdmi;


import static com.android.server.hdmi.Constants.IRT_MS;
import static com.android.server.hdmi.HdmiConfig.IRT_MS;


import android.util.Slog;
import android.util.Slog;
import android.view.KeyEvent;
import android.view.KeyEvent;
@@ -35,6 +35,11 @@ import android.view.KeyEvent;
final class SendKeyAction extends HdmiCecFeatureAction {
final class SendKeyAction extends HdmiCecFeatureAction {
    private static final String TAG = "SendKeyAction";
    private static final String TAG = "SendKeyAction";


    // Amount of time this action waits for a new release key input event. When timed out,
    // the action sends out UCR and finishes its lifecycle. Used to deal with missing key release
    // event, which can lead the device on the receiving end to generating unintended key repeats.
    private static final int AWAIT_RELEASE_KEY_MS = 1000;

    // State in which the action is at work. The state is set in {@link #start()} and
    // State in which the action is at work. The state is set in {@link #start()} and
    // persists throughout the process till it is set back to {@code STATE_NONE} at the end.
    // persists throughout the process till it is set back to {@code STATE_NONE} at the end.
    private static final int STATE_PROCESSING_KEYCODE = 1;
    private static final int STATE_PROCESSING_KEYCODE = 1;
@@ -45,6 +50,10 @@ final class SendKeyAction extends HdmiCecFeatureAction {
    // The key code of the last key press event the action is passed via processKeyEvent.
    // The key code of the last key press event the action is passed via processKeyEvent.
    private int mLastKeycode;
    private int mLastKeycode;


    // The time stamp when the last CEC key command was sent. Used to determine the press-and-hold
    // operation.
    private long mLastSendKeyTime;

    /**
    /**
     * Constructor.
     * Constructor.
     *
     *
@@ -61,6 +70,7 @@ final class SendKeyAction extends HdmiCecFeatureAction {
    @Override
    @Override
    public boolean start() {
    public boolean start() {
        sendKeyDown(mLastKeycode);
        sendKeyDown(mLastKeycode);
        mLastSendKeyTime = getCurrentTime();
        // finish action for non-repeatable key.
        // finish action for non-repeatable key.
        if (!HdmiCecKeycode.isRepeatableKey(mLastKeycode)) {
        if (!HdmiCecKeycode.isRepeatableKey(mLastKeycode)) {
            sendKeyUp();
            sendKeyUp();
@@ -68,10 +78,14 @@ final class SendKeyAction extends HdmiCecFeatureAction {
            return true;
            return true;
        }
        }
        mState = STATE_PROCESSING_KEYCODE;
        mState = STATE_PROCESSING_KEYCODE;
        addTimer(mState, IRT_MS);
        addTimer(mState, AWAIT_RELEASE_KEY_MS);
        return true;
        return true;
    }
    }


    private long getCurrentTime() {
        return System.currentTimeMillis();
    }

    /**
    /**
     * Called when a key event should be handled for the action.
     * Called when a key event should be handled for the action.
     *
     *
@@ -83,24 +97,32 @@ final class SendKeyAction extends HdmiCecFeatureAction {
            Slog.w(TAG, "Not in a valid state");
            Slog.w(TAG, "Not in a valid state");
            return;
            return;
        }
        }
        // A new key press event that comes in with a key code different from the last
        // one sets becomes a new key code to be used for press-and-hold operation.
        // Removes any pending timer and starts a new timer for itself.
        // Key release event indicates that the action shall be finished. Send UCR
        // command and terminate the action. Other release events are ignored.
        if (isPressed) {
        if (isPressed) {
            // A new key press event that comes in with a key code different from the last
            // one becomes a new key code to be used for press-and-hold operation.
            if (keycode != mLastKeycode) {
            if (keycode != mLastKeycode) {
                sendKeyDown(keycode);
                sendKeyDown(keycode);
                mLastSendKeyTime = getCurrentTime();
                if (!HdmiCecKeycode.isRepeatableKey(keycode)) {
                if (!HdmiCecKeycode.isRepeatableKey(keycode)) {
                    sendKeyUp();
                    sendKeyUp();
                    finish();
                    finish();
                    return;
                    return;
                }
                }
            } else {
                // Press-and-hold key transmission takes place if Android key inputs are
                // repeatedly coming in and more than IRT_MS has passed since the last
                // press-and-hold key transmission.
                if (getCurrentTime() - mLastSendKeyTime >= IRT_MS) {
                    sendKeyDown(keycode);
                    mLastSendKeyTime = getCurrentTime();
                }
            }
            mActionTimer.clearTimerMessage();
            mActionTimer.clearTimerMessage();
                addTimer(mState, IRT_MS);
            addTimer(mState, AWAIT_RELEASE_KEY_MS);
            mLastKeycode = keycode;
            mLastKeycode = keycode;
            }
        } else {
        } else {
            // Key release event indicates that the action shall be finished. Send UCR
            // command and terminate the action. Other release events are ignored.
            if (keycode == mLastKeycode) {
            if (keycode == mLastKeycode) {
                sendKeyUp();
                sendKeyUp();
                finish();
                finish();
@@ -130,15 +152,12 @@ final class SendKeyAction extends HdmiCecFeatureAction {


    @Override
    @Override
    public void handleTimerEvent(int state) {
    public void handleTimerEvent(int state) {
        // Timer event occurs every IRT_MS milliseconds to perform key-repeat (or press-and-hold)
        // Timeout on waiting for the release key event. Send UCR and quit the action.
        // operation. If the last received key code is as same as the one with which the action
        // is started, plus there was no key release event in last IRT_MS timeframe, send a UCP
        // command and start another timer to schedule the next press-and-hold command.
        if (mState != STATE_PROCESSING_KEYCODE) {
        if (mState != STATE_PROCESSING_KEYCODE) {
            Slog.w(TAG, "Not in a valid state");
            Slog.w(TAG, "Not in a valid state");
            return;
            return;
        }
        }
        sendKeyDown(mLastKeycode);
        sendKeyUp();
        addTimer(mState, IRT_MS);
        finish();
    }
    }
}
}
+1 −1
Original line number Original line Diff line number Diff line
@@ -16,10 +16,10 @@


package com.android.server.hdmi;
package com.android.server.hdmi;


import static com.android.server.hdmi.Constants.IRT_MS;
import static com.android.server.hdmi.Constants.MESSAGE_FEATURE_ABORT;
import static com.android.server.hdmi.Constants.MESSAGE_FEATURE_ABORT;
import static com.android.server.hdmi.Constants.MESSAGE_REPORT_AUDIO_STATUS;
import static com.android.server.hdmi.Constants.MESSAGE_REPORT_AUDIO_STATUS;
import static com.android.server.hdmi.Constants.MESSAGE_USER_CONTROL_PRESSED;
import static com.android.server.hdmi.Constants.MESSAGE_USER_CONTROL_PRESSED;
import static com.android.server.hdmi.HdmiConfig.IRT_MS;


import android.media.AudioManager;
import android.media.AudioManager;