tv.cec: Update framework code to call Treble HAL

Bug: 32073236
Test: Checked CEC features works on fugu after applying Treble HAL
Change-Id: I26df037594e2505bd8f2d2bb6222cba5ddca2906
This commit is contained in:
Donghyun Cho
2016-11-04 05:25:52 +09:00
parent e6022a40ad
commit bc6e372b25
19 changed files with 287 additions and 263 deletions

View File

@@ -19,8 +19,9 @@ LOCAL_AIDL_INCLUDES += \
LOCAL_JAVA_LIBRARIES := \
services.net \
telephony-common \
android.hardware.light@2.0-java \
android.hardware.power@1.0-java \
android.hardware.light@2.0-java
android.hardware.tv.cec@1.0-java
LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update

View File

@@ -188,12 +188,6 @@ final class Constants {
static final int INVALID_PHYSICAL_ADDRESS = HdmiDeviceInfo.PATH_INVALID;
static final int PATH_INTERNAL = HdmiDeviceInfo.PATH_INTERNAL;
// Send result codes. It should be consistent with hdmi_cec.h's send_message error code.
static final int SEND_RESULT_SUCCESS = 0;
static final int SEND_RESULT_NAK = 1;
static final int SEND_RESULT_BUSY = 2;
static final int SEND_RESULT_FAILURE = 3;
// Strategy for device polling.
// Should use "OR(|) operation of POLL_STRATEGY_XXX and POLL_ITERATION_XXX.
static final int POLL_STRATEGY_MASK = 0x3; // first and second bit.
@@ -231,26 +225,7 @@ final class Constants {
static final int RECORDING_TYPE_OWN_SOURCE = 4;
// Definitions used for setOption(). These should be in sync with the definition
// in hardware/libhardware/include/hardware/{hdmi_cec.h,mhl.h}.
// TV gets turned on by incoming <Text/Image View On>. enabled by default.
// If set to disabled, TV won't turn on automatically.
static final int OPTION_CEC_AUTO_WAKEUP = 1;
// If set to disabled, all CEC commands are discarded.
static final int OPTION_CEC_ENABLE = 2;
// If set to disabled, system service yields control of CEC to sub-microcontroller.
// If enabled, it takes the control back.
static final int OPTION_CEC_SERVICE_CONTROL = 3;
// Put other devices to standby when TV goes to standby. enabled by default.
// If set to disabled, TV doesn't send <Standby> to other devices.
static final int OPTION_CEC_AUTO_DEVICE_OFF = 4;
// Passes the language used in the system when updated. The value to use is the 3 byte
// code as defined in ISO/FDIS 639-2.
static final int OPTION_CEC_SET_LANGUAGE = 5;
// in hardware/libhardware/include/hardware/mhl.h.
// If set to disabled, TV does not switch ports when mobile device is connected.
static final int OPTION_MHL_INPUT_SWITCHING = 101;

View File

@@ -16,13 +16,13 @@
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiTvClient;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.os.RemoteException;
import android.util.Slog;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
/**
@@ -95,7 +95,7 @@ final class DeviceSelectAction extends HdmiCecFeatureAction {
sendCommand(mGivePowerStatus, new SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
if (error != Constants.SEND_RESULT_SUCCESS) {
if (error != SendMessageResult.SUCCESS) {
invokeCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED);
finish();
return;

View File

@@ -17,23 +17,23 @@
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.tv.cec.V1_0.Result;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Predicate;
import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiControlService.DevicePollingCallback;
import libcore.util.EmptyArray;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import libcore.util.EmptyArray;
import sun.util.locale.LanguageTag;
/**
* Manages HDMI-CEC command and behaviors. It converts user's command into CEC command
@@ -256,7 +256,7 @@ final class HdmiCecController {
if (HdmiUtils.isValidAddress(newLogicalAddress)) {
return nativeAddLogicalAddress(mNativePtr, newLogicalAddress);
} else {
return -1;
return Result.FAILURE_INVALID_ARGS;
}
}
@@ -320,13 +320,27 @@ final class HdmiCecController {
* Set an option to CEC HAL.
*
* @param flag key of option
* @param value value of option
* @param enabled whether to enable/disable the given option.
*/
@ServiceThreadOnly
void setOption(int flag, int value) {
void setOption(int flag, boolean enabled) {
assertRunOnServiceThread();
HdmiLogger.debug("setOption: [flag:%d, value:%d]", flag, value);
nativeSetOption(mNativePtr, flag, value);
HdmiLogger.debug("setOption: [flag:%d, enabled:%b]", flag, enabled);
nativeSetOption(mNativePtr, flag, enabled);
}
/**
* Informs CEC HAL about the current system language.
*
* @param language Three-letter code defined in ISO/FDIS 639-2. Must be lowercase letters.
*/
@ServiceThreadOnly
void setLanguage(String language) {
assertRunOnServiceThread();
if (!LanguageTag.isLanguage(language)) {
return;
}
nativeSetLanguage(mNativePtr, language);
}
/**
@@ -336,9 +350,9 @@ final class HdmiCecController {
* @param enabled whether to enable/disable ARC
*/
@ServiceThreadOnly
void setAudioReturnChannel(int port, boolean enabled) {
void enableAudioReturnChannel(int port, boolean enabled) {
assertRunOnServiceThread();
nativeSetAudioReturnChannel(mNativePtr, port, enabled);
nativeEnableAudioReturnChannel(mNativePtr, port, enabled);
}
/**
@@ -472,9 +486,9 @@ final class HdmiCecController {
// <Polling Message> is a message which has empty body.
int ret =
nativeSendCecCommand(mNativePtr, sourceAddress, destinationAddress, EMPTY_BODY);
if (ret == Constants.SEND_RESULT_SUCCESS) {
if (ret == SendMessageResult.SUCCESS) {
return true;
} else if (ret != Constants.SEND_RESULT_NAK) {
} else if (ret != SendMessageResult.NACK) {
// Unusual failure
HdmiLogger.warning("Failed to send a polling message(%d->%d) with return code %d",
sourceAddress, destinationAddress, ret);
@@ -572,17 +586,17 @@ final class HdmiCecController {
HdmiLogger.debug("[S]:" + cecMessage);
byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
int i = 0;
int errorCode = Constants.SEND_RESULT_SUCCESS;
int errorCode = SendMessageResult.SUCCESS;
do {
errorCode = nativeSendCecCommand(mNativePtr, cecMessage.getSource(),
cecMessage.getDestination(), body);
if (errorCode == Constants.SEND_RESULT_SUCCESS) {
if (errorCode == SendMessageResult.SUCCESS) {
break;
}
} while (i++ < HdmiConfig.RETRANSMISSION_COUNT);
final int finalError = errorCode;
if (finalError != Constants.SEND_RESULT_SUCCESS) {
if (finalError != SendMessageResult.SUCCESS) {
Slog.w(TAG, "Failed to send " + cecMessage);
}
if (callback != null) {
@@ -636,7 +650,8 @@ final class HdmiCecController {
private static native int nativeGetVersion(long controllerPtr);
private static native int nativeGetVendorId(long controllerPtr);
private static native HdmiPortInfo[] nativeGetPortInfos(long controllerPtr);
private static native void nativeSetOption(long controllerPtr, int flag, int value);
private static native void nativeSetAudioReturnChannel(long controllerPtr, int port, boolean flag);
private static native void nativeSetOption(long controllerPtr, int flag, boolean enabled);
private static native void nativeSetLanguage(long controllerPtr, String language);
private static native void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag);
private static native boolean nativeIsConnected(long controllerPtr, int port);
}

View File

@@ -36,6 +36,7 @@ import android.hardware.hdmi.HdmiPortInfo;
import android.hardware.hdmi.HdmiRecordSources;
import android.hardware.hdmi.HdmiTimerRecordSources;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.tv.TvInputInfo;
@@ -46,7 +47,6 @@ import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback;
@@ -57,9 +57,9 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.HashMap;
/**
* Represent a logical device of type TV residing in Android system.
@@ -910,7 +910,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled);
boolean oldStatus = mArcEstablished;
// 1. Enable/disable ARC circuit.
setAudioReturnChannel(enabled);
enableAudioReturnChannel(enabled);
// 2. Notify arc status to audio service.
notifyArcStatusToAudioService(enabled);
// 3. Update arc status;
@@ -922,11 +922,11 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
* Switch hardware ARC circuit in the system.
*/
@ServiceThreadOnly
void setAudioReturnChannel(boolean enabled) {
void enableAudioReturnChannel(boolean enabled) {
assertRunOnServiceThread();
HdmiDeviceInfo avr = getAvrDeviceInfo();
if (avr != null) {
mService.setAudioReturnChannel(avr.getPortId(), enabled);
mService.enableAudioReturnChannel(avr.getPortId(), enabled);
}
}
@@ -1870,7 +1870,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
mService.sendCecCommand(message, new SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
if (error != Constants.SEND_RESULT_SUCCESS) {
if (error != SendMessageResult.SUCCESS) {
announceClearTimerRecordingResult(recorderAddress,
CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE);
}

View File

@@ -20,10 +20,6 @@ import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE;
import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE;
import static com.android.server.hdmi.Constants.DISABLED;
import static com.android.server.hdmi.Constants.ENABLED;
import static com.android.server.hdmi.Constants.OPTION_CEC_AUTO_WAKEUP;
import static com.android.server.hdmi.Constants.OPTION_CEC_ENABLE;
import static com.android.server.hdmi.Constants.OPTION_CEC_SERVICE_CONTROL;
import static com.android.server.hdmi.Constants.OPTION_CEC_SET_LANGUAGE;
import static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE;
import static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING;
import static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE;
@@ -49,6 +45,8 @@ import android.hardware.hdmi.IHdmiMhlVendorCommandListener;
import android.hardware.hdmi.IHdmiRecordListener;
import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
import android.hardware.hdmi.IHdmiVendorCommandListener;
import android.hardware.tv.cec.V1_0.OptionKey;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.media.AudioManager;
import android.media.tv.TvInputManager;
import android.media.tv.TvInputManager.TvInputCallback;
@@ -69,7 +67,6 @@ import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.SystemService;
@@ -77,11 +74,6 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
import com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource;
import com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback;
import com.android.server.hdmi.SelectRequestBuffer.DeviceSelectRequest;
import com.android.server.hdmi.SelectRequestBuffer.PortSelectRequest;
import libcore.util.EmptyArray;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -89,6 +81,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import libcore.util.EmptyArray;
/**
* Provides a service for sending and processing HDMI control messages,
@@ -123,9 +116,10 @@ public final class HdmiControlService extends SystemService {
*
* @param error result of send request.
* <ul>
* <li>{@link Constants#SEND_RESULT_SUCCESS}
* <li>{@link Constants#SEND_RESULT_NAK}
* <li>{@link Constants#SEND_RESULT_FAILURE}
* <li>{@link SendMessageResult#SUCCESS}
* <li>{@link SendMessageResult#NACK}
* <li>{@link SendMessageResult#BUSY}
* <li>{@link SendMessageResult#FAIL}
* </ul>
*/
void onSendCompleted(int error);
@@ -466,7 +460,7 @@ public final class HdmiControlService extends SystemService {
mWakeUpMessageReceived = false;
if (isTvDeviceEnabled()) {
mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup()));
mCecController.setOption(OptionKey.WAKEUP, tv().getAutoWakeup());
}
int reason = -1;
switch (initiatedBy) {
@@ -519,7 +513,7 @@ public final class HdmiControlService extends SystemService {
if (isTvDeviceEnabled()) {
tv().setAutoWakeup(enabled);
}
setCecOption(OPTION_CEC_AUTO_WAKEUP, toInt(enabled));
setCecOption(OptionKey.WAKEUP, enabled);
break;
case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED:
for (int type : mLocalDevices) {
@@ -556,8 +550,8 @@ public final class HdmiControlService extends SystemService {
private void initializeCec(int initiatedBy) {
mAddressAllocated = false;
mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED);
mCecController.setOption(OPTION_CEC_SET_LANGUAGE, HdmiUtils.languageToInt(mLanguage));
mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
mCecController.setLanguage(mLanguage);
initializeLocalDevices(initiatedBy);
}
@@ -842,7 +836,7 @@ public final class HdmiControlService extends SystemService {
} else {
HdmiLogger.error("Invalid message type:" + command);
if (callback != null) {
callback.onSendCompleted(Constants.SEND_RESULT_FAILURE);
callback.onSendCompleted(SendMessageResult.FAIL);
}
}
}
@@ -884,8 +878,8 @@ public final class HdmiControlService extends SystemService {
return dispatchMessageToLocalDevice(message);
}
void setAudioReturnChannel(int portId, boolean enabled) {
mCecController.setAudioReturnChannel(portId, enabled);
void enableAudioReturnChannel(int portId, boolean enabled) {
mCecController.enableAudioReturnChannel(portId, enabled);
}
@ServiceThreadOnly
@@ -2079,7 +2073,7 @@ public final class HdmiControlService extends SystemService {
if (isTvDeviceEnabled()) {
tv().broadcastMenuLanguage(language);
mCecController.setOption(OPTION_CEC_SET_LANGUAGE, HdmiUtils.languageToInt(language));
mCecController.setLanguage(language);
}
}
@@ -2123,7 +2117,7 @@ public final class HdmiControlService extends SystemService {
}
mStandbyMessageReceived = false;
mAddressAllocated = false;
mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, DISABLED);
mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, false);
mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, DISABLED);
}
@@ -2216,7 +2210,7 @@ public final class HdmiControlService extends SystemService {
}
@ServiceThreadOnly
void setCecOption(int key, int value) {
void setCecOption(int key, boolean value) {
assertRunOnServiceThread();
mCecController.setOption(key, value);
}
@@ -2249,7 +2243,7 @@ public final class HdmiControlService extends SystemService {
@ServiceThreadOnly
private void enableHdmiControlService() {
mCecController.setOption(OPTION_CEC_ENABLE, ENABLED);
mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
mMhlController.setOption(OPTION_MHL_ENABLE, ENABLED);
initializeCec(INITIATED_BY_ENABLE_CEC);
@@ -2264,7 +2258,7 @@ public final class HdmiControlService extends SystemService {
mCecController.flush(new Runnable() {
@Override
public void run() {
mCecController.setOption(OPTION_CEC_ENABLE, DISABLED);
mCecController.setOption(OptionKey.ENABLE_CEC, false);
mMhlController.setOption(OPTION_MHL_ENABLE, DISABLED);
clearLocalDevices();
}

View File

@@ -291,18 +291,4 @@ final class HdmiUtils {
info.getPhysicalAddress(), info.getPortId(), info.getDeviceType(),
info.getVendorId(), info.getDisplayName(), newPowerStatus);
}
/**
* Convert 3 byte-long language code in string to integer representation.
* English(eng), for example, is converted to 0x656e67.
*
* @param language language code in string
* @return language code in integer representation
*/
static int languageToInt(String language) {
String normalized = language.toLowerCase();
return ((normalized.charAt(0) & 0xFF) << 16)
| ((normalized.charAt(1) & 0xFF) << 8)
| (normalized.charAt(2) & 0xFF);
}
}

View File

@@ -265,7 +265,7 @@ final class HotplugDetectionAction extends HdmiCecFeatureAction {
// Turn off system audio mode and update settings.
tv().setSystemAudioMode(false, true);
if (tv().isArcEstablished()) {
tv().setAudioReturnChannel(false);
tv().enableAudioReturnChannel(false);
addAndStartAction(new RequestArcTerminationAction(localDevice(), address));
}
}

View File

@@ -22,8 +22,8 @@ import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDIN
import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE;
import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.util.Slog;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
/**
@@ -62,7 +62,7 @@ public class OneTouchRecordAction extends HdmiCecFeatureAction {
@Override
public void onSendCompleted(int error) {
// if failed to send <Record On>, display error message and finish action.
if (error != Constants.SEND_RESULT_SUCCESS) {
if (error != SendMessageResult.SUCCESS) {
tv().announceOneTouchRecordResult(
mRecorderAddress,
ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION);

View File

@@ -18,10 +18,9 @@ package com.android.server.hdmi;
import static android.hardware.hdmi.HdmiControlManager.POWER_STATUS_UNKNOWN;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.util.SparseIntArray;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
import java.util.List;
/**
@@ -123,7 +122,7 @@ public class PowerStatusMonitorAction extends HdmiCecFeatureAction {
public void onSendCompleted(int error) {
// If fails to send <Give Device Power Status>,
// update power status into UNKNOWN.
if (error != Constants.SEND_RESULT_SUCCESS) {
if (error != SendMessageResult.SUCCESS) {
updatePowerStatus(logicalAddress, POWER_STATUS_UNKNOWN, true);
}
}

View File

@@ -16,6 +16,8 @@
package com.android.server.hdmi;
import android.hardware.tv.cec.V1_0.SendMessageResult;
/**
* Feature action that handles ARC action initiated by TV devices.
*
@@ -44,7 +46,7 @@ final class RequestArcInitiationAction extends RequestArcAction {
sendCommand(command, new HdmiControlService.SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
if (error != Constants.SEND_RESULT_SUCCESS) {
if (error != SendMessageResult.SUCCESS) {
// Turn off ARC status if <Request ARC Initiation> fails.
tv().setArcStatus(false);
finish();

View File

@@ -16,6 +16,8 @@
package com.android.server.hdmi;
import android.hardware.tv.cec.V1_0.SendMessageResult;
/**
* Feature action to handle <Request ARC Termination>.
*
@@ -43,7 +45,7 @@ final class RequestArcTerminationAction extends RequestArcAction {
sendCommand(command, new HdmiControlService.SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
if (error != Constants.SEND_RESULT_SUCCESS) {
if (error != SendMessageResult.SUCCESS) {
// If failed to send <Request ARC Termination>, start "Disabled" ARC
// transmission action.
disableArcTransmission();

View File

@@ -17,6 +17,7 @@
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.util.Slog;
/**
@@ -81,14 +82,14 @@ final class SetArcTransmissionStateAction extends HdmiCecFeatureAction {
@Override
public void onSendCompleted(int error) {
switch (error) {
case Constants.SEND_RESULT_SUCCESS:
case Constants.SEND_RESULT_BUSY:
case Constants.SEND_RESULT_FAILURE:
case SendMessageResult.SUCCESS:
case SendMessageResult.BUSY:
case SendMessageResult.FAIL:
// The result of the command transmission, unless it is an obvious
// failure indicated by the target device (or lack thereof), should
// not affect the ARC status. Ignores it silently.
break;
case Constants.SEND_RESULT_NAK:
case SendMessageResult.NACK:
// If <Report ARC Initiated> is negatively ack'ed, disable ARC and
// send <Report ARC Terminated> directly.
setArcStatus(false);

View File

@@ -17,12 +17,12 @@
package com.android.server.hdmi;
import android.annotation.Nullable;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.os.RemoteException;
import android.util.Slog;
import java.util.List;
/**
@@ -96,7 +96,7 @@ abstract class SystemAudioAction extends HdmiCecFeatureAction {
sendCommand(command, new HdmiControlService.SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
if (error != Constants.SEND_RESULT_SUCCESS) {
if (error != SendMessageResult.SUCCESS) {
HdmiLogger.debug("Failed to send <System Audio Mode Request>:" + error);
setSystemAudioMode(false);
finishWithCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED);

View File

@@ -16,6 +16,7 @@
package com.android.server.hdmi;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
/**
@@ -48,7 +49,7 @@ final class SystemAudioAutoInitiationAction extends HdmiCecFeatureAction {
mAvrAddress), new SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
if (error != Constants.SEND_RESULT_SUCCESS) {
if (error != SendMessageResult.SUCCESS) {
tv().setSystemAudioMode(false, true);
finish();
}

View File

@@ -19,9 +19,9 @@ package com.android.server.hdmi;
import android.annotation.Nullable;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.os.RemoteException;
import android.util.Slog;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
/**
@@ -56,7 +56,7 @@ final class SystemAudioStatusAction extends HdmiCecFeatureAction {
new SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
if (error != Constants.SEND_RESULT_SUCCESS) {
if (error != SendMessageResult.SUCCESS) {
handleSendGiveAudioStatusFailure();
}
}

View File

@@ -22,10 +22,9 @@ import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_ANAL
import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL;
import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL;
import android.hardware.tv.cec.V1_0.SendMessageResult;
import android.util.Slog;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
import java.util.Arrays;
/**
@@ -82,7 +81,7 @@ public class TimerRecordingAction extends HdmiCecFeatureAction {
sendCommand(message, new SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
if (error != Constants.SEND_RESULT_SUCCESS) {
if (error != SendMessageResult.SUCCESS) {
tv().announceTimerRecordingResult(mRecorderAddress,
TIMER_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION);
finish();

View File

@@ -67,10 +67,11 @@ LOCAL_SHARED_LIBRARIES += \
libhidl \
libhwbinder \
libutils \
android.hardware.power@1.0 \
android.hardware.vibrator@1.0 \
android.hardware.light@2.0 \
android.hardware.vr@1.0 \
android.hardware.audio.common@2.0 \
android.hardware.tv.input@1.0 \
android.hardware.light@2.0 \
android.hardware.power@1.0 \
android.hardware.thermal@1.0 \
android.hardware.tv.cec@1.0 \
android.hardware.tv.input@1.0 \
android.hardware.vibrator@1.0 \
android.hardware.vr@1.0 \

View File

@@ -21,16 +21,32 @@
#include <JNIHelp.h>
#include <ScopedPrimitiveArray.h>
#include <cstring>
#include <android/hardware/tv/cec/1.0/IHdmiCec.h>
#include <android/hardware/tv/cec/1.0/IHdmiCecCallback.h>
#include <android/hardware/tv/cec/1.0/types.h>
#include <android_os_MessageQueue.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
#include <hardware/hdmi_cec.h>
#include <sys/param.h>
#include <utils/Errors.h>
#include <utils/Looper.h>
#include <utils/RefBase.h>
using ::android::hardware::tv::cec::V1_0::CecLogicalAddress;
using ::android::hardware::tv::cec::V1_0::CecMessage;
using ::android::hardware::tv::cec::V1_0::HdmiPortInfo;
using ::android::hardware::tv::cec::V1_0::HotplugEvent;
using ::android::hardware::tv::cec::V1_0::IHdmiCec;
using ::android::hardware::tv::cec::V1_0::IHdmiCecCallback;
using ::android::hardware::tv::cec::V1_0::MaxLength;
using ::android::hardware::tv::cec::V1_0::OptionKey;
using ::android::hardware::tv::cec::V1_0::Result;
using ::android::hardware::tv::cec::V1_0::SendMessageResult;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
namespace android {
static struct {
@@ -40,15 +56,13 @@ static struct {
class HdmiCecController {
public:
HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj,
const sp<Looper>& looper);
void init();
HdmiCecController(sp<IHdmiCec> hdmiCec, jobject callbacksObj, const sp<Looper>& looper);
~HdmiCecController();
// Send message to other device. Note that it runs in IO thread.
int sendMessage(const cec_message_t& message);
int sendMessage(const CecMessage& message);
// Add a logical address to device.
int addLogicalAddress(cec_logical_address_t address);
int addLogicalAddress(CecLogicalAddress address);
// Clear all logical address registered to the device.
void clearLogicaladdress();
// Get physical address of device.
@@ -59,10 +73,12 @@ public:
uint32_t getVendorId();
// Get Port information on all the HDMI ports.
jobjectArray getPortInfos();
// Set a flag and its value.
void setOption(int flag, int value);
// Set audio return channel status.
void setAudioReturnChannel(int port, bool flag);
// Set an option to CEC HAL.
void setOption(OptionKey key, bool enabled);
// Informs CEC HAL about the current system language.
void setLanguage(hidl_string language);
// Enable audio return channel.
void enableAudioReturnChannel(int port, bool flag);
// Whether to hdmi device is connected to the given port.
bool isConnected(int port);
@@ -71,69 +87,48 @@ public:
}
private:
class HdmiCecCallback : public IHdmiCecCallback {
public:
HdmiCecCallback(HdmiCecController* controller) : mController(controller) {};
Return<void> onCecMessage(const CecMessage& event) override;
Return<void> onHotplugEvent(const HotplugEvent& event) override;
private:
HdmiCecController* mController;
};
static const int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
static void onReceived(const hdmi_event_t* event, void* arg);
hdmi_cec_device_t* mDevice;
sp<IHdmiCec> mHdmiCec;
jobject mCallbacksObj;
sp<IHdmiCecCallback> mHdmiCecCallback;
sp<Looper> mLooper;
};
// RefBase wrapper for hdmi_event_t. As hdmi_event_t coming from HAL
// may keep its own lifetime, we need to copy it in order to delegate
// it to service thread.
class CecEventWrapper : public LightRefBase<CecEventWrapper> {
public:
explicit CecEventWrapper(const hdmi_event_t& event) {
// Copy message.
switch (event.type) {
case HDMI_EVENT_CEC_MESSAGE:
mEvent.cec.initiator = event.cec.initiator;
mEvent.cec.destination = event.cec.destination;
mEvent.cec.length = event.cec.length;
std::memcpy(mEvent.cec.body, event.cec.body, event.cec.length);
break;
case HDMI_EVENT_HOT_PLUG:
mEvent.hotplug.connected = event.hotplug.connected;
mEvent.hotplug.port_id = event.hotplug.port_id;
break;
default:
// TODO: add more type whenever new type is introduced.
break;
}
}
const cec_message_t& cec() const {
return mEvent.cec;
}
const hotplug_event_t& hotplug() const {
return mEvent.hotplug;
}
virtual ~CecEventWrapper() {}
private:
hdmi_event_t mEvent;
};
// Handler class to delegate incoming message to service thread.
class HdmiCecEventHandler : public MessageHandler {
public:
HdmiCecEventHandler(HdmiCecController* controller, const sp<CecEventWrapper>& event)
: mController(controller),
mEventWrapper(event) {
}
enum EventType {
CEC_MESSAGE,
HOT_PLUG
};
HdmiCecEventHandler(HdmiCecController* controller, const CecMessage& cecMessage)
: mController(controller),
mCecMessage(cecMessage) {}
HdmiCecEventHandler(HdmiCecController* controller, const HotplugEvent& hotplugEvent)
: mController(controller),
mHotplugEvent(hotplugEvent) {}
virtual ~HdmiCecEventHandler() {}
void handleMessage(const Message& message) {
switch (message.what) {
case HDMI_EVENT_CEC_MESSAGE:
propagateCecCommand(mEventWrapper->cec());
case EventType::CEC_MESSAGE:
propagateCecCommand(mCecMessage);
break;
case HDMI_EVENT_HOT_PLUG:
propagateHotplugEvent(mEventWrapper->hotplug());
case EventType::HOT_PLUG:
propagateHotplugEvent(mHotplugEvent);
break;
default:
// TODO: add more type whenever new type is introduced.
@@ -143,14 +138,13 @@ public:
private:
// Propagate the message up to Java layer.
void propagateCecCommand(const cec_message_t& message) {
jint srcAddr = message.initiator;
jint dstAddr = message.destination;
void propagateCecCommand(const CecMessage& message) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
jbyteArray body = env->NewByteArray(message.length);
const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body);
env->SetByteArrayRegion(body, 0, message.length, bodyPtr);
jint srcAddr = static_cast<jint>(message.initiator);
jint dstAddr = static_cast<jint>(message.destination);
jbyteArray body = env->NewByteArray(message.body.size());
const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body.data());
env->SetByteArrayRegion(body, 0, message.body.size(), bodyPtr);
env->CallVoidMethod(mController->getCallbacksObj(),
gHdmiCecControllerClassInfo.handleIncomingCecCommand, srcAddr,
dstAddr, body);
@@ -159,10 +153,10 @@ private:
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
void propagateHotplugEvent(const hotplug_event_t& event) {
void propagateHotplugEvent(const HotplugEvent& event) {
// Note that this method should be called in service thread.
JNIEnv* env = AndroidRuntime::getJNIEnv();
jint port = event.port_id;
jint port = static_cast<jint>(event.portId);
jboolean connected = (jboolean) event.connected;
env->CallVoidMethod(mController->getCallbacksObj(),
gHdmiCecControllerClassInfo.handleHotplug, port, connected);
@@ -180,51 +174,83 @@ private:
}
HdmiCecController* mController;
sp<CecEventWrapper> mEventWrapper;
CecMessage mCecMessage;
HotplugEvent mHotplugEvent;
};
HdmiCecController::HdmiCecController(hdmi_cec_device_t* device,
jobject callbacksObj, const sp<Looper>& looper) :
mDevice(device),
mCallbacksObj(callbacksObj),
mLooper(looper) {
HdmiCecController::HdmiCecController(sp<IHdmiCec> hdmiCec,
jobject callbacksObj, const sp<Looper>& looper)
: mHdmiCec(hdmiCec),
mCallbacksObj(callbacksObj),
mLooper(looper) {
mHdmiCecCallback = new HdmiCecCallback(this);
Return<void> ret = mHdmiCec->setCallback(mHdmiCecCallback);
if (!ret.getStatus().isOk()) {
ALOGE("Failed to set a cec callback.");
}
}
void HdmiCecController::init() {
mDevice->register_event_callback(mDevice, HdmiCecController::onReceived, this);
HdmiCecController::~HdmiCecController() {
Return<void> ret = mHdmiCec->setCallback(nullptr);
if (!ret.getStatus().isOk()) {
ALOGE("Failed to set a cec callback.");
}
}
int HdmiCecController::sendMessage(const cec_message_t& message) {
int HdmiCecController::sendMessage(const CecMessage& message) {
// TODO: propagate send_message's return value.
return mDevice->send_message(mDevice, &message);
Return<SendMessageResult> ret = mHdmiCec->sendMessage(message);
if (!ret.getStatus().isOk()) {
ALOGE("Failed to send CEC message.");
return static_cast<int>(SendMessageResult::FAIL);
}
return static_cast<int>((SendMessageResult) ret);
}
int HdmiCecController::addLogicalAddress(cec_logical_address_t address) {
return mDevice->add_logical_address(mDevice, address);
int HdmiCecController::addLogicalAddress(CecLogicalAddress address) {
Return<Result> ret = mHdmiCec->addLogicalAddress(address);
if (!ret.getStatus().isOk()) {
ALOGE("Failed to add a logical address.");
return static_cast<int>(Result::FAILURE_UNKNOWN);
}
return static_cast<int>((Result) ret);
}
void HdmiCecController::clearLogicaladdress() {
mDevice->clear_logical_address(mDevice);
Return<void> ret = mHdmiCec->clearLogicalAddress();
if (!ret.getStatus().isOk()) {
ALOGE("Failed to clear logical address.");
}
}
int HdmiCecController::getPhysicalAddress() {
Result result;
uint16_t addr;
if (!mDevice->get_physical_address(mDevice, &addr)) {
return addr;
Return<void> ret = mHdmiCec->getPhysicalAddress([&result, &addr](Result res, uint16_t paddr) {
result = res;
addr = paddr;
});
if (!ret.getStatus().isOk()) {
ALOGE("Failed to get physical address.");
return INVALID_PHYSICAL_ADDRESS;
}
return INVALID_PHYSICAL_ADDRESS;
return result == Result::SUCCESS ? addr : INVALID_PHYSICAL_ADDRESS;
}
int HdmiCecController::getVersion() {
int version = 0;
mDevice->get_version(mDevice, &version);
return version;
Return<int32_t> ret = mHdmiCec->getCecVersion();
if (!ret.getStatus().isOk()) {
ALOGE("Failed to get cec version.");
}
return ret;
}
uint32_t HdmiCecController::getVendorId() {
uint32_t vendorId = 0;
mDevice->get_vendor_id(mDevice, &vendorId);
return vendorId;
Return<uint32_t> ret = mHdmiCec->getVendorId();
if (!ret.getStatus().isOk()) {
ALOGE("Failed to get vendor id.");
}
return ret;
}
jobjectArray HdmiCecController::getPortInfos() {
@@ -237,48 +263,69 @@ jobjectArray HdmiCecController::getPortInfos() {
if (ctor == NULL) {
return NULL;
}
hdmi_port_info* ports;
int numPorts;
mDevice->get_port_info(mDevice, &ports, &numPorts);
jobjectArray res = env->NewObjectArray(numPorts, hdmiPortInfo, NULL);
hidl_vec<HdmiPortInfo> ports;
Return<void> ret = mHdmiCec->getPortInfo([&ports](hidl_vec<HdmiPortInfo> list) {
ports = list;
});
if (!ret.getStatus().isOk()) {
ALOGE("Failed to get port information.");
return NULL;
}
jobjectArray res = env->NewObjectArray(ports.size(), hdmiPortInfo, NULL);
// MHL support field will be obtained from MHL HAL. Leave it to false.
jboolean mhlSupported = (jboolean) 0;
for (int i = 0; i < numPorts; ++i) {
hdmi_port_info* info = &ports[i];
jboolean cecSupported = (jboolean) info->cec_supported;
jboolean arcSupported = (jboolean) info->arc_supported;
jobject infoObj = env->NewObject(hdmiPortInfo, ctor, info->port_id, info->type,
info->physical_address, cecSupported, mhlSupported, arcSupported);
for (size_t i = 0; i < ports.size(); ++i) {
jboolean cecSupported = (jboolean) ports[i].cecSupported;
jboolean arcSupported = (jboolean) ports[i].arcSupported;
jobject infoObj = env->NewObject(hdmiPortInfo, ctor, ports[i].portId, ports[i].type,
ports[i].physicalAddress, cecSupported, mhlSupported, arcSupported);
env->SetObjectArrayElement(res, i, infoObj);
}
return res;
}
void HdmiCecController::setOption(int flag, int value) {
mDevice->set_option(mDevice, flag, value);
void HdmiCecController::setOption(OptionKey key, bool enabled) {
Return<void> ret = mHdmiCec->setOption(key, enabled);
if (!ret.getStatus().isOk()) {
ALOGE("Failed to set option.");
}
}
// Set audio return channel status.
void HdmiCecController::setAudioReturnChannel(int port, bool enabled) {
mDevice->set_audio_return_channel(mDevice, port, enabled ? 1 : 0);
void HdmiCecController::setLanguage(hidl_string language) {
Return<void> ret = mHdmiCec->setLanguage(language);
if (!ret.getStatus().isOk()) {
ALOGE("Failed to set language.");
}
}
// Enable audio return channel.
void HdmiCecController::enableAudioReturnChannel(int port, bool enabled) {
Return<void> ret = mHdmiCec->enableAudioReturnChannel(port, enabled);
if (!ret.getStatus().isOk()) {
ALOGE("Failed to enable/disable ARC.");
}
}
// Whether to hdmi device is connected to the given port.
bool HdmiCecController::isConnected(int port) {
return mDevice->is_connected(mDevice, port) == HDMI_CONNECTED;
Return<bool> ret = mHdmiCec->isConnected(port);
if (!ret.getStatus().isOk()) {
ALOGE("Failed to get connection info.");
}
return ret;
}
// static
void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) {
HdmiCecController* controller = static_cast<HdmiCecController*>(arg);
if (controller == NULL) {
return;
}
Return<void> HdmiCecController::HdmiCecCallback::onCecMessage(const CecMessage& message) {
sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(mController, message));
mController->mLooper->sendMessage(handler, HdmiCecEventHandler::EventType::CEC_MESSAGE);
return Void();
}
sp<CecEventWrapper> spEvent(new CecEventWrapper(*event));
sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(controller, spEvent));
controller->mLooper->sendMessage(handler, event->type);
Return<void> HdmiCecController::HdmiCecCallback::onHotplugEvent(const HotplugEvent& event) {
sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(mController, event));
mController->mLooper->sendMessage(handler, HdmiCecEventHandler::EventType::HOT_PLUG);
return Void();
}
//------------------------------------------------------------------------------
@@ -288,30 +335,19 @@ void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) {
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj,
jobject messageQueueObj) {
int err;
hw_module_t* module;
err = hw_get_module(HDMI_CEC_HARDWARE_MODULE_ID,
const_cast<const hw_module_t **>(&module));
if (err != 0) {
ALOGE("Error acquiring hardware module: %d", err);
// TODO(b/31632518)
sp<IHdmiCec> hdmiCec = IHdmiCec::getService("tv.cec");
if (hdmiCec == nullptr) {
ALOGE("Couldn't get tv.cec service.");
return 0;
}
hw_device_t* device;
err = module->methods->open(module, HDMI_CEC_HARDWARE_INTERFACE, &device);
if (err != 0) {
ALOGE("Error opening hardware module: %d", err);
return 0;
}
sp<MessageQueue> messageQueue =
android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
HdmiCecController* controller = new HdmiCecController(
reinterpret_cast<hdmi_cec_device*>(device),
hdmiCec,
env->NewGlobalRef(callbacksObj),
messageQueue->getLooper());
controller->init();
GET_METHOD_ID(gHdmiCecControllerClassInfo.handleIncomingCecCommand, clazz,
"handleIncomingCecCommand", "(II[B)V");
@@ -323,14 +359,18 @@ static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj,
static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr,
jint srcAddr, jint dstAddr, jbyteArray body) {
cec_message_t message;
message.initiator = static_cast<cec_logical_address_t>(srcAddr);
message.destination = static_cast<cec_logical_address_t>(dstAddr);
CecMessage message;
message.initiator = static_cast<CecLogicalAddress>(srcAddr);
message.destination = static_cast<CecLogicalAddress>(dstAddr);
jsize len = env->GetArrayLength(body);
message.length = MIN(len, CEC_MESSAGE_BODY_MAX_LENGTH);
ScopedByteArrayRO bodyPtr(env, body);
std::memcpy(message.body, bodyPtr.get(), message.length);
size_t bodyLength = MIN(static_cast<size_t>(len),
static_cast<size_t>(MaxLength::MESSAGE_BODY));
message.body.resize(bodyLength);
for (size_t i = 0; i < bodyLength; ++i) {
message.body[i] = static_cast<uint8_t>(bodyPtr[i]);
}
HdmiCecController* controller =
reinterpret_cast<HdmiCecController*>(controllerPtr);
@@ -340,7 +380,7 @@ static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr,
static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr,
jint logicalAddress) {
HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
return controller->addLogicalAddress(static_cast<cec_logical_address_t>(logicalAddress));
return controller->addLogicalAddress(static_cast<CecLogicalAddress>(logicalAddress));
}
static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) {
@@ -370,13 +410,20 @@ static jobjectArray nativeGetPortInfos(JNIEnv* env, jclass clazz, jlong controll
static void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag, jint value) {
HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
controller->setOption(flag, value);
controller->setOption(static_cast<OptionKey>(flag), value > 0 ? true : false);
}
static void nativeSetAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr,
static void nativeSetLanguage(JNIEnv* env, jclass clazz, jlong controllerPtr, jstring language) {
HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
const char *languageStr = env->GetStringUTFChars(language, NULL);
controller->setLanguage(languageStr);
env->ReleaseStringUTFChars(language, languageStr);
}
static void nativeEnableAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr,
jint port, jboolean enabled) {
HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr);
controller->setAudioReturnChannel(port, enabled == JNI_TRUE);
controller->enableAudioReturnChannel(port, enabled == JNI_TRUE);
}
static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port) {
@@ -398,8 +445,9 @@ static const JNINativeMethod sMethods[] = {
{ "nativeGetPortInfos",
"(J)[Landroid/hardware/hdmi/HdmiPortInfo;",
(void *) nativeGetPortInfos },
{ "nativeSetOption", "(JII)V", (void *) nativeSetOption },
{ "nativeSetAudioReturnChannel", "(JIZ)V", (void *) nativeSetAudioReturnChannel },
{ "nativeSetOption", "(JIZ)V", (void *) nativeSetOption },
{ "nativeSetLanguage", "(JLjava/lang/String;)V", (void *) nativeSetLanguage },
{ "nativeEnableAudioReturnChannel", "(JIZ)V", (void *) nativeEnableAudioReturnChannel },
{ "nativeIsConnected", "(JI)Z", (void *) nativeIsConnected },
};