Merge "CEC: Change vendor command handling" am: 134f59f851
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1807376 Change-Id: Ia4d1dda5058b8fa8ec452a3556cf5b76cf7f642e
This commit is contained in:
@@ -2954,6 +2954,7 @@ package android.hardware.hdmi {
|
|||||||
method public void sendKeyEvent(int, boolean);
|
method public void sendKeyEvent(int, boolean);
|
||||||
method public void sendVendorCommand(int, byte[], boolean);
|
method public void sendVendorCommand(int, byte[], boolean);
|
||||||
method public void setVendorCommandListener(@NonNull android.hardware.hdmi.HdmiControlManager.VendorCommandListener);
|
method public void setVendorCommandListener(@NonNull android.hardware.hdmi.HdmiControlManager.VendorCommandListener);
|
||||||
|
method public void setVendorCommandListener(@NonNull android.hardware.hdmi.HdmiControlManager.VendorCommandListener, int);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class HdmiControlManager {
|
public final class HdmiControlManager {
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import android.util.Log;
|
|||||||
public abstract class HdmiClient {
|
public abstract class HdmiClient {
|
||||||
private static final String TAG = "HdmiClient";
|
private static final String TAG = "HdmiClient";
|
||||||
|
|
||||||
|
private static final int UNKNOWN_VENDOR_ID = 0xFFFFFF;
|
||||||
|
|
||||||
/* package */ final IHdmiControlService mService;
|
/* package */ final IHdmiControlService mService;
|
||||||
|
|
||||||
private IHdmiVendorCommandListener mIHdmiVendorCommandListener;
|
private IHdmiVendorCommandListener mIHdmiVendorCommandListener;
|
||||||
@@ -94,11 +96,25 @@ public abstract class HdmiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a listener used to receive incoming vendor-specific command.
|
* Sets a listener used to receive incoming vendor-specific command. This listener will only
|
||||||
|
* receive {@code <Vendor Command>} but will not receive any {@code <Vendor Command with ID>}
|
||||||
|
* messages.
|
||||||
*
|
*
|
||||||
* @param listener listener object
|
* @param listener listener object
|
||||||
*/
|
*/
|
||||||
public void setVendorCommandListener(@NonNull VendorCommandListener listener) {
|
public void setVendorCommandListener(@NonNull VendorCommandListener listener) {
|
||||||
|
// Set the vendor ID to INVALID_VENDOR_ID.
|
||||||
|
setVendorCommandListener(listener, UNKNOWN_VENDOR_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a listener used to receive incoming vendor-specific command.
|
||||||
|
*
|
||||||
|
* @param listener listener object
|
||||||
|
* @param vendorId The listener is interested in {@code <Vendor Command with ID>} received with
|
||||||
|
* this vendorId and all {@code <Vendor Command>} messages.
|
||||||
|
*/
|
||||||
|
public void setVendorCommandListener(@NonNull VendorCommandListener listener, int vendorId) {
|
||||||
if (listener == null) {
|
if (listener == null) {
|
||||||
throw new IllegalArgumentException("listener cannot be null");
|
throw new IllegalArgumentException("listener cannot be null");
|
||||||
}
|
}
|
||||||
@@ -107,7 +123,7 @@ public abstract class HdmiClient {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
IHdmiVendorCommandListener wrappedListener = getListenerWrapper(listener);
|
IHdmiVendorCommandListener wrappedListener = getListenerWrapper(listener);
|
||||||
mService.addVendorCommandListener(wrappedListener, getDeviceType());
|
mService.addVendorCommandListener(wrappedListener, vendorId);
|
||||||
mIHdmiVendorCommandListener = wrappedListener;
|
mIHdmiVendorCommandListener = wrappedListener;
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "failed to set vendor command listener: ", e);
|
Log.e(TAG, "failed to set vendor command listener: ", e);
|
||||||
|
|||||||
@@ -221,8 +221,8 @@ public final class HdmiControlServiceWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {
|
public void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId) {
|
||||||
HdmiControlServiceWrapper.this.addVendorCommandListener(listener, deviceType);
|
HdmiControlServiceWrapper.this.addVendorCommandListener(listener, vendorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -471,7 +471,7 @@ public final class HdmiControlServiceWrapper {
|
|||||||
boolean hasVendorId) {}
|
boolean hasVendorId) {}
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {}
|
public void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId) {}
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public void sendStandby(int deviceType, int deviceId) {}
|
public void sendStandby(int deviceType, int deviceId) {}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ interface IHdmiControlService {
|
|||||||
void askRemoteDeviceToBecomeActiveSource(int physicalAddress);
|
void askRemoteDeviceToBecomeActiveSource(int physicalAddress);
|
||||||
void sendVendorCommand(int deviceType, int targetAddress, in byte[] params,
|
void sendVendorCommand(int deviceType, int targetAddress, in byte[] params,
|
||||||
boolean hasVendorId);
|
boolean hasVendorId);
|
||||||
void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType);
|
void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId);
|
||||||
void sendStandby(int deviceType, int deviceId);
|
void sendStandby(int deviceType, int deviceId);
|
||||||
void setHdmiRecordListener(IHdmiRecordListener callback);
|
void setHdmiRecordListener(IHdmiRecordListener callback);
|
||||||
void startOneTouchRecord(int recorderAddress, in byte[] recordSource);
|
void startOneTouchRecord(int recorderAddress, in byte[] recordSource);
|
||||||
|
|||||||
@@ -288,9 +288,8 @@ public class HdmiAudioSystemClientTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addVendorCommandListener(final IHdmiVendorCommandListener listener,
|
public void addVendorCommandListener(
|
||||||
final int deviceType) {
|
final IHdmiVendorCommandListener listener, final int vendorId) {}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendVendorCommand(final int deviceType, final int targetAddress,
|
public void sendVendorCommand(final int deviceType, final int targetAddress,
|
||||||
|
|||||||
@@ -829,17 +829,12 @@ abstract class HdmiCecLocalDevice {
|
|||||||
protected int handleVendorCommandWithId(HdmiCecMessage message) {
|
protected int handleVendorCommandWithId(HdmiCecMessage message) {
|
||||||
byte[] params = message.getParams();
|
byte[] params = message.getParams();
|
||||||
int vendorId = HdmiUtils.threeBytesToInt(params);
|
int vendorId = HdmiUtils.threeBytesToInt(params);
|
||||||
if (vendorId == mService.getVendorId()) {
|
if (message.getDestination() == Constants.ADDR_BROADCAST
|
||||||
if (!mService.invokeVendorCommandListenersOnReceived(
|
|| message.getSource() == Constants.ADDR_UNREGISTERED) {
|
||||||
mDeviceType, message.getSource(), message.getDestination(), params, true)) {
|
|
||||||
return Constants.ABORT_REFUSED;
|
|
||||||
}
|
|
||||||
} else if (message.getDestination() != Constants.ADDR_BROADCAST
|
|
||||||
&& message.getSource() != Constants.ADDR_UNREGISTERED) {
|
|
||||||
Slog.v(TAG, "Wrong direct vendor command. Replying with <Feature Abort>");
|
|
||||||
return Constants.ABORT_UNRECOGNIZED_OPCODE;
|
|
||||||
} else {
|
|
||||||
Slog.v(TAG, "Wrong broadcast vendor command. Ignoring");
|
Slog.v(TAG, "Wrong broadcast vendor command. Ignoring");
|
||||||
|
} else if (!mService.invokeVendorCommandListenersOnReceived(
|
||||||
|
mDeviceType, message.getSource(), message.getDestination(), params, true)) {
|
||||||
|
return Constants.ABORT_REFUSED;
|
||||||
}
|
}
|
||||||
return Constants.HANDLED;
|
return Constants.HANDLED;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1582,11 +1582,11 @@ public class HdmiControlService extends SystemService {
|
|||||||
|
|
||||||
class VendorCommandListenerRecord implements IBinder.DeathRecipient {
|
class VendorCommandListenerRecord implements IBinder.DeathRecipient {
|
||||||
private final IHdmiVendorCommandListener mListener;
|
private final IHdmiVendorCommandListener mListener;
|
||||||
private final int mDeviceType;
|
private final int mVendorId;
|
||||||
|
|
||||||
public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) {
|
VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int vendorId) {
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
mDeviceType = deviceType;
|
mVendorId = vendorId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -2077,10 +2077,10 @@ public class HdmiControlService extends SystemService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addVendorCommandListener(final IHdmiVendorCommandListener listener,
|
public void addVendorCommandListener(
|
||||||
final int deviceType) {
|
final IHdmiVendorCommandListener listener, final int vendorId) {
|
||||||
initBinderCall();
|
initBinderCall();
|
||||||
HdmiControlService.this.addVendorCommandListener(listener, deviceType);
|
HdmiControlService.this.addVendorCommandListener(listener, vendorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -3219,8 +3219,9 @@ public class HdmiControlService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {
|
@VisibleForTesting
|
||||||
VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType);
|
void addVendorCommandListener(IHdmiVendorCommandListener listener, int vendorId) {
|
||||||
|
VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, vendorId);
|
||||||
try {
|
try {
|
||||||
listener.asBinder().linkToDeath(record, 0);
|
listener.asBinder().linkToDeath(record, 0);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
@@ -3239,8 +3240,14 @@ public class HdmiControlService extends SystemService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) {
|
for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) {
|
||||||
if (record.mDeviceType != deviceType) {
|
if (hasVendorId) {
|
||||||
continue;
|
int vendorId =
|
||||||
|
((params[0] & 0xFF) << 16)
|
||||||
|
+ ((params[1] & 0xFF) << 8)
|
||||||
|
+ (params[2] & 0xFF);
|
||||||
|
if (record.mVendorId != vendorId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId);
|
record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import android.hardware.hdmi.HdmiControlManager;
|
|||||||
import android.hardware.hdmi.HdmiPortInfo;
|
import android.hardware.hdmi.HdmiPortInfo;
|
||||||
import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
|
import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
|
||||||
import android.hardware.hdmi.IHdmiControlStatusChangeListener;
|
import android.hardware.hdmi.IHdmiControlStatusChangeListener;
|
||||||
|
import android.hardware.hdmi.IHdmiVendorCommandListener;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.IPowerManager;
|
import android.os.IPowerManager;
|
||||||
import android.os.IThermalService;
|
import android.os.IThermalService;
|
||||||
@@ -885,6 +886,114 @@ public class HdmiControlServiceTest {
|
|||||||
.isEqualTo(Constants.ABORT_REFUSED);
|
.isEqualTo(Constants.ABORT_REFUSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addVendorCommandListener_receiveCallback_VendorCmdNoIdTest() {
|
||||||
|
int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress();
|
||||||
|
int sourceAddress = Constants.ADDR_TV;
|
||||||
|
byte[] params = {0x00, 0x01, 0x02, 0x03};
|
||||||
|
int vendorId = 0x123456;
|
||||||
|
|
||||||
|
VendorCommandListener vendorCmdListener =
|
||||||
|
new VendorCommandListener(sourceAddress, destAddress, params, vendorId);
|
||||||
|
mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
|
||||||
|
HdmiCecMessage vendorCommandNoId =
|
||||||
|
HdmiCecMessageBuilder.buildVendorCommand(sourceAddress, destAddress, params);
|
||||||
|
mNativeWrapper.onCecMessage(vendorCommandNoId);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isTrue();
|
||||||
|
assertThat(vendorCmdListener.mParamsCorrect).isTrue();
|
||||||
|
assertThat(vendorCmdListener.mHasVendorId).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addVendorCommandListener_receiveCallback_VendorCmdWithIdTest() {
|
||||||
|
int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress();
|
||||||
|
int sourceAddress = Constants.ADDR_TV;
|
||||||
|
byte[] params = {0x00, 0x01, 0x02, 0x03};
|
||||||
|
int vendorId = 0x123456;
|
||||||
|
|
||||||
|
VendorCommandListener vendorCmdListener =
|
||||||
|
new VendorCommandListener(sourceAddress, destAddress, params, vendorId);
|
||||||
|
mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
|
||||||
|
HdmiCecMessage vendorCommandWithId =
|
||||||
|
HdmiCecMessageBuilder.buildVendorCommandWithId(
|
||||||
|
sourceAddress, destAddress, vendorId, params);
|
||||||
|
mNativeWrapper.onCecMessage(vendorCommandWithId);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isTrue();
|
||||||
|
assertThat(vendorCmdListener.mParamsCorrect).isTrue();
|
||||||
|
assertThat(vendorCmdListener.mHasVendorId).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addVendorCommandListener_noCallback_VendorCmdDiffIdTest() {
|
||||||
|
int destAddress = mHdmiControlServiceSpy.playback().getDeviceInfo().getLogicalAddress();
|
||||||
|
int sourceAddress = Constants.ADDR_TV;
|
||||||
|
byte[] params = {0x00, 0x01, 0x02, 0x03};
|
||||||
|
int vendorId = 0x123456;
|
||||||
|
int diffVendorId = 0x345678;
|
||||||
|
|
||||||
|
VendorCommandListener vendorCmdListener =
|
||||||
|
new VendorCommandListener(sourceAddress, destAddress, params, vendorId);
|
||||||
|
mHdmiControlServiceSpy.addVendorCommandListener(vendorCmdListener, vendorId);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
|
||||||
|
HdmiCecMessage vendorCommandWithDiffId =
|
||||||
|
HdmiCecMessageBuilder.buildVendorCommandWithId(
|
||||||
|
sourceAddress, destAddress, diffVendorId, params);
|
||||||
|
mNativeWrapper.onCecMessage(vendorCommandWithDiffId);
|
||||||
|
mTestLooper.dispatchAll();
|
||||||
|
assertThat(vendorCmdListener.mVendorCommandCallbackReceived).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class VendorCommandListener extends IHdmiVendorCommandListener.Stub {
|
||||||
|
boolean mVendorCommandCallbackReceived = false;
|
||||||
|
boolean mParamsCorrect = false;
|
||||||
|
boolean mHasVendorId = false;
|
||||||
|
|
||||||
|
int mSourceAddress;
|
||||||
|
int mDestAddress;
|
||||||
|
byte[] mParams;
|
||||||
|
int mVendorId;
|
||||||
|
|
||||||
|
VendorCommandListener(int sourceAddress, int destAddress, byte[] params, int vendorId) {
|
||||||
|
this.mSourceAddress = sourceAddress;
|
||||||
|
this.mDestAddress = destAddress;
|
||||||
|
this.mParams = params.clone();
|
||||||
|
this.mVendorId = vendorId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceived(
|
||||||
|
int sourceAddress, int destAddress, byte[] params, boolean hasVendorId) {
|
||||||
|
mVendorCommandCallbackReceived = true;
|
||||||
|
if (mSourceAddress == sourceAddress && mDestAddress == destAddress) {
|
||||||
|
byte[] expectedParams;
|
||||||
|
if (hasVendorId) {
|
||||||
|
// If the command has vendor ID, we have to add it to mParams.
|
||||||
|
expectedParams = new byte[params.length];
|
||||||
|
expectedParams[0] = (byte) ((mVendorId >> 16) & 0xFF);
|
||||||
|
expectedParams[1] = (byte) ((mVendorId >> 8) & 0xFF);
|
||||||
|
expectedParams[2] = (byte) (mVendorId & 0xFF);
|
||||||
|
System.arraycopy(mParams, 0, expectedParams, 3, mParams.length);
|
||||||
|
} else {
|
||||||
|
expectedParams = params.clone();
|
||||||
|
}
|
||||||
|
if (Arrays.equals(expectedParams, params)) {
|
||||||
|
mParamsCorrect = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mHasVendorId = hasVendorId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onControlStateChanged(boolean enabled, int reason) {}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void dispatchMessageToLocalDevice_broadcastMessage_returnsHandled() {
|
public void dispatchMessageToLocalDevice_broadcastMessage_returnsHandled() {
|
||||||
HdmiCecMessage message = HdmiCecMessageBuilder.buildStandby(
|
HdmiCecMessage message = HdmiCecMessageBuilder.buildStandby(
|
||||||
|
|||||||
Reference in New Issue
Block a user