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

Commit a062a933 authored by Jinsuk Kim's avatar Jinsuk Kim
Browse files

Implement portSelect/sendKeyEvent for HdmiControlService

TIF (TV Input Framework) uses these API to switch inputs, send
keys for selected device on CEC bus. Also renamed getActiveInput
to getActivePortId to use a unified term for port/input.

Change-Id: I8196825c0d960988cc1c0bb58a628ccd8ab1957e
parent df48918c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -185,6 +185,7 @@ public final class HdmiCec {
    public static final int RESULT_TARGET_NOT_AVAILABLE = 3;
    public static final int RESULT_ALREADY_IN_PROGRESS = 4;
    public static final int RESULT_EXCEPTION = 5;
    public static final int RESULT_INCORRECT_MODE = 6;

    private static final int[] ADDRESS_TO_TYPE = {
        DEVICE_TV,  // ADDR_TV
+2 −2
Original line number Diff line number Diff line
@@ -72,9 +72,9 @@ final class ActiveSourceHandler {
        }

        if (!mSource.isInPresetInstallationMode()) {
            int prevActiveInput = mSource.getActiveInput();
            int prevActiveInput = mSource.getActivePortId();
            mSource.updateActiveDevice(deviceLogicalAddress, routingPath);
            if (prevActiveInput != mSource.getActiveInput()) {
            if (prevActiveInput != mSource.getActivePortId()) {
                // TODO: change port input here.
            }
            invokeCallback(HdmiCec.RESULT_SUCCESS);
+16 −3
Original line number Diff line number Diff line
@@ -372,15 +372,28 @@ abstract class HdmiCecLocalDevice {
    }

    /**
     * Returns the ID of the active HDMI port. The active input is the port that has the active
     * routing path connected directly or indirectly under the device hierarchy.
     * Returns the ID of the active HDMI port. The active port is the one that has the active
     * routing path connected to it directly or indirectly under the device hierarchy.
     */
    int getActiveInput() {
    int getActivePortId() {
        synchronized (mLock) {
            return mService.pathToPortId(mActiveRoutingPath);
        }
    }

    /**
     * Update the active port.
     *
     * @param portId the new active port id
     */
    void setActivePortId(int portId) {
        synchronized (mLock) {
            // We update active routing path instead, since we get the active port id from
            // the active routing path.
            mActiveRoutingPath = mService.portIdToPath(portId);
        }
    }

    void updateActiveDevice(int logicalAddress, int physicalAddress) {
        synchronized (mLock) {
            mActiveSource = logicalAddress;
+54 −0
Original line number Diff line number Diff line
@@ -87,6 +87,60 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
        addAndStartAction(new DeviceSelectAction(this, targetDevice, callback));
    }

    /**
     * Performs the action routing control.
     *
     * @param portId new HDMI port to route to
     * @param callback callback object to report the result with
     */
    void portSelect(int portId, IHdmiControlCallback callback) {
        assertRunOnServiceThread();
        if (isInPresetInstallationMode()) {
            invokeCallback(callback, HdmiCec.RESULT_INCORRECT_MODE);
            return;
        }
        // Make sure this call does not stem from <Active Source> message reception, in
        // which case the two ports will be the same.
        if (portId == getActivePortId()) {
            invokeCallback(callback, HdmiCec.RESULT_SUCCESS);
            return;
        }
        setActivePortId(portId);

        // TODO: Return immediately if the operation is triggered by <Text/Image View On>
        // TODO: Handle invalid port id / active input which should be treated as an
        //        internal tuner.

        removeAction(RoutingControlAction.class);

        int oldPath = mService.portIdToPath(mService.portIdToPath(getActivePortId()));
        int newPath = mService.portIdToPath(portId);
        HdmiCecMessage routingChange =
                HdmiCecMessageBuilder.buildRoutingChange(mAddress, oldPath, newPath);
        mService.sendCecCommand(routingChange);
        addAndStartAction(new RoutingControlAction(this, newPath, callback));
    }

    /**
     * Sends key to a target CEC device.
     *
     * @param keyCode key code to send. Defined in {@link KeyEvent}.
     * @param isPressed true if this is keypress event
     */
    void sendKeyEvent(int keyCode, boolean isPressed) {
        assertRunOnServiceThread();
        List<SendKeyAction> action = getActions(SendKeyAction.class);
        if (!action.isEmpty()) {
            action.get(0).processKeyEvent(keyCode, isPressed);
        } else {
            if (isPressed) {
                addAndStartAction(new SendKeyAction(this, getActiveSource(), keyCode));
            } else {
                Slog.w(TAG, "Discard key release event");
            }
        }
    }

    private static void invokeCallback(IHdmiControlCallback callback, int result) {
        try {
            callback.onComplete(result);
+36 −11
Original line number Diff line number Diff line
@@ -507,7 +507,7 @@ public final class HdmiControlService extends SystemService {
                public void run() {
                    HdmiCecLocalDeviceTv tv = tv();
                    if (tv == null) {
                        Slog.w(TAG, "Local playback device not available");
                        Slog.w(TAG, "Local tv device not available");
                        invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
                        return;
                    }
@@ -516,6 +516,41 @@ public final class HdmiControlService extends SystemService {
            });
        }

        @Override
        public void portSelect(final int portId, final IHdmiControlCallback callback) {
            enforceAccessPermission();
            runOnServiceThread(new Runnable() {
                @Override
                public void run() {
                    HdmiCecLocalDeviceTv tv = tv();
                    if (tv == null) {
                        Slog.w(TAG, "Local tv device not available");
                        invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE);
                        return;
                    }
                    tv.portSelect(portId, callback);
                }
            });
        }

        @Override
        public void sendKeyEvent(final int keyCode, final boolean isPressed) {
            enforceAccessPermission();
            runOnServiceThread(new Runnable() {
                @Override
                public void run() {
                    // TODO: sendKeyEvent is for TV device only for now. Allow other
                    //       local devices of different types to use this as well.
                    HdmiCecLocalDeviceTv tv = tv();
                    if (tv == null) {
                        Slog.w(TAG, "Local tv device not available");
                        return;
                    }
                    tv.sendKeyEvent(keyCode, isPressed);
                }
            });
        }

        @Override
        public void oneTouchPlay(final IHdmiControlCallback callback) {
            enforceAccessPermission();
@@ -571,16 +606,6 @@ public final class HdmiControlService extends SystemService {
            });
        }

        @Override
        public void portSelect(int portId, IHdmiControlCallback callback) {
            // TODO: Implement this
        }

        @Override
        public void sendKeyEvent(int keyCode, boolean isPressed) {
            // TODO: Implement this
        }

        @Override
        public List<HdmiPortInfo> getPortInfo() {
            enforceAccessPermission();
Loading