CEC: Add a callback for vendor when HDMI control setting is changed.

- removed unregisterContentObserver() to reactivate the service later.
- added the parameter destAddress to onReceived() callback to
  distinguish whether the message is broadcast or not.

Bug: 17962624
Change-Id: I552d14661583f63bb66b07866092f972b259b15a
This commit is contained in:
Yuncheol Heo
2014-10-13 16:39:18 +09:00
parent 7a78e578d7
commit 0608b9328b
5 changed files with 89 additions and 23 deletions

View File

@@ -3,7 +3,6 @@ package android.hardware.hdmi;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.hardware.hdmi.HdmiControlManager.VendorCommandListener;
import android.hardware.hdmi.IHdmiVendorCommandListener;
import android.os.RemoteException;
import android.util.Log;
@@ -91,8 +90,13 @@ public abstract class HdmiClient {
final VendorCommandListener listener) {
return new IHdmiVendorCommandListener.Stub() {
@Override
public void onReceived(int srcAddress, byte[] params, boolean hasVendorId) {
listener.onReceived(srcAddress, params, hasVendorId);
public void onReceived(int srcAddress, int destAddress, byte[] params,
boolean hasVendorId) {
listener.onReceived(srcAddress, destAddress, params, hasVendorId);
}
@Override
public void onControlStateChanged(boolean enabled, int reason) {
listener.onControlStateChanged(enabled, reason);
}
};
}

View File

@@ -236,6 +236,15 @@ public final class HdmiControlManager {
/** Clear timer error - CEC is disabled. */
public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 0xA2;
/** The HdmiControlService is started. */
public static final int CONTROL_STATE_CHANGED_REASON_START = 0;
/** The state of HdmiControlService is changed by changing of settings. */
public static final int CONTROL_STATE_CHANGED_REASON_SETTING = 1;
/** The HdmiControlService is enabled to wake up. */
public static final int CONTROL_STATE_CHANGED_REASON_WAKEUP = 2;
/** The HdmiControlService will be disabled to standby. */
public static final int CONTROL_STATE_CHANGED_REASON_STANDBY = 3;
// True if we have a logical device of type playback hosted in the system.
private final boolean mHasPlaybackDevice;
// True if we have a logical device of type TV hosted in the system.
@@ -339,11 +348,29 @@ public final class HdmiControlManager {
* Called when a vendor command is received.
*
* @param srcAddress source logical address
* @param destAddress destination logical address
* @param params vendor-specific parameters
* @param hasVendorId {@code true} if the command is <Vendor Command
* With ID>. The first 3 bytes of params is vendor id.
*/
void onReceived(int srcAddress, byte[] params, boolean hasVendorId);
void onReceived(int srcAddress, int destAddress, byte[] params, boolean hasVendorId);
/**
* The callback is called:
* <ul>
* <li> before HdmiControlService is disabled.
* <li> after HdmiControlService is enabled and the local address is assigned.
* </ul>
* The client shouldn't hold the thread too long since this is a blocking call.
*
* @param enabled {@code true} if HdmiControlService is enabled.
* @param reason the reason code why the state of HdmiControlService is changed.
* @see #CONTROL_STATE_CHANGED_REASON_START
* @see #CONTROL_STATE_CHANGED_REASON_SETTING
* @see #CONTROL_STATE_CHANGED_REASON_WAKEUP
* @see #CONTROL_STATE_CHANGED_REASON_STANDBY
*/
void onControlStateChanged(boolean enabled, int reason);
}
/**

View File

@@ -23,5 +23,6 @@ package android.hardware.hdmi;
* @hide
*/
oneway interface IHdmiVendorCommandListener {
void onReceived(int logicalAddress, in byte[] operands, boolean hasVendorId);
void onReceived(int logicalAddress, int destAddress, in byte[] operands, boolean hasVendorId);
void onControlStateChanged(boolean enabled, int reason);
}

View File

@@ -516,8 +516,8 @@ abstract class HdmiCecLocalDevice {
}
protected boolean handleVendorCommand(HdmiCecMessage message) {
if (!mService.invokeVendorCommandListeners(mDeviceType, message.getSource(),
message.getParams(), false)) {
if (!mService.invokeVendorCommandListenersOnReceived(mDeviceType, message.getSource(),
message.getDestination(), message.getParams(), false)) {
// Vendor command listener may not have been registered yet. Respond with
// <Feature Abort> [NOT_IN_CORRECT_MODE] so that the sender can try again later.
mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE);
@@ -529,8 +529,8 @@ abstract class HdmiCecLocalDevice {
byte[] params = message.getParams();
int vendorId = HdmiUtils.threeBytesToInt(params);
if (vendorId == mService.getVendorId()) {
if (!mService.invokeVendorCommandListeners(mDeviceType, message.getSource(), params,
true)) {
if (!mService.invokeVendorCommandListenersOnReceived(mDeviceType, message.getSource(),
message.getDestination(), params, true)) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE);
}
} else if (message.getDestination() != Constants.ADDR_BROADCAST &&

View File

@@ -316,20 +316,23 @@ public final class HdmiControlService extends SystemService {
mMessageValidator = new HdmiCecMessageValidator(this);
publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService());
// Register broadcast receiver for power state change.
if (mCecController != null) {
// Register broadcast receiver for power state change.
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
getContext().registerReceiver(mHdmiControlBroadcastReceiver, filter);
// Register ContentObserver to monitor the settings change.
registerContentObserver();
}
}
/**
* Called when the initialization of local devices is complete.
*/
private void onInitializeCecComplete() {
private void onInitializeCecComplete(int initiatedBy) {
if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) {
mPowerStatus = HdmiControlManager.POWER_STATUS_ON;
}
@@ -337,7 +340,22 @@ public final class HdmiControlService extends SystemService {
if (isTvDevice()) {
mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup()));
registerContentObserver();
}
int reason = -1;
switch (initiatedBy) {
case INITIATED_BY_BOOT_UP:
reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_START;
break;
case INITIATED_BY_ENABLE_CEC:
reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING;
break;
case INITIATED_BY_SCREEN_ON:
case INITIATED_BY_WAKE_UP_MESSAGE:
reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP;
break;
}
if (reason != -1) {
invokeVendorCommandListenersOnControlStateChanged(true, reason);
}
}
@@ -402,10 +420,6 @@ public final class HdmiControlService extends SystemService {
Global.putInt(cr, key, toInt(value));
}
private void unregisterSettingsObserver() {
getContext().getContentResolver().unregisterContentObserver(mSettingsObserver);
}
private void initializeCec(int initiatedBy) {
mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED);
initializeLocalDevices(initiatedBy);
@@ -460,7 +474,7 @@ public final class HdmiControlService extends SystemService {
if (initiatedBy != INITIATED_BY_HOTPLUG) {
// In case of the hotplug we don't call onInitializeCecComplete()
// since we reallocate the logical address only.
onInitializeCecComplete();
onInitializeCecComplete(initiatedBy);
}
notifyAddressAllocated(allocatedDevices, initiatedBy);
}
@@ -1789,6 +1803,8 @@ public final class HdmiControlService extends SystemService {
private void onStandby() {
assertRunOnServiceThread();
mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY;
invokeVendorCommandListenersOnControlStateChanged(false,
HdmiControlManager.CONTROL_STATE_CHANGED_REASON_STANDBY);
final List<HdmiCecLocalDevice> devices = getAllLocalDevices();
disableDevices(new PendingActionClearedCallback() {
@@ -1827,9 +1843,6 @@ public final class HdmiControlService extends SystemService {
for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
device.disableDevice(mStandbyMessageReceived, callback);
}
if (isTvDevice()) {
unregisterSettingsObserver();
}
}
mMhlController.clearAllLocalDevices();
@@ -1874,8 +1887,8 @@ public final class HdmiControlService extends SystemService {
}
}
boolean invokeVendorCommandListeners(int deviceType, int srcAddress, byte[] params,
boolean hasVendorId) {
boolean invokeVendorCommandListenersOnReceived(int deviceType, int srcAddress, int destAddress,
byte[] params, boolean hasVendorId) {
synchronized (mLock) {
if (mVendorCommandListenerRecords.isEmpty()) {
return false;
@@ -1885,7 +1898,7 @@ public final class HdmiControlService extends SystemService {
continue;
}
try {
record.mListener.onReceived(srcAddress, params, hasVendorId);
record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to notify vendor command reception", e);
}
@@ -1894,6 +1907,22 @@ public final class HdmiControlService extends SystemService {
}
}
boolean invokeVendorCommandListenersOnControlStateChanged(boolean enabled, int reason) {
synchronized (mLock) {
if (mVendorCommandListenerRecords.isEmpty()) {
return false;
}
for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) {
try {
record.mListener.onControlStateChanged(enabled, reason);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to notify control-state-changed to vendor handler", e);
}
}
return true;
}
}
private void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener) {
HdmiMhlVendorCommandListenerRecord record =
new HdmiMhlVendorCommandListenerRecord(listener);
@@ -1943,6 +1972,11 @@ public final class HdmiControlService extends SystemService {
void setControlEnabled(boolean enabled) {
assertRunOnServiceThread();
if (!enabled) {
// Call the vendor handler before the service is disabled.
invokeVendorCommandListenersOnControlStateChanged(false,
HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING);
}
int value = toInt(enabled);
mCecController.setOption(OPTION_CEC_ENABLE, value);
mMhlController.setOption(OPTION_MHL_ENABLE, value);