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
This commit is contained in:
Jinsuk Kim
2014-05-20 16:45:45 +09:00
parent dd64b567c3
commit 2918e9e133
4 changed files with 200 additions and 54 deletions

View File

@@ -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;
}
private void init(HdmiControlService service, long nativePtr) {
mService = service;
mIoHandler = new Handler(service.getServiceLooper());
mControlHandler = new Handler(service.getServiceLooper());
mNativePtr = nativePtr;
}
/**
* Initialize {@link #mLocalAddresses} by allocating logical addresses for each hosted type.
* Perform initialization for each hosted device.
*
* @param deviceTypes local device types
* @param deviceTypes array of 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);
}
});
}
}
/**
* Get the preferred address for a given type.
*
* @param deviceType logical device type to get the address for
* @return preferred address; {@link HdmiCec#ADDR_UNREGISTERED} if not available.
*/
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;
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() {

View File

@@ -0,0 +1,78 @@
/*
* 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;
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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));
}
}

View File

@@ -0,0 +1,43 @@
/*
* 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.
}
}