diff --git a/services/core/Android.bp b/services/core/Android.bp index 9f369101dd7c3..0725bb277e510 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -127,7 +127,7 @@ java_library_static { "android.hardware.health-V2.0-java", "android.hardware.health-V2.1-java", "android.hardware.light-V1-java", - "android.hardware.tv.cec-V1.0-java", + "android.hardware.tv.cec-V1.1-java", "android.hardware.weaver-V1.0-java", "android.hardware.biometrics.face-V1-java", "android.hardware.biometrics.face-V1.0-java", diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java index 06bcada84ff98..1643ec162bc2a 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecController.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java @@ -50,6 +50,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.NoSuchElementException; import java.util.concurrent.ArrayBlockingQueue; import java.util.function.Predicate; @@ -149,6 +150,12 @@ final class HdmiCecController { * returns {@code null}. */ static HdmiCecController create(HdmiControlService service, HdmiCecAtomWriter atomWriter) { + HdmiCecController controller = createWithNativeWrapper(service, new NativeWrapperImpl11(), + atomWriter); + if (controller != null) { + return controller; + } + HdmiLogger.warning("Unable to use cec@1.1"); return createWithNativeWrapper(service, new NativeWrapperImpl(), atomWriter); } @@ -312,7 +319,7 @@ final class HdmiCecController { } /** - * Return CEC version of the device. + * Return highest CEC version supported by this device. * *
Declared as package-private. accessed by {@link HdmiControlService} only.
*/
@@ -745,13 +752,202 @@ final class HdmiCecController {
boolean nativeIsConnected(int port);
}
- private static final class NativeWrapperImpl implements NativeWrapper,
+ private static final class NativeWrapperImpl11 implements NativeWrapper,
IHwBinder.DeathRecipient, getPhysicalAddressCallback {
- private IHdmiCec mHdmiCec;
+ private android.hardware.tv.cec.V1_1.IHdmiCec mHdmiCec;
+ @Nullable private HdmiCecCallback mCallback;
+
private final Object mLock = new Object();
private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
+
+ @Override
+ public String nativeInit() {
+ return (connectToHal() ? mHdmiCec.toString() : null);
+ }
+
+ boolean connectToHal() {
+ try {
+ mHdmiCec = android.hardware.tv.cec.V1_1.IHdmiCec.getService(true);
+ try {
+ mHdmiCec.linkToDeath(this, HDMI_CEC_HAL_DEATH_COOKIE);
+ } catch (RemoteException e) {
+ HdmiLogger.error("Couldn't link to death : ", e);
+ }
+ } catch (RemoteException | NoSuchElementException e) {
+ HdmiLogger.error("Couldn't connect to cec@1.1", e);
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void onValues(int result, short addr) {
+ if (result == Result.SUCCESS) {
+ synchronized (mLock) {
+ mPhysicalAddress = new Short(addr).intValue();
+ }
+ }
+ }
+
+ @Override
+ public void serviceDied(long cookie) {
+ if (cookie == HDMI_CEC_HAL_DEATH_COOKIE) {
+ HdmiLogger.error("Service died cookie : " + cookie + "; reconnecting");
+ connectToHal();
+ // Reconnect the callback
+ if (mCallback != null) {
+ setCallback(mCallback);
+ }
+ }
+ }
+
+ @Override
+ public void setCallback(HdmiCecCallback callback) {
+ mCallback = callback;
+ try {
+ mHdmiCec.setCallback_1_1(new HdmiCecCallback11(callback));
+ } catch (RemoteException e) {
+ HdmiLogger.error("Couldn't initialise tv.cec callback : ", e);
+ }
+ }
+
+ @Override
+ public int nativeSendCecCommand(int srcAddress, int dstAddress, byte[] body) {
+ android.hardware.tv.cec.V1_1.CecMessage message =
+ new android.hardware.tv.cec.V1_1.CecMessage();
+ message.initiator = srcAddress;
+ message.destination = dstAddress;
+ message.body = new ArrayList<>(body.length);
+ for (byte b : body) {
+ message.body.add(b);
+ }
+ try {
+ return mHdmiCec.sendMessage_1_1(message);
+ } catch (RemoteException e) {
+ HdmiLogger.error("Failed to send CEC message : ", e);
+ return SendMessageResult.FAIL;
+ }
+ }
+
+ @Override
+ public int nativeAddLogicalAddress(int logicalAddress) {
+ try {
+ return mHdmiCec.addLogicalAddress_1_1(logicalAddress);
+ } catch (RemoteException e) {
+ HdmiLogger.error("Failed to add a logical address : ", e);
+ return Result.FAILURE_INVALID_ARGS;
+ }
+ }
+
+ @Override
+ public void nativeClearLogicalAddress() {
+ try {
+ mHdmiCec.clearLogicalAddress();
+ } catch (RemoteException e) {
+ HdmiLogger.error("Failed to clear logical address : ", e);
+ }
+ }
+
+ @Override
+ public int nativeGetPhysicalAddress() {
+ try {
+ mHdmiCec.getPhysicalAddress(this);
+ return mPhysicalAddress;
+ } catch (RemoteException e) {
+ HdmiLogger.error("Failed to get physical address : ", e);
+ return INVALID_PHYSICAL_ADDRESS;
+ }
+ }
+
+ @Override
+ public int nativeGetVersion() {
+ try {
+ return mHdmiCec.getCecVersion();
+ } catch (RemoteException e) {
+ HdmiLogger.error("Failed to get cec version : ", e);
+ return Result.FAILURE_UNKNOWN;
+ }
+ }
+
+ @Override
+ public int nativeGetVendorId() {
+ try {
+ return mHdmiCec.getVendorId();
+ } catch (RemoteException e) {
+ HdmiLogger.error("Failed to get vendor id : ", e);
+ return Result.FAILURE_UNKNOWN;
+ }
+ }
+
+ @Override
+ public HdmiPortInfo[] nativeGetPortInfos() {
+ try {
+ ArrayList