Methods Summary |
---|
void | addLocalDevice(int deviceType, HdmiCecLocalDevice device)
assertRunOnServiceThread();
mLocalDevices.put(deviceType, device);
|
int | addLogicalAddress(int newLogicalAddress)Add a new logical address to the device. Device's HW should be notified
when a new logical address is assigned to a device, so that it can accept
a command having available destinations.
Declared as package-private. accessed by {@link HdmiControlService} only.
assertRunOnServiceThread();
if (HdmiUtils.isValidAddress(newLogicalAddress)) {
return nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
} else {
return -1;
}
|
void | allocateLogicalAddress(int deviceType, int preferredAddress, com.android.server.hdmi.HdmiCecController$AllocateAddressCallback callback)Allocate a new logical address of the given device type. Allocated
address will be reported through {@link AllocateAddressCallback}.
Declared as package-private, accessed by {@link HdmiControlService} only.
assertRunOnServiceThread();
runOnIoThread(new Runnable() {
@Override
public void run() {
handleAllocateLogicalAddress(deviceType, preferredAddress, callback);
}
});
|
private void | assertRunOnIoThread()
if (Looper.myLooper() != mIoHandler.getLooper()) {
throw new IllegalStateException("Should run on io thread.");
}
|
private void | assertRunOnServiceThread()
if (Looper.myLooper() != mControlHandler.getLooper()) {
throw new IllegalStateException("Should run on service thread.");
}
|
private static byte[] | buildBody(int opcode, byte[] params)
byte[] body = new byte[params.length + 1];
body[0] = (byte) opcode;
System.arraycopy(params, 0, body, 1, params.length);
return body;
|
void | clearLocalDevices()
assertRunOnServiceThread();
mLocalDevices.clear();
|
void | clearLogicalAddress()Clear all logical addresses registered in the device.
Declared as package-private. accessed by {@link HdmiControlService} only.
assertRunOnServiceThread();
for (int i = 0; i < mLocalDevices.size(); ++i) {
mLocalDevices.valueAt(i).clearAddress();
}
nativeClearLogicalAddress(mNativePtr);
|
static com.android.server.hdmi.HdmiCecController | create(HdmiControlService service)A factory method to get {@link HdmiCecController}. If it fails to initialize
inner device or has no device it will return {@code null}.
Declared as package-private, accessed by {@link HdmiControlService} only.
HdmiCecController controller = new HdmiCecController(service);
long nativePtr = nativeInit(controller, service.getServiceLooper().getQueue());
if (nativePtr == 0L) {
controller = null;
return null;
}
controller.init(nativePtr);
return controller;
|
void | dump(com.android.internal.util.IndentingPrintWriter pw)
for (int i = 0; i < mLocalDevices.size(); ++i) {
pw.println("HdmiCecLocalDevice #" + i + ":");
pw.increaseIndent();
mLocalDevices.valueAt(i).dump(pw);
pw.decreaseIndent();
}
|
void | flush(java.lang.Runnable runnable)
assertRunOnServiceThread();
runOnIoThread(new Runnable() {
@Override
public void run() {
// This ensures the runnable for cleanup is performed after all the pending
// commands are processed by IO thread.
runOnServiceThread(runnable);
}
});
|
HdmiCecLocalDevice | getLocalDevice(int deviceType)Return the locally hosted logical device of a given type.
return mLocalDevices.get(deviceType);
|
java.util.List | getLocalDeviceList()Return a list of all {@link HdmiCecLocalDevice}s.
Declared as package-private. accessed by {@link HdmiControlService} only.
assertRunOnServiceThread();
return HdmiUtils.sparseArrayToList(mLocalDevices);
|
int | getPhysicalAddress()Return the physical address of the device.
Declared as package-private. accessed by {@link HdmiControlService} only.
assertRunOnServiceThread();
return nativeGetPhysicalAddress(mNativePtr);
|
android.hardware.hdmi.HdmiPortInfo[] | getPortInfos()
return nativeGetPortInfos(mNativePtr);
|
int | getVendorId()Return vendor id of the device.
Declared as package-private. accessed by {@link HdmiControlService} only.
assertRunOnServiceThread();
return nativeGetVendorId(mNativePtr);
|
int | getVersion()Return CEC version of the device.
Declared as package-private. accessed by {@link HdmiControlService} only.
assertRunOnServiceThread();
return nativeGetVersion(mNativePtr);
|
private void | handleAllocateLogicalAddress(int deviceType, int preferredAddress, com.android.server.hdmi.HdmiCecController$AllocateAddressCallback callback)
assertRunOnIoThread();
int startAddress = preferredAddress;
// If preferred address is "unregistered", start address will be the smallest
// address matched with the given device type.
if (preferredAddress == Constants.ADDR_UNREGISTERED) {
for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
if (deviceType == HdmiUtils.getTypeFromAddress(i)) {
startAddress = i;
break;
}
}
}
int logicalAddress = Constants.ADDR_UNREGISTERED;
// Iterates all possible addresses which has the same device type.
for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) {
int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS;
if (curAddress != Constants.ADDR_UNREGISTERED
&& deviceType == HdmiUtils.getTypeFromAddress(curAddress)) {
int failedPollingCount = 0;
for (int j = 0; j < HdmiConfig.ADDRESS_ALLOCATION_RETRY; ++j) {
if (!sendPollMessage(curAddress, curAddress, 1)) {
failedPollingCount++;
}
}
// Pick logical address if failed ratio is more than a half of all retries.
if (failedPollingCount * 2 > HdmiConfig.ADDRESS_ALLOCATION_RETRY) {
logicalAddress = curAddress;
break;
}
}
}
final int assignedAddress = logicalAddress;
HdmiLogger.debug("New logical address for device [%d]: [preferred:%d, assigned:%d]",
deviceType, preferredAddress, assignedAddress);
if (callback != null) {
runOnServiceThread(new Runnable() {
@Override
public void run() {
callback.onAllocated(deviceType, assignedAddress);
}
});
}
|
private void | handleHotplug(int port, boolean connected)Called by native when a hotplug event issues.
assertRunOnServiceThread();
HdmiLogger.debug("Hotplug event:[port:%d, connected:%b]", port, connected);
mService.onHotplug(port, connected);
|
private void | handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body)Called by native when incoming CEC message arrived.
assertRunOnServiceThread();
HdmiCecMessage command = HdmiCecMessageBuilder.of(srcAddress, dstAddress, body);
HdmiLogger.debug("[R]:" + command);
onReceiveCommand(command);
|
private void | init(long nativePtr)
mIoHandler = new Handler(mService.getIoLooper());
mControlHandler = new Handler(mService.getServiceLooper());
mNativePtr = nativePtr;
|
private boolean | isAcceptableAddress(int address)
// Can access command targeting devices available in local device or broadcast command.
if (address == Constants.ADDR_BROADCAST) {
return true;
}
return isAllocatedLocalDeviceAddress(address);
|
private boolean | isAllocatedLocalDeviceAddress(int address)
assertRunOnServiceThread();
for (int i = 0; i < mLocalDevices.size(); ++i) {
if (mLocalDevices.valueAt(i).isAddressOf(address)) {
return true;
}
}
return false;
|
boolean | isConnected(int port)Return the connection status of the specified port
assertRunOnServiceThread();
return nativeIsConnected(mNativePtr, port);
|
void | maySendFeatureAbortCommand(HdmiCecMessage message, int reason)
assertRunOnServiceThread();
// Swap the source and the destination.
int src = message.getDestination();
int dest = message.getSource();
if (src == Constants.ADDR_BROADCAST || dest == Constants.ADDR_UNREGISTERED) {
// Don't reply <Feature Abort> from the unregistered devices or for the broadcasted
// messages. See CEC 12.2 Protocol General Rules for detail.
return;
}
int originalOpcode = message.getOpcode();
if (originalOpcode == Constants.MESSAGE_FEATURE_ABORT) {
return;
}
sendCommand(
HdmiCecMessageBuilder.buildFeatureAbortCommand(src, dest, originalOpcode, reason));
|
private static native int | nativeAddLogicalAddress(long controllerPtr, int logicalAddress)
|
private static native void | nativeClearLogicalAddress(long controllerPtr)
|
private static native int | nativeGetPhysicalAddress(long controllerPtr)
|
private static native android.hardware.hdmi.HdmiPortInfo[] | nativeGetPortInfos(long controllerPtr)
|
private static native int | nativeGetVendorId(long controllerPtr)
|
private static native int | nativeGetVersion(long controllerPtr)
|
private static native long | nativeInit(com.android.server.hdmi.HdmiCecController handler, android.os.MessageQueue messageQueue)
|
private static native boolean | nativeIsConnected(long controllerPtr, int port)
|
private static native int | nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress, byte[] body)
|
private static native void | nativeSetAudioReturnChannel(long controllerPtr, int port, boolean flag)
|
private static native void | nativeSetOption(long controllerPtr, int flag, int value)
|
private void | onReceiveCommand(HdmiCecMessage message)
assertRunOnServiceThread();
if (isAcceptableAddress(message.getDestination()) && mService.handleCecCommand(message)) {
return;
}
// Not handled message, so we will reply it with <Feature Abort>.
maySendFeatureAbortCommand(message, Constants.ABORT_UNRECOGNIZED_OPCODE);
|
private java.util.List | pickPollCandidates(int pickStrategy)
int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK;
Predicate<Integer> pickPredicate = null;
switch (strategy) {
case Constants.POLL_STRATEGY_SYSTEM_AUDIO:
pickPredicate = mSystemAudioAddressPredicate;
break;
case Constants.POLL_STRATEGY_REMOTES_DEVICES:
default: // The default is POLL_STRATEGY_REMOTES_DEVICES.
pickPredicate = mRemoteDeviceAddressPredicate;
break;
}
int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK;
LinkedList<Integer> pollingCandidates = new LinkedList<>();
switch (iterationStrategy) {
case Constants.POLL_ITERATION_IN_ORDER:
for (int i = Constants.ADDR_TV; i <= Constants.ADDR_SPECIFIC_USE; ++i) {
if (pickPredicate.apply(i)) {
pollingCandidates.add(i);
}
}
break;
case Constants.POLL_ITERATION_REVERSE_ORDER:
default: // The default is reverse order.
for (int i = Constants.ADDR_SPECIFIC_USE; i >= Constants.ADDR_TV; --i) {
if (pickPredicate.apply(i)) {
pollingCandidates.add(i);
}
}
break;
}
return pollingCandidates;
|
void | pollDevices(com.android.server.hdmi.HdmiControlService.DevicePollingCallback callback, int sourceAddress, int pickStrategy, int retryCount)Poll all remote devices. It sends <Polling Message> to all remote
devices.
Declared as package-private. accessed by {@link HdmiControlService} only.
assertRunOnServiceThread();
// Extract polling candidates. No need to poll against local devices.
List<Integer> pollingCandidates = pickPollCandidates(pickStrategy);
ArrayList<Integer> allocated = new ArrayList<>();
runDevicePolling(sourceAddress, pollingCandidates, retryCount, callback, allocated);
|
private void | runDevicePolling(int sourceAddress, java.util.List candidates, int retryCount, com.android.server.hdmi.HdmiControlService.DevicePollingCallback callback, java.util.List allocated)
assertRunOnServiceThread();
if (candidates.isEmpty()) {
if (callback != null) {
HdmiLogger.debug("[P]:AllocatedAddress=%s", allocated.toString());
callback.onPollingFinished(allocated);
}
return;
}
final Integer candidate = candidates.remove(0);
// Proceed polling action for the next address once polling action for the
// previous address is done.
runOnIoThread(new Runnable() {
@Override
public void run() {
if (sendPollMessage(sourceAddress, candidate, retryCount)) {
allocated.add(candidate);
}
runOnServiceThread(new Runnable() {
@Override
public void run() {
runDevicePolling(sourceAddress, candidates, retryCount, callback,
allocated);
}
});
}
});
|
private void | runOnIoThread(java.lang.Runnable runnable)
mIoHandler.post(runnable);
|
private void | runOnServiceThread(java.lang.Runnable runnable)
mControlHandler.post(runnable);
|
void | sendCommand(HdmiCecMessage cecMessage)
assertRunOnServiceThread();
sendCommand(cecMessage, null);
|
void | sendCommand(HdmiCecMessage cecMessage, HdmiControlService.SendMessageCallback callback)
assertRunOnServiceThread();
runOnIoThread(new Runnable() {
@Override
public void run() {
HdmiLogger.debug("[S]:" + cecMessage);
byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
int i = 0;
int errorCode = Constants.SEND_RESULT_SUCCESS;
do {
errorCode = nativeSendCecCommand(mNativePtr, cecMessage.getSource(),
cecMessage.getDestination(), body);
if (errorCode == Constants.SEND_RESULT_SUCCESS) {
break;
}
} while (i++ < HdmiConfig.RETRANSMISSION_COUNT);
final int finalError = errorCode;
if (finalError != Constants.SEND_RESULT_SUCCESS) {
Slog.w(TAG, "Failed to send " + cecMessage);
}
if (callback != null) {
runOnServiceThread(new Runnable() {
@Override
public void run() {
callback.onSendCompleted(finalError);
}
});
}
}
});
|
private boolean | sendPollMessage(int sourceAddress, int destinationAddress, int retryCount)
assertRunOnIoThread();
for (int i = 0; i < retryCount; ++i) {
// <Polling Message> is a message which has empty body.
// If sending <Polling Message> failed (NAK), it becomes
// new logical address for the device because no device uses
// it as logical address of the device.
if (nativeSendCecCommand(mNativePtr, sourceAddress, destinationAddress, EMPTY_BODY)
== Constants.SEND_RESULT_SUCCESS) {
return true;
}
}
return false;
|
void | setAudioReturnChannel(int port, boolean enabled)Configure ARC circuit in the hardware logic to start or stop the feature.
assertRunOnServiceThread();
nativeSetAudioReturnChannel(mNativePtr, port, enabled);
|
void | setOption(int flag, int value)Set an option to CEC HAL.
assertRunOnServiceThread();
HdmiLogger.debug("setOption: [flag:%d, value:%d]", flag, value);
nativeSetOption(mNativePtr, flag, value);
|