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

Commit c2f2977c authored by Shubang Lu's avatar Shubang Lu Committed by Android (Google) Code Review
Browse files

Merge changes Idebffbec,Ief4435c7,I9f9a5f46,Iee495e71,I949587e1, ...

* changes:
  Add Power Status query steps in Device Discovery Action.
  Unmute when turning system audio mode on.
  Make sure the device route to HOME when OneTouchPlay is triggered.
  Add APIs to expose some cec control to other services.
  Fix port id mismatch temporarily.
  Add dump info of local active port and routing port.
  Set routing feature enabled to default false and dump its status.
  Add a thread safe copy of connected device list.
parents be607448 47fe0b16
Loading
Loading
Loading
Loading
+68 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.Log;

import java.util.List;

/**
 * The {@link HdmiControlManager} class is used to send HDMI control messages
 * to attached CEC devices.
@@ -403,6 +405,72 @@ public final class HdmiControlManager {
        return (HdmiSwitchClient) getClient(HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH);
    }

    /**
     * Get a snapshot of the real-time status of the remote devices.
     *
     * @return a list of {@link HdmiDeviceInfo} of the devices connected to the current device.
     *
     * TODO(b/110094868): unhide for Q
     * @hide
     */
    public List<HdmiDeviceInfo> getConnectedDevicesList() {
        try {
            return mService.getDeviceList();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Power off the target device.
     *
     * @param deviceInfo HdmiDeviceInfo of the device to be powered off
     *
     * TODO(b/110094868): unhide for Q
     * @hide
     */
    public void powerOffRemoteDevice(HdmiDeviceInfo deviceInfo) {
        try {
            mService.powerOffRemoteDevice(
                    deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Power on the target device.
     *
     * @param deviceInfo HdmiDeviceInfo of the device to be powered on
     *
     * TODO(b/110094868): unhide for Q
     * @hide
     */
    public void powerOnRemoteDevice(HdmiDeviceInfo deviceInfo) {
        try {
            mService.powerOnRemoteDevice(
                    deviceInfo.getLogicalAddress(), deviceInfo.getDevicePowerStatus());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Ask the target device to be the new Active Source.
     *
     * @param deviceInfo HdmiDeviceInfo of the target device
     *
     * TODO(b/110094868): unhide for Q
     * @hide
     */
    public void askRemoteDeviceToBecomeActiveSource(HdmiDeviceInfo deviceInfo) {
        try {
            mService.askRemoteDeviceToBecomeActiveSource(deviceInfo.getPhysicalAddress());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Controls standby mode of the system. It will also try to turn on/off the connected devices if
     * necessary.
+3 −0
Original line number Diff line number Diff line
@@ -61,6 +61,9 @@ interface IHdmiControlService {
    void setInputChangeListener(IHdmiInputChangeListener listener);
    List<HdmiDeviceInfo> getInputDevices();
    List<HdmiDeviceInfo> getDeviceList();
    void powerOffRemoteDevice(int logicalAddress, int powerStatus);
    void powerOnRemoteDevice(int logicalAddress, int powerStatus);
    void askRemoteDeviceToBecomeActiveSource(int physicalAddress);
    void sendVendorCommand(int deviceType, int targetAddress, in byte[] params,
            boolean hasVendorId);
    void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType);
+12 −0
Original line number Diff line number Diff line
@@ -327,6 +327,18 @@ public class HdmiAudioSystemClientTest {
        public int getPhysicalAddress() {
            return 0x0000;
        }

        @Override
        public void powerOffRemoteDevice(int logicalAddress, int powerStatus) {
        }

        @Override
        public void powerOnRemoteDevice(int logicalAddress, int powerStatus) {
        }

        @Override
        public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) {
        }
    }

}
+70 −3
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.hdmi;

import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.util.Slog;

@@ -51,8 +52,10 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
    private static final int STATE_WAITING_FOR_OSD_NAME = 3;
    // State in which the action is waiting for gathering vendor id of non-local devices.
    private static final int STATE_WAITING_FOR_VENDOR_ID = 4;
    // State in which the action is waiting for devices to be ready
    // State in which the action is waiting for devices to be ready.
    private static final int STATE_WAITING_FOR_DEVICES = 5;
    // State in which the action is waiting for gathering power status of non-local devices.
    private static final int STATE_WAITING_FOR_POWER = 6;

    /**
     * Interface used to report result of device discovery.
@@ -74,6 +77,7 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
        private int mPhysicalAddress = Constants.INVALID_PHYSICAL_ADDRESS;
        private int mPortId = Constants.INVALID_PORT_ID;
        private int mVendorId = Constants.UNKNOWN_VENDOR_ID;
        private int mPowerStatus = HdmiControlManager.POWER_STATUS_UNKNOWN;
        private String mDisplayName = "";
        private int mDeviceType = HdmiDeviceInfo.DEVICE_INACTIVE;

@@ -83,7 +87,7 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {

        private HdmiDeviceInfo toHdmiDeviceInfo() {
            return new HdmiDeviceInfo(mLogicalAddress, mPhysicalAddress, mPortId, mDeviceType,
                    mVendorId, mDisplayName);
                    mVendorId, mDisplayName, mPowerStatus);
        }
    }

@@ -237,6 +241,29 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
        addTimer(mState, HdmiConfig.TIMEOUT_MS);
    }

    private void startPowerStatusStage() {
        Slog.v(TAG, "Start [Power Status Stage]:" + mDevices.size());
        mProcessedDeviceCount = 0;
        mState = STATE_WAITING_FOR_POWER;

        checkAndProceedStage();
    }

    private void queryPowerStatus(int address) {
        if (!verifyValidLogicalAddress(address)) {
            checkAndProceedStage();
            return;
        }

        mActionTimer.clearTimerMessage();

        if (mayProcessMessageIfCached(address, Constants.MESSAGE_REPORT_POWER_STATUS)) {
            return;
        }
        sendCommand(HdmiCecMessageBuilder.buildGiveDevicePowerStatus(getSourceAddress(), address));
        addTimer(mState, HdmiConfig.TIMEOUT_MS);
    }

    private boolean mayProcessMessageIfCached(int address, int opcode) {
        HdmiCecMessage message = getCecMessageCache().getMessage(address, opcode);
        if (message != null) {
@@ -275,6 +302,16 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
                    return true;
                }
                return false;
            case STATE_WAITING_FOR_POWER:
                if (cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) {
                    handleReportPowerStatus(cmd);
                    return true;
                } else if ((cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT)
                        && ((cmd.getParams()[0] & 0xFF) == Constants.MESSAGE_REPORT_POWER_STATUS)) {
                    handleReportPowerStatus(cmd);
                    return true;
                }
                return false;
            case STATE_WAITING_FOR_DEVICE_POLLING:
                // Fall through.
            default:
@@ -359,6 +396,26 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
        checkAndProceedStage();
    }

    private void handleReportPowerStatus(HdmiCecMessage cmd) {
        Preconditions.checkState(mProcessedDeviceCount < mDevices.size());

        DeviceInfo current = mDevices.get(mProcessedDeviceCount);
        if (current.mLogicalAddress != cmd.getSource()) {
            Slog.w(TAG, "Unmatched address[expected:" + current.mLogicalAddress + ", actual:"
                    + cmd.getSource());
            return;
        }

        if (cmd.getOpcode() != Constants.MESSAGE_FEATURE_ABORT) {
            byte[] params = cmd.getParams();
            int powerStatus = params[0] & 0xFF;
            current.mPowerStatus = powerStatus;
        }

        increaseProcessedDeviceCount();
        checkAndProceedStage();
    }

    private void increaseProcessedDeviceCount() {
        mProcessedDeviceCount++;
        mTimeoutRetry = 0;
@@ -402,6 +459,9 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
                    startVendorIdStage();
                    return;
                case STATE_WAITING_FOR_VENDOR_ID:
                    startPowerStatusStage();
                    return;
                case STATE_WAITING_FOR_POWER:
                    wrapUpAndFinish();
                    return;
                default:
@@ -427,6 +487,9 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
            case STATE_WAITING_FOR_VENDOR_ID:
                queryVendorId(address);
                return;
            case STATE_WAITING_FOR_POWER:
                queryPowerStatus(address);
                return;
            default:
                return;
        }
@@ -448,7 +511,11 @@ final class DeviceDiscoveryAction extends HdmiCecFeatureAction {
        }
        mTimeoutRetry = 0;
        Slog.v(TAG, "Timeout[State=" + mState + ", Processed=" + mProcessedDeviceCount);
        if (mState != STATE_WAITING_FOR_POWER) {
            removeDevice(mProcessedDeviceCount);
        } else {
            increaseProcessedDeviceCount();
        }
        checkAndProceedStage();
    }
}
+53 −21
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
@@ -84,6 +85,10 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
    // processing.
    private final HashMap<Integer, String> mTvInputs = new HashMap<>();

    // Copy of mDeviceInfos to guarantee thread-safety.
    @GuardedBy("mLock")
    private List<HdmiDeviceInfo> mSafeAllDeviceInfos = Collections.emptyList();

    // Map-like container of all cec devices.
    // device id is used as key of container.
    private final SparseArray<HdmiDeviceInfo> mDeviceInfos = new SparseArray<>();
@@ -91,16 +96,13 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
    protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) {
        super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
        mRoutingControlFeatureEnabled =
            mService.readBooleanSetting(Global.HDMI_CEC_SWITCH_ENABLED, true);
            mService.readBooleanSetting(Global.HDMI_CEC_SWITCH_ENABLED, false);
        mSystemAudioControlFeatureEnabled =
            mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true);
        // TODO(amyjojo): make the map ro property.
        mTvInputs.put(Constants.CEC_SWITCH_HDMI1,
                "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5");
        mTvInputs.put(Constants.CEC_SWITCH_HDMI2,
                "com.droidlogic.tvinput/.services.Hdmi2InputService/HW6");
        mTvInputs.put(Constants.CEC_SWITCH_HDMI3,
                "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7");
        // TODO(amyjojo): Maintain a portId to TvinputId map.
        mTvInputs.put(2, "com.droidlogic.tvinput/.services.Hdmi1InputService/HW5");
        mTvInputs.put(4, "com.droidlogic.tvinput/.services.Hdmi2InputService/HW6");
        mTvInputs.put(1, "com.droidlogic.tvinput/.services.Hdmi3InputService/HW7");
    }

    /**
@@ -174,6 +176,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
            removeDeviceInfo(deviceInfo.getId());
        }
        mDeviceInfos.append(deviceInfo.getId(), deviceInfo);
        updateSafeDeviceInfoList();
        return oldDeviceInfo;
    }

@@ -191,6 +194,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
        if (deviceInfo != null) {
            mDeviceInfos.remove(id);
        }
        updateSafeDeviceInfoList();
        return deviceInfo;
    }

@@ -207,6 +211,24 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
        return mDeviceInfos.get(HdmiDeviceInfo.idForCecDevice(logicalAddress));
    }

    @ServiceThreadOnly
    private void updateSafeDeviceInfoList() {
        assertRunOnServiceThread();
        List<HdmiDeviceInfo> copiedDevices = HdmiUtils.sparseArrayToList(mDeviceInfos);
        synchronized (mLock) {
            mSafeAllDeviceInfos = copiedDevices;
        }
    }

    @GuardedBy("mLock")
    List<HdmiDeviceInfo> getSafeCecDevicesLocked() {
        ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>();
        for (HdmiDeviceInfo info : mSafeAllDeviceInfos) {
            infoList.add(info);
        }
        return infoList;
    }

    private void invokeDeviceEventListener(HdmiDeviceInfo info, int status) {
        mService.invokeDeviceEventListeners(info, status);
    }
@@ -723,7 +745,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
     */
    private void setSystemAudioMode(boolean newSystemAudioMode) {
        int targetPhysicalAddress = getActiveSource().physicalAddress;
        int port = getLocalPortFromPhysicalAddress(targetPhysicalAddress);
        int port = mService.pathToPortId(targetPhysicalAddress);
        if (newSystemAudioMode && port >= 0) {
            switchToAudioInput();
        }
@@ -731,9 +753,10 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
        // PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE is false when device never needs to be muted.
        boolean currentMuteStatus =
                mService.getAudioManager().isStreamMute(AudioManager.STREAM_MUSIC);
        if (currentMuteStatus == newSystemAudioMode) {
            if (SystemProperties.getBoolean(
                    Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, true)
                && currentMuteStatus == newSystemAudioMode) {
                            || newSystemAudioMode) {
                mService.getAudioManager()
                        .adjustStreamVolume(
                                AudioManager.STREAM_MUSIC,
@@ -742,6 +765,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
                                        : AudioManager.ADJUST_MUTE,
                                0);
            }
        }
        updateAudioManagerForSystemAudio(newSystemAudioMode);
        synchronized (mLock) {
            if (mSystemAudioActivated != newSystemAudioMode) {
@@ -922,7 +946,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {

    @Override
    protected void switchInputOnReceivingNewActivePath(int physicalAddress) {
        int port = getLocalPortFromPhysicalAddress(physicalAddress);
        int port = mService.pathToPortId(physicalAddress);
        if (isSystemAudioActivated() && port < 0) {
            // If system audio mode is on and the new active source is not under the current device,
            // Will switch to ARC input.
@@ -994,7 +1018,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {

    @Override
    protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
        int port = getLocalPortFromPhysicalAddress(physicalAddress);
        int port = mService.pathToPortId(physicalAddress);
        // Routing change or information sent from switches under the current device can be ignored.
        if (port > 0) {
            return;
@@ -1063,6 +1087,10 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
    @ServiceThreadOnly
    private void launchDeviceDiscovery() {
        assertRunOnServiceThread();
        if (hasAction(DeviceDiscoveryAction.class)) {
            Slog.i(TAG, "Device Discovery Action is in progress. Restarting.");
            removeAction(DeviceDiscoveryAction.class);
        }
        DeviceDiscoveryAction action = new DeviceDiscoveryAction(this,
                new DeviceDiscoveryCallback() {
                    @Override
@@ -1086,6 +1114,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
            invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
        }
        mDeviceInfos.clear();
        updateSafeDeviceInfoList();
    }

    @Override
@@ -1093,10 +1122,13 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
        pw.println("HdmiCecLocalDeviceAudioSystem:");
        pw.increaseIndent();
        pw.println("mSystemAudioActivated: " + mSystemAudioActivated);
        pw.println("isRoutingFeatureEnabled " + isRoutingControlFeatureEnabled());
        pw.println("mSystemAudioControlFeatureEnabled: " + mSystemAudioControlFeatureEnabled);
        pw.println("mTvSystemAudioModeSupport: " + mTvSystemAudioModeSupport);
        pw.println("mArcEstablished: " + mArcEstablished);
        pw.println("mArcIntentUsed: " + mArcIntentUsed);
        pw.println("mRoutingPort: " + getRoutingPort());
        pw.println("mLocalActivePort: " + getLocalActivePort());
        HdmiUtils.dumpMap(pw, "mTvInputs:", mTvInputs);
        HdmiUtils.dumpSparseArray(pw, "mDeviceInfos:", mDeviceInfos);
        pw.decreaseIndent();
Loading