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

Commit 2918e9e1 authored by Jinsuk Kim's avatar Jinsuk Kim
Browse files

CEC Initialization per device type

CEC initialization may vary from device type to type. Changed logical address
map to HdmiCecLocalDevice map to handle it. These per-type classes for local
device will be extended also to take care of incoming CEC commands that should
require different action based on device type.

Change-Id: Ia59a464607b14e942fcf83e63aa1d6310ca6a575
parent dd64b567
Loading
Loading
Loading
Loading
+42 −53
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.hardware.hdmi.HdmiCecDeviceInfo;
import android.hardware.hdmi.HdmiCecMessage;
import android.os.Handler;
import android.util.SparseArray;
import android.util.SparseIntArray;

import libcore.util.EmptyArray;

@@ -75,14 +74,12 @@ final class HdmiCecController {
    // used as key of container.
    private final SparseArray<HdmiCecDeviceInfo> mDeviceInfos =
            new SparseArray<HdmiCecDeviceInfo>();
    // Set-like container for all local devices' logical address.
    // Key and value are same.
    private final SparseIntArray mLocalAddresses = new SparseIntArray();

    // Stores the local CEC devices in the system.
    private final ArrayList<HdmiCecLocalDevice> mLocalDevices = new ArrayList<>();

    // Private constructor.  Use HdmiCecController.create().
    private HdmiCecController() {
        // TODO: Consider restoring the local device addresses from persistent storage
        //       to allocate the same addresses again if possible.
    }

    /**
@@ -96,53 +93,41 @@ final class HdmiCecController {
     *         returns {@code null}.
     */
    static HdmiCecController create(HdmiControlService service) {
        HdmiCecController handler = new HdmiCecController();
        long nativePtr = nativeInit(handler);
        HdmiCecController controller = new HdmiCecController();
        long nativePtr = nativeInit(controller);
        if (nativePtr == 0L) {
            handler = null;
            controller = null;
            return null;
        }

        handler.init(service, nativePtr);
        return handler;
        controller.init(service, nativePtr);
        return controller;
    }

    /**
     * Initialize {@link #mLocalAddresses} by allocating logical addresses for each hosted type.
     *
     * @param deviceTypes local device types
     */
    void initializeLocalDevices(int[] deviceTypes) {
        for (int deviceType : deviceTypes) {
            int preferred = getPreferredAddress(deviceType);
            allocateLogicalAddress(deviceType, preferred, new AllocateLogicalAddressCallback() {
                @Override
                public void onAllocated(int deviceType, int logicalAddress) {
                    addLogicalAddress(logicalAddress);
                }
            });
        }
    private void init(HdmiControlService service, long nativePtr) {
        mService = service;
        mIoHandler = new Handler(service.getServiceLooper());
        mControlHandler = new Handler(service.getServiceLooper());
        mNativePtr = nativePtr;
    }

    /**
     * Get the preferred address for a given type.
     * Perform initialization for each hosted device.
     *
     * @param deviceType logical device type to get the address for
     * @return preferred address; {@link HdmiCec#ADDR_UNREGISTERED} if not available.
     * @param deviceTypes array of device types
     */
    private int getPreferredAddress(int deviceType) {
        // Uses the data restored from persistent memory at boot up if they are available.
        // Otherwise we return UNREGISTERED indicating there is no preferred address.
        // Note that for address SPECIFIC_USE(14), HdmiCec.getTypeFromAddress() returns DEVICE_TV,
        // meaning that we do not support device type video processor yet.
        for (int i = 0; i < mLocalAddresses.size(); ++i) {
            int address = mLocalAddresses.keyAt(i);
            int type = HdmiCec.getTypeFromAddress(address);
            if (type == deviceType) {
                return address;
    void initializeLocalDevices(int[] deviceTypes) {
        for (int type : deviceTypes) {
            HdmiCecLocalDevice device = HdmiCecLocalDevice.create(this, type);
            if (device == null) {
                continue;
            }
            // TODO: Consider restoring the local device addresses from persistent storage
            //       to allocate the same addresses again if possible.
            device.setPreferredAddress(HdmiCec.ADDR_UNREGISTERED);
            mLocalDevices.add(device);
            device.init();
        }
        return HdmiCec.ADDR_UNREGISTERED;
    }

    /**
@@ -310,7 +295,6 @@ final class HdmiCecController {
     */
    int addLogicalAddress(int newLogicalAddress) {
        if (HdmiCec.isValidAddress(newLogicalAddress)) {
            mLocalAddresses.put(newLogicalAddress, newLogicalAddress);
            return nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
        } else {
            return -1;
@@ -325,7 +309,9 @@ final class HdmiCecController {
    void clearLogicalAddress() {
        // TODO: consider to backup logical address so that new logical address
        // allocation can use it as preferred address.
        mLocalAddresses.clear();
        for (HdmiCecLocalDevice device : mLocalDevices) {
            device.clearAddress();
        }
        nativeClearLogicalAddress(mNativePtr);
    }

@@ -367,18 +353,17 @@ final class HdmiCecController {
        mControlHandler.post(runnable);
    }

    private void init(HdmiControlService service, long nativePtr) {
        mService = service;
        mIoHandler = new Handler(service.getServiceLooper());
        mControlHandler = new Handler(service.getServiceLooper());
        mNativePtr = nativePtr;
    }

    private boolean isAcceptableAddress(int address) {
        // Can access command targeting devices available in local device or
        // broadcast command.
        return address == HdmiCec.ADDR_BROADCAST
                || mLocalAddresses.indexOfKey(address) < 0;
        // Can access command targeting devices available in local device or broadcast command.
        if (address == HdmiCec.ADDR_BROADCAST) {
            return true;
        }
        for (HdmiCecLocalDevice device : mLocalDevices) {
            if (device.isAddressOf(address)) {
                return true;
            }
        }
        return false;
    }

    private void onReceiveCommand(HdmiCecMessage message) {
@@ -397,6 +382,10 @@ final class HdmiCecController {
        sendCommand(cecMessage, null);
    }

    void sendCommand(HdmiCecMessage cecMessage) {
        sendCommand(cecMessage, null);
    }

    void sendCommand(final HdmiCecMessage cecMessage,
            final HdmiControlService.SendMessageCallback callback) {
        runOnIoThread(new Runnable() {
+78 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.hdmi;

import com.android.server.hdmi.HdmiCecController.AllocateLogicalAddressCallback;

import android.hardware.hdmi.HdmiCec;

/**
 * Class that models a logical CEC device hosted in this system. Handles initialization,
 * CEC commands that call for actions customized per device type.
 */
abstract class HdmiCecLocalDevice {

    protected final HdmiCecController mController;
    protected final int mDeviceType;
    protected int mAddress;
    protected int mPreferredAddress;

    protected HdmiCecLocalDevice(HdmiCecController controller, int deviceType) {
        mController = controller;
        mDeviceType = deviceType;
        mAddress = HdmiCec.ADDR_UNREGISTERED;
    }

    // Factory method that returns HdmiCecLocalDevice of corresponding type.
    static HdmiCecLocalDevice create(HdmiCecController controller, int deviceType) {
        switch (deviceType) {
        case HdmiCec.DEVICE_TV:
            return new HdmiCecLocalDeviceTv(controller);
        case HdmiCec.DEVICE_PLAYBACK:
            return new HdmiCecLocalDevicePlayback(controller);
        default:
            return null;
        }
    }

    abstract void init();

    protected void allocateAddress(int type) {
        mController.allocateLogicalAddress(type, mPreferredAddress,
                new AllocateLogicalAddressCallback() {
            @Override
            public void onAllocated(int deviceType, int logicalAddress) {
                mAddress = mPreferredAddress = logicalAddress;
                mController.addLogicalAddress(logicalAddress);
            }
        });
    }

    // Returns true if the logical address is same as the argument.
    boolean isAddressOf(int addr) {
        return addr == mAddress;
    }

    // Resets the logical address to unregistered(15), meaning the logical device is invalid.
    void clearAddress() {
        mAddress = HdmiCec.ADDR_UNREGISTERED;
    }

    void setPreferredAddress(int addr) {
        mPreferredAddress = addr;
    }
}
+36 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.hdmi;

import android.hardware.hdmi.HdmiCec;

/**
 * Represent a logical device of type Playback residing in Android system.
 */
final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {

    HdmiCecLocalDevicePlayback(HdmiCecController controller) {
        super(controller, HdmiCec.DEVICE_PLAYBACK);
    }

    @Override
    void init() {
        allocateAddress(mDeviceType);
        mController.sendCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
                mAddress, mController.getPhysicalAddress(), mDeviceType));
    }
}
+43 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.hdmi;

import android.hardware.hdmi.HdmiCec;

/**
 * Represent a logical device of type TV residing in Android system.
 */
final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {

    HdmiCecLocalDeviceTv(HdmiCecController controller) {
        super(controller, HdmiCec.DEVICE_TV);
    }

    @Override
    void init() {
        allocateAddress(mDeviceType);

        // TODO: vendor-specific initialization here.

        mController.sendCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
                mAddress, mController.getPhysicalAddress(), mDeviceType));
        mController.sendCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
                mAddress, mController.getVendorId()));

        // TODO: Start routing control action, device discovery action.
    }
}