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

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

Merge "Refactor handling sequences in HdmiControlService"

parents 177d078d 92b77cf9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -48,4 +48,5 @@ interface IHdmiControlService {
    void setSystemAudioMode(boolean enabled, IHdmiControlCallback callback);
    void addSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
    void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
    void setControlEnabled(boolean enabled);
}
+1 −3
Original line number Diff line number Diff line
@@ -67,9 +67,7 @@ final class ActiveSourceHandler {
        }
        HdmiCecDeviceInfo device = mService.getDeviceInfo(activeAddress);
        if (device == null) {
            // "New device action" initiated by <Active Source> does not require
            // "Routing change action".
            tv.addAndStartAction(new NewDeviceAction(tv, activeAddress, activePath, false));
            tv.addAndStartAction(new NewDeviceAction(tv, activeAddress, activePath));
        }

        int currentActive = tv.getActiveSource();
+6 −35
Original line number Diff line number Diff line
@@ -143,6 +143,8 @@ abstract class HdmiCecLocalDevice {
                return handleGetCecVersion(message);
            case HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS:
                return handleReportPhysicalAddress(message);
            case HdmiCec.MESSAGE_ROUTING_CHANGE:
                return handleRoutingChange(message);
            case HdmiCec.MESSAGE_INITIATE_ARC:
                return handleInitiateArc(message);
            case HdmiCec.MESSAGE_TERMINATE_ARC:
@@ -245,6 +247,10 @@ abstract class HdmiCecLocalDevice {
        return false;
    }

    protected boolean handleRoutingChange(HdmiCecMessage message) {
        return false;
    }

    protected boolean handleReportPhysicalAddress(HdmiCecMessage message) {
        return false;
    }
@@ -471,41 +477,6 @@ abstract class HdmiCecLocalDevice {
        }
    }

    boolean isHdmiControlEnabled() {
        synchronized (mLock) {
            return !mInputChangeEnabled;
        }
    }

    /**
     * Whether the given path is located in the tail of current active path.
     *
     * @param path to be tested
     * @return true if the given path is located in the tail of current active path; otherwise,
     *         false
     */
    // TODO: move this to local device tv.
    boolean isTailOfActivePath(int path) {
        synchronized (mLock) {
            // If active routing path is internal source, return false.
            if (mActiveRoutingPath == 0) {
                return false;
            }
            for (int i = 12; i >= 0; i -= 4) {
                int curActivePath = (mActiveRoutingPath >> i) & 0xF;
                if (curActivePath == 0) {
                    return true;
                } else {
                    int curPath = (path >> i) & 0xF;
                    if (curPath != curActivePath) {
                        return false;
                    }
                }
            }
            return false;
        }
    }

    @ServiceThreadOnly
    HdmiCecMessageCache getCecMessageCache() {
        assertRunOnServiceThread();
+110 −18
Original line number Diff line number Diff line
@@ -121,7 +121,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
    private void handleSelectInternalSource(IHdmiControlCallback callback) {
        assertRunOnServiceThread();
        // Seq #18
        if (isHdmiControlEnabled() && getActiveSource() != mAddress) {
        if (mService.isControlEnabled() && getActiveSource() != mAddress) {
            updateActiveSource(mAddress, mService.getPhysicalAddress());
            // TODO: Check if this comes from <Text/Image View On> - if true, do nothing.
            HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource(
@@ -185,7 +185,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
    void doManualPortSwitching(int portId, IHdmiControlCallback callback) {
        assertRunOnServiceThread();
        // Seq #20
        if (!isHdmiControlEnabled() || portId == getActivePortId()) {
        if (!mService.isControlEnabled() || portId == getActivePortId()) {
            invokeCallback(callback, HdmiCec.RESULT_INCORRECT_MODE);
            return;
        }
@@ -243,8 +243,13 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
    @ServiceThreadOnly
    protected boolean handleActiveSource(HdmiCecMessage message) {
        assertRunOnServiceThread();
        int activePath = HdmiUtils.twoBytesToInt(message.getParams());
        ActiveSourceHandler.create(this, null).process(message.getSource(), activePath);
        int address = message.getSource();
        int path = HdmiUtils.twoBytesToInt(message.getParams());
        if (getDeviceInfo(address) == null) {
            handleNewDeviceAtTheTailOfActivePath(address, path);
        } else {
            ActiveSourceHandler.create(this, null).process(address, path);
        }
        return true;
    }

@@ -286,10 +291,9 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
    protected boolean handleRequestActiveSource(HdmiCecMessage message) {
        assertRunOnServiceThread();
        // Seq #19
        int address = getDeviceInfo().getLogicalAddress();
        if (address == getActiveSource()) {
        if (mAddress == getActiveSource()) {
            mService.sendCecCommand(
                    HdmiCecMessageBuilder.buildActiveSource(address, getActivePath()));
                    HdmiCecMessageBuilder.buildActiveSource(mAddress, getActivePath()));
        }
        return true;
    }
@@ -320,15 +324,70 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
            return true;
        }

        int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
        int logicalAddress = message.getSource();
        int path = HdmiUtils.twoBytesToInt(message.getParams());
        int address = message.getSource();
        if (!isInDeviceList(path, address)) {
            handleNewDeviceAtTheTailOfActivePath(address, path);
        }
        addAndStartAction(new NewDeviceAction(this, address, path));
        return true;
    }

    private void handleNewDeviceAtTheTailOfActivePath(int address, int path) {
        // Seq #22
        if (isTailOfActivePath(path, getActivePath())) {
            removeAction(RoutingControlAction.class);
            int newPath = mService.portIdToPath(getActivePortId());
            mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingChange(
                    mAddress, getActivePath(), newPath));
            addAndStartAction(new RoutingControlAction(this, getActivePortId(), null));
        }
    }

        // If it is a new device and connected to the tail of active path,
        // it's required to change routing path.
        boolean requireRoutingChange = !isInDeviceList(physicalAddress, logicalAddress)
                && isTailOfActivePath(physicalAddress);
        addAndStartAction(new NewDeviceAction(this, message.getSource(), physicalAddress,
                requireRoutingChange));
    /**
     * Whether the given path is located in the tail of current active path.
     *
     * @param path to be tested
     * @param activePath current active path
     * @return true if the given path is located in the tail of current active path; otherwise,
     *         false
     */
    static boolean isTailOfActivePath(int path, int activePath) {
        // If active routing path is internal source, return false.
        if (activePath == 0) {
            return false;
        }
        for (int i = 12; i >= 0; i -= 4) {
            int curActivePath = (activePath >> i) & 0xF;
            if (curActivePath == 0) {
                return true;
            } else {
                int curPath = (path >> i) & 0xF;
                if (curPath != curActivePath) {
                    return false;
                }
            }
        }
        return false;
    }

    @Override
    @ServiceThreadOnly
    protected boolean handleRoutingChange(HdmiCecMessage message) {
        assertRunOnServiceThread();
        // Seq #21
        byte[] params = message.getParams();
        if (params.length != 4) {
            Slog.w(TAG, "Wrong parameter: " + message);
            return true;
        }
        int currentPath = HdmiUtils.twoBytesToInt(params);
        if (HdmiUtils.isAffectingActiveRoutingPath(getActivePath(), currentPath)) {
            int newPath = HdmiUtils.twoBytesToInt(params, 2);
            setActivePath(newPath);
            removeAction(RoutingControlAction.class);
            addAndStartAction(new RoutingControlAction(this, newPath, null));
        }
        return true;
    }

@@ -776,10 +835,43 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
    final void removeCecDevice(int address) {
        assertRunOnServiceThread();
        HdmiCecDeviceInfo info = removeDeviceInfo(address);
        handleRemoveActiveRoutingPath(info.getPhysicalAddress());
        mCecMessageCache.flushMessagesFrom(address);
        mService.invokeDeviceEventListeners(info, false);
    }

    private void handleRemoveActiveRoutingPath(int path) {
        // Seq #23
        if (isTailOfActivePath(path, getActivePath())) {
            removeAction(RoutingControlAction.class);
            int newPath = mService.portIdToPath(getActivePortId());
            mService.sendCecCommand(HdmiCecMessageBuilder.buildRoutingChange(
                    mAddress, getActivePath(), newPath));
            addAndStartAction(new RoutingControlAction(this, getActivePortId(), null));
        }
    }

    @ServiceThreadOnly
    void routingAtEnableTime() {
        assertRunOnServiceThread();
        // Seq #24
        if (getActivePortId() != HdmiConstants.INVALID_PORT_ID) {
            // TODO: Check if TV was not powered on due to <Text/Image View On>,
            //       TV is not in Preset Installation mode, not in initial setup mode, not
            //       in Software updating mode, not in service mode, for following actions.
            removeAction(RoutingControlAction.class);
            int newPath = mService.portIdToPath(getActivePortId());
            mService.sendCecCommand(
                    HdmiCecMessageBuilder.buildRoutingChange(mAddress, getActivePath(), newPath));
            addAndStartAction(new RoutingControlAction(this, getActivePortId(), null));
        } else {
            int activePath = mService.getPhysicalAddress();
            setActivePath(activePath);
            // TODO: Do following only when TV was not powered on due to <Text/Image View On>.
            mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(mAddress, activePath));
        }
    }

    /**
     * Returns the {@link HdmiCecDeviceInfo} instance whose physical address matches
     * the given routing path. CEC devices use routing path for its physical address to
@@ -804,12 +896,12 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
     * in a device info list. However, both are minimal condition and it could
     * be different device from the original one.
     *
     * @param physicalAddress physical address of a device to be searched
     * @param logicalAddress logical address of a device to be searched
     * @param physicalAddress physical address of a device to be searched
     * @return true if exist; otherwise false
     */
    @ServiceThreadOnly
    boolean isInDeviceList(int physicalAddress, int logicalAddress) {
    boolean isInDeviceList(int logicalAddress, int physicalAddress) {
        assertRunOnServiceThread();
        HdmiCecDeviceInfo device = getDeviceInfo(logicalAddress);
        if (device == null) {
@@ -820,7 +912,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {

    @Override
    @ServiceThreadOnly
    void onHotplug(int portNo, boolean connected) {
    void onHotplug(int portId, boolean connected) {
        assertRunOnServiceThread();

        // Tv device will have permanent HotplugDetectionAction.
+35 −0
Original line number Diff line number Diff line
@@ -116,6 +116,11 @@ public final class HdmiControlService extends SystemService {
    private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords =
            new ArrayList<>();

    // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol
    // handling will be disabled and no request will be handled.
    @GuardedBy("mLock")
    private boolean mHdmiControlEnabled;

    // List of listeners registered by callers that want to get notified of
    // system audio mode changes.
    private final ArrayList<IHdmiSystemAudioModeChangeListener>
@@ -163,6 +168,7 @@ public final class HdmiControlService extends SystemService {

        // TODO: Read the preference for SystemAudioMode and initialize mSystemAudioMode and
        // start to monitor the preference value and invoke SystemAudioActionFromTv if needed.
        mHdmiControlEnabled = true;
    }

    @ServiceThreadOnly
@@ -716,6 +722,29 @@ public final class HdmiControlService extends SystemService {
            enforceAccessPermission();
            HdmiControlService.this.removeSystemAudioModeChangeListener(listener);
        }

        @Override
        public void setControlEnabled(boolean enabled) {
            enforceAccessPermission();
            synchronized (mLock) {
                mHdmiControlEnabled = enabled;
            }
            // TODO: Stop the running actions when disabled, and start
            //       address allocation/device discovery when enabled.
            if (!enabled) {
                return;
            }
            runOnServiceThread(new Runnable() {
                @Override
                public void run() {
                    HdmiCecLocalDeviceTv tv = tv();
                    if (tv == null) {
                        return;
                    }
                    tv.routingAtEnableTime();
                }
            });
        }
    }

    @ServiceThreadOnly
@@ -875,4 +904,10 @@ public final class HdmiControlService extends SystemService {
    AudioManager getAudioManager() {
        return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
    }

    boolean isControlEnabled() {
        synchronized (mLock) {
            return mHdmiControlEnabled;
        }
    }
}
Loading