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

Commit 3d08555e authored by Jinsuk Kim's avatar Jinsuk Kim Committed by Android (Google) Code Review
Browse files

Merge "Give clear distinction between active source/active routing path" into lmp-dev

parents 5eeb59cc 72b7d738
Loading
Loading
Loading
Loading
+21 −18
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import android.hardware.hdmi.HdmiControlManager;
import android.os.RemoteException;
import android.util.Slog;

import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;

/**
 * Handles CEC command <Active Source>.
 * <p>
@@ -54,44 +56,45 @@ final class ActiveSourceHandler {
    /**
     * Handles the incoming active source command.
     *
     * @param activeAddress logical address of the device to be the active source
     * @param activePath routing path of the device to be the active source
     * @param newActive new active source information
     */
    void process(int activeAddress, int activePath) {
    void process(ActiveSource newActive) {
        // Seq #17
        HdmiCecLocalDeviceTv tv = mSource;
        if (getSourcePath() == activePath && tv.getActiveSource() == getSourceAddress()) {
        ActiveSource activeSource = tv.getActiveSource();
        if (activeSource.equals(newActive)) {
            invokeCallback(HdmiControlManager.RESULT_SUCCESS);
            return;
        }
        HdmiCecDeviceInfo device = mService.getDeviceInfo(activeAddress);
        HdmiCecDeviceInfo device = mService.getDeviceInfo(newActive.logicalAddress);
        if (device == null) {
            tv.startNewDeviceAction(activeAddress, activePath);
            tv.startNewDeviceAction(newActive);
        }

        int currentActive = tv.getActiveSource();
        int currentPath = tv.getActivePath();
        ActiveSource current = tv.getActiveSource();
        if (!tv.isProhibitMode()) {
            tv.updateActiveSource(activeAddress, activePath);
            if (currentActive != activeAddress && currentPath != activePath) {
                tv.updateActivePortId(mService.pathToPortId(activePath));
            tv.updateActiveSource(newActive);
            if (!current.equals(newActive)) {
                boolean notifyInputChange = (mCallback == null);
                tv.updateActiveInput(newActive.physicalAddress, notifyInputChange);
            }
            invokeCallback(HdmiControlManager.RESULT_SUCCESS);
        } else {
            // TV is in a mode that should keep its current source/input from
            // being changed for its operation. Reclaim the active source
            // or switch the port back to the one used for the current mode.
            if (currentActive == getSourceAddress()) {
                HdmiCecMessage activeSource =
                        HdmiCecMessageBuilder.buildActiveSource(currentActive, currentPath);
                mService.sendCecCommand(activeSource);
                tv.updateActiveSource(currentActive, currentPath);
            if (current.logicalAddress == getSourceAddress()) {
                HdmiCecMessage activeSourceCommand = HdmiCecMessageBuilder.buildActiveSource(
                        current.logicalAddress, current.physicalAddress);
                mService.sendCecCommand(activeSourceCommand);
                tv.updateActiveSource(current);
                invokeCallback(HdmiControlManager.RESULT_SUCCESS);
            } else {
                HdmiCecMessage routingChange = HdmiCecMessageBuilder.buildRoutingChange(
                        getSourceAddress(), activePath, currentPath);
                        getSourceAddress(), newActive.physicalAddress, current.physicalAddress);
                mService.sendCecCommand(routingChange);
                tv.addAndStartAction(new RoutingControlAction(tv, currentPath, true, mCallback));
                tv.addAndStartAction(
                        new RoutingControlAction(tv, current.physicalAddress, true, mCallback));
            }
        }
    }
+3 −2
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.hardware.hdmi.IHdmiControlCallback;
import android.os.RemoteException;
import android.util.Slog;

import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;

/**
@@ -130,10 +131,10 @@ final class DeviceSelectAction extends FeatureAction {
                return false;
            case STATE_WAIT_FOR_ACTIVE_SOURCE:
                if (opcode == Constants.MESSAGE_ACTIVE_SOURCE) {
                    int activePath = HdmiUtils.twoBytesToInt(params);
                    int physicalAddress = HdmiUtils.twoBytesToInt(params);
                    ActiveSourceHandler
                            .create((HdmiCecLocalDeviceTv) localDevice(), mCallback)
                            .process(cmd.getSource(), activePath);
                            .process(ActiveSource.of(cmd.getSource(), physicalAddress));
                    finish();
                    return true;
                }
+45 −11
Original line number Diff line number Diff line
@@ -49,9 +49,41 @@ abstract class HdmiCecLocalDevice {
    protected int mPreferredAddress;
    protected HdmiCecDeviceInfo mDeviceInfo;

    static class ActiveSource {
        int logicalAddress;
        int physicalAddress;

        public ActiveSource(int logical, int physical) {
            logicalAddress = logical;
            physicalAddress = physical;
        }
        public static ActiveSource of(int logical, int physical) {
            return new ActiveSource(logical, physical);
        }
        public boolean isValid() {
            return HdmiUtils.isValidAddress(logicalAddress);
        }
        public boolean equals(int logical, int physical) {
            return logicalAddress == logical && physicalAddress == physical;
        }
        @Override
        public boolean equals(Object obj) {
            if (obj instanceof ActiveSource) {
                ActiveSource that = (ActiveSource) obj;
                return that.logicalAddress == logicalAddress &&
                       that.physicalAddress == physicalAddress;
            }
            return false;
        }
        @Override
        public int hashCode() {
            return logicalAddress * 29 + physicalAddress;
        }
    }
    // Logical address of the active source.
    @GuardedBy("mLock")
    private int mActiveSource;
    protected final ActiveSource mActiveSource =
            new ActiveSource(-1, Constants.INVALID_PHYSICAL_ADDRESS);

    // Active routing path. Physical address of the active source but not all the time, such as
    // when the new active source does not claim itself to be one. Note that we don't keep
@@ -549,15 +581,24 @@ abstract class HdmiCecLocalDevice {
        return mService.isConnectedToArcPort(path);
    }

    int getActiveSource() {
    ActiveSource getActiveSource() {
        synchronized (mLock) {
            return mActiveSource;
        }
    }

    void setActiveSource(int source) {
    void setActiveSource(ActiveSource newActive) {
        setActiveSource(newActive.logicalAddress, newActive.physicalAddress);
    }

    void setActiveSource(HdmiCecDeviceInfo info) {
        setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress());
    }

    void setActiveSource(int logicalAddress, int physicalAddress) {
        synchronized (mLock) {
            mActiveSource = source;
            mActiveSource.logicalAddress = logicalAddress;
            mActiveSource.physicalAddress = physicalAddress;
        }
    }

@@ -596,13 +637,6 @@ abstract class HdmiCecLocalDevice {
        }
    }

    void updateActiveDevice(int logicalAddress, int physicalAddress) {
        synchronized (mLock) {
            mActiveSource = logicalAddress;
            mActiveRoutingPath = physicalAddress;
        }
    }

    @ServiceThreadOnly
    HdmiCecMessageCache getCecMessageCache() {
        assertRunOnServiceThread();
+56 −36
Original line number Diff line number Diff line
@@ -147,12 +147,15 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
        if (targetAddress == Constants.ADDR_INTERNAL) {
            handleSelectInternalSource();
            // Switching to internal source is always successful even when CEC control is disabled.
            setActiveSource(targetAddress);
            setActiveSource(targetAddress, mService.getPhysicalAddress());
            invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
            return;
        }
        if (!mService.isControlEnabled()) {
            setActiveSource(targetAddress);
            HdmiCecDeviceInfo info = getDeviceInfo(targetAddress);
            if (info != null) {
                setActiveSource(info);
            }
            invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
            return;
        }
@@ -169,7 +172,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
    private void handleSelectInternalSource() {
        assertRunOnServiceThread();
        // Seq #18
        if (mService.isControlEnabled() && getActiveSource() != mAddress) {
        if (mService.isControlEnabled() && mActiveSource.logicalAddress != mAddress) {
            updateActiveSource(mAddress, mService.getPhysicalAddress());
            // TODO: Check if this comes from <Text/Image View On> - if true, do nothing.
            HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
@@ -179,16 +182,22 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
    }

    @ServiceThreadOnly
    void updateActiveSource(int activeSource, int activePath) {
    void updateActiveSource(int logicalAddress, int physicalAddress) {
        assertRunOnServiceThread();
        updateActiveSource(ActiveSource.of(logicalAddress, physicalAddress));
    }

    @ServiceThreadOnly
    void updateActiveSource(ActiveSource newActive) {
        assertRunOnServiceThread();
        // Seq #14
        if (activeSource == getActiveSource() && activePath == getActivePath()) {
        if (mActiveSource.equals(newActive)) {
            return;
        }
        setActiveSource(activeSource);
        setActivePath(activePath);
        if (getDeviceInfo(activeSource) != null && activeSource != mAddress) {
            if (mService.pathToPortId(activePath) == getActivePortId()) {
        setActiveSource(newActive);
        int logicalAddress = newActive.logicalAddress;
        if (getDeviceInfo(logicalAddress) != null && logicalAddress != mAddress) {
            if (mService.pathToPortId(newActive.physicalAddress) == getActivePortId()) {
                setPrevPortId(getActivePortId());
            }
            // TODO: Show the OSD banner related to the new active source device.
@@ -222,16 +231,26 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
    }

    @ServiceThreadOnly
    void updateActivePortId(int portId) {
    void updateActiveInput(int path, boolean notifyInputChange) {
        assertRunOnServiceThread();
        // Seq #15
        int portId = mService.pathToPortId(path);
        if (portId == getActivePortId()) {
            return;
        }
        setActivePath(path);
        setPrevPortId(portId);
        // TODO: Actually switch the physical port here. Handle PAP/PIP as well.
        // TODO: Handle PAP/PIP case.
        // Show OSD port change banner
        mService.invokeInputChangeListener(getActiveSource());
        if (notifyInputChange) {
            ActiveSource activeSource = getActiveSource();
            HdmiCecDeviceInfo info = getDeviceInfo(activeSource.logicalAddress);
            if (info == null) {
                info = new HdmiCecDeviceInfo(Constants.ADDR_INVALID, path, portId,
                        HdmiCecDeviceInfo.DEVICE_RESERVED, 0, null);
            }
            mService.invokeInputChangeListener(info);
        }
    }

    @ServiceThreadOnly
@@ -242,26 +261,25 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
            invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
            return;
        }
        if (!mService.isControlEnabled()) {
            setActivePortId(portId);
            invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
            return;
        }
        if (portId == getActivePortId()) {
            invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
            return;
        }
        setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS);
        if (!mService.isControlEnabled()) {
            setActivePortId(portId);
            invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
            return;
        }
        // TODO: Return immediately if the operation is triggered by <Text/Image View On>
        // and this is the first notification about the active input after power-on
        // (switch to HDMI didn't happen so far but is expected to happen soon).
        removeAction(RoutingControlAction.class);

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

@@ -284,7 +302,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
            action.get(0).processKeyEvent(keyCode, isPressed);
        } else {
            if (isPressed) {
                addAndStartAction(new SendKeyAction(this, getActiveSource(), keyCode));
                int logicalAddress = getActiveSource().logicalAddress;
                addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode));
            } else {
                Slog.w(TAG, "Discard key release event");
            }
@@ -306,12 +325,13 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
    @ServiceThreadOnly
    protected boolean handleActiveSource(HdmiCecMessage message) {
        assertRunOnServiceThread();
        int address = message.getSource();
        int path = HdmiUtils.twoBytesToInt(message.getParams());
        if (getDeviceInfo(address) == null) {
            handleNewDeviceAtTheTailOfActivePath(path);
        int logicalAddress = message.getSource();
        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
        if (getDeviceInfo(logicalAddress) == null) {
            handleNewDeviceAtTheTailOfActivePath(physicalAddress);
        } else {
            ActiveSourceHandler.create(this, null).process(address, path);
            ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
            ActiveSourceHandler.create(this, null).process(activeSource);
        }
        return true;
    }
@@ -323,7 +343,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
        // Seq #10

        // Ignore <Inactive Source> from non-active source device.
        if (getActiveSource() != message.getSource()) {
        if (getActiveSource().logicalAddress != message.getSource()) {
            return true;
        }
        if (isProhibitMode()) {
@@ -342,7 +362,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
            }
            // TODO: Switch the TV freeze mode off

            setActivePortId(portId);
            doManualPortSwitching(portId, null);
            setPrevPortId(Constants.INVALID_PORT_ID);
        }
@@ -354,7 +373,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
    protected boolean handleRequestActiveSource(HdmiCecMessage message) {
        assertRunOnServiceThread();
        // Seq #19
        if (mAddress == getActiveSource()) {
        if (mAddress == getActiveSource().logicalAddress) {
            mService.sendCecCommand(
                    HdmiCecMessageBuilder.buildActiveSource(mAddress, getActivePath()));
        }
@@ -392,11 +411,11 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
        if (!isInDeviceList(path, address)) {
            handleNewDeviceAtTheTailOfActivePath(path);
        }
        startNewDeviceAction(address, path);
        startNewDeviceAction(ActiveSource.of(address, path));
        return true;
    }

    void startNewDeviceAction(int address, int path) {
    void startNewDeviceAction(ActiveSource activeSource) {
        for (NewDeviceAction action : getActions(NewDeviceAction.class)) {
            // If there is new device action which has the same logical address and path
            // ignore new request.
@@ -406,12 +425,13 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
            // in. However, TV can detect a new device from HotPlugDetectionAction,
            // which sends <Give Physical Address> to the source for newly detected
            // device.
            if (action.isActionOf(address, path)) {
            if (action.isActionOf(activeSource)) {
                return;
            }
        }

        addAndStartAction(new NewDeviceAction(this, address, path));
        addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress,
                activeSource.physicalAddress));
    }

    private void handleNewDeviceAtTheTailOfActivePath(int path) {
+10 −3
Original line number Diff line number Diff line
@@ -724,6 +724,10 @@ public final class HdmiControlService extends SystemService {
            runOnServiceThread(new Runnable() {
                @Override
                public void run() {
                    if (callback == null) {
                        Slog.e(TAG, "Callback cannot be null");
                        return;
                    }
                    HdmiCecLocalDeviceTv tv = tv();
                    if (tv == null) {
                        Slog.w(TAG, "Local tv device not available");
@@ -741,6 +745,10 @@ public final class HdmiControlService extends SystemService {
            runOnServiceThread(new Runnable() {
                @Override
                public void run() {
                    if (callback == null) {
                        Slog.e(TAG, "Callback cannot be null");
                        return;
                    }
                    HdmiCecLocalDeviceTv tv = tv();
                    if (tv == null) {
                        Slog.w(TAG, "Local tv device not available");
@@ -1218,12 +1226,11 @@ public final class HdmiControlService extends SystemService {
        }
    }

    void invokeInputChangeListener(int activeAddress) {
    void invokeInputChangeListener(HdmiCecDeviceInfo info) {
        synchronized (mLock) {
            if (mInputChangeListener != null) {
                HdmiCecDeviceInfo activeSource = getDeviceInfo(activeAddress);
                try {
                    mInputChangeListener.onChanged(activeSource);
                    mInputChangeListener.onChanged(info);
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e);
                }
Loading