CEC: Content observer to handle TV Setting update
Replaced the API setOption with content observer to read/get informed of
the CEC settings.
Bug: 16855247
Change-Id: Ieff2399bbfe83f05af4448e7337f91ef40d1e24d
diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java
index a9040cf..a3f6c00 100644
--- a/core/java/android/hardware/hdmi/HdmiTvClient.java
+++ b/core/java/android/hardware/hdmi/HdmiTvClient.java
@@ -35,55 +35,6 @@
public final class HdmiTvClient extends HdmiClient {
private static final String TAG = "HdmiTvClient";
- // 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>. {@code ENABLED} by default.
- * If set to {@code DISABLED}, TV won't turn on automatically.
- */
- public static final int OPTION_CEC_AUTO_WAKEUP = 1;
-
- /**
- * If set to {@code DISABLED}, all CEC commands are discarded.
- *
- * <p> This option is for internal use only, not supposed to be used by other components.
- * @hide
- */
- public static final int OPTION_CEC_ENABLE = 2;
-
- /**
- * If set to {@code DISABLED}, system service yields control of CEC to sub-microcontroller.
- * If {@code ENABLED}, it take the control back.
- *
- * <p> This option is for internal use only, not supposed to be used by other components.
- * @hide
- */
- public static final int OPTION_CEC_SERVICE_CONTROL = 3;
-
- /**
- * Put other devices to standby when TV goes to standby. {@code ENABLED} by default.
- * If set to {@code DISABLED}, TV doesn't send <Standby> to other devices.
- */
- public static final int OPTION_CEC_AUTO_DEVICE_OFF = 4;
-
- /** If set to {@code DISABLED}, TV does not switch ports when mobile device is connected. */
- public static final int OPTION_MHL_INPUT_SWITCHING = 101;
-
- /** If set to {@code ENABLED}, TV disables power charging for mobile device. */
- public static final int OPTION_MHL_POWER_CHARGE = 102;
-
- /**
- * If set to {@code DISABLED}, all MHL commands are discarded.
- *
- * <p> This option is for internal use only, not supposed to be used by other components.
- * @hide
- */
- public static final int OPTION_MHL_ENABLE = 103;
-
- public static final int DISABLED = 0;
- public static final int ENABLED = 1;
-
HdmiTvClient(IHdmiControlService service) {
super(service);
}
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index d6cb492..5422bc2 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -52,9 +52,7 @@
void setSystemAudioMode(boolean enabled, IHdmiControlCallback callback);
void addSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener);
- void setControlEnabled(boolean enabled);
void setArcMode(boolean enabled);
- void setOption(int option, int value);
void setProhibitMode(boolean enabled);
void setSystemAudioVolume(int oldIndex, int newIndex, int maxIndex);
void setSystemAudioMute(boolean mute);
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 0b57474..0003210 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -214,5 +214,35 @@
static final int RECORDING_TYPE_EXTERNAL_PHYSICAL_ADDRESS = 3;
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 take 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;
+
+ // If set to disabled, TV does not switch ports when mobile device is connected.
+ static final int OPTION_MHL_INPUT_SWITCHING = 101;
+
+ // If set to enabled, TV disables power charging for mobile device.
+ static final int OPTION_MHL_POWER_CHARGE = 102;
+
+ // If set to disabled, all MHL commands are discarded.
+ static final int OPTION_MHL_ENABLE = 103;
+
+ static final int DISABLED = 0;
+ static final int ENABLED = 1;
+
private Constants() { /* cannot be instantiated */ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index ad5b2ba..183f299 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -30,8 +30,8 @@
import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL;
import android.content.Intent;
-import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiControlManager;
+import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiRecordSources;
import android.hardware.hdmi.HdmiTimerRecordSources;
import android.hardware.hdmi.IHdmiControlCallback;
@@ -1274,14 +1274,12 @@
void setAutoDeviceOff(boolean enabled) {
assertRunOnServiceThread();
mAutoDeviceOff = enabled;
- mService.writeBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, enabled);
}
@ServiceThreadOnly
void setAutoWakeup(boolean enabled) {
assertRunOnServiceThread();
mAutoWakeup = enabled;
- mService.writeBooleanSetting(Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, enabled);
}
@ServiceThreadOnly
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 81b99f0..6f68bd8 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -16,17 +16,27 @@
package com.android.server.hdmi;
+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_DEVICE_OFF;
+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_MHL_ENABLE;
+import static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING;
+import static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE;
+
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.ContentObserver;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiHotplugEvent;
import android.hardware.hdmi.HdmiPortInfo;
-import android.hardware.hdmi.HdmiTvClient;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.hdmi.IHdmiControlService;
import android.hardware.hdmi.IHdmiDeviceEventListener;
@@ -36,6 +46,7 @@
import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
import android.hardware.hdmi.IHdmiVendorCommandListener;
import android.media.AudioManager;
+import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
@@ -44,6 +55,7 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.provider.Settings.Global;
import android.util.ArraySet;
import android.util.Slog;
@@ -196,6 +208,8 @@
// Handler used to run a task in service thread.
private final Handler mHandler = new Handler();
+ private final SettingsObserver mSettingsObserver;
+
@Nullable
private HdmiCecController mCecController;
@@ -229,6 +243,7 @@
super(context);
mLocalDevices = HdmiUtils.asImmutableList(getContext().getResources().getIntArray(
com.android.internal.R.array.config_hdmiCecLogicalDeviceType));
+ mSettingsObserver = new SettingsObserver(mHandler);
}
@Override
@@ -241,8 +256,7 @@
mCecController = HdmiCecController.create(this);
if (mCecController != null) {
// TODO: Remove this as soon as OEM's HAL implementation is corrected.
- mCecController.setOption(HdmiTvClient.OPTION_CEC_ENABLE,
- HdmiTvClient.ENABLED);
+ mCecController.setOption(OPTION_CEC_ENABLE, ENABLED);
// TODO: load value for mHdmiControlEnabled from preference.
if (mHdmiControlEnabled) {
@@ -279,24 +293,78 @@
mWakeUpMessageReceived = false;
if (isTvDevice()) {
- mCecController.setOption(HdmiTvClient.OPTION_CEC_AUTO_WAKEUP,
- tv().getAutoWakeup() ? HdmiTvClient.ENABLED : HdmiTvClient.DISABLED);
+ mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup()));
+ registerContentObserver();
}
}
+
+ private void registerContentObserver() {
+ ContentResolver resolver = getContext().getContentResolver();
+ String[] settings = new String[] {
+ Global.HDMI_CONTROL_ENABLED,
+ Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
+ Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
+ Global.MHL_INPUT_SWITCHING_ENABLED,
+ Global.MHL_POWER_CHARGE_ENABLED
+ };
+ for (String s: settings) {
+ resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver,
+ UserHandle.USER_ALL);
+ }
+ }
+
+ private class SettingsObserver extends ContentObserver {
+ public SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ String option = uri.getLastPathSegment();
+ boolean enabled = readBooleanSetting(option, true);
+ switch (option) {
+ case Global.HDMI_CONTROL_ENABLED:
+ setControlEnabled(enabled);
+ break;
+ case Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED:
+ tv().setAutoWakeup(enabled);
+ setOption(OPTION_CEC_AUTO_WAKEUP, toInt(enabled));
+ break;
+ case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED:
+ tv().setAutoDeviceOff(enabled);
+ // No need to propagate to HAL.
+ break;
+ case Global.MHL_INPUT_SWITCHING_ENABLED:
+ setOption(OPTION_MHL_INPUT_SWITCHING, toInt(enabled));
+ break;
+ case Global.MHL_POWER_CHARGE_ENABLED:
+ setOption(OPTION_MHL_POWER_CHARGE, toInt(enabled));
+ break;
+ }
+ }
+ }
+
+ private static int toInt(boolean enabled) {
+ return enabled ? ENABLED : DISABLED;
+ }
+
boolean readBooleanSetting(String key, boolean defVal) {
ContentResolver cr = getContext().getContentResolver();
- return Global.getInt(cr, key, defVal ? Constants.TRUE : Constants.FALSE) == Constants.TRUE;
+ return Global.getInt(cr, key, toInt(defVal)) == ENABLED;
}
void writeBooleanSetting(String key, boolean value) {
ContentResolver cr = getContext().getContentResolver();
- Global.putInt(cr, key, value ? Constants.TRUE : Constants.FALSE);
+ Global.putInt(cr, key, toInt(value));
+ }
+
+ private void unregisterSettingsObserver() {
+ getContext().getContentResolver().unregisterContentObserver(mSettingsObserver);
}
private void initializeCec(int initiatedBy) {
- mCecController.setOption(HdmiTvClient.OPTION_CEC_SERVICE_CONTROL,
- HdmiTvClient.ENABLED);
+ mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED);
initializeLocalDevices(mLocalDevices, initiatedBy);
}
@@ -965,18 +1033,6 @@
}
@Override
- public void setControlEnabled(final boolean enabled) {
- enforceAccessPermission();
- runOnServiceThread(new Runnable() {
- @Override
- public void run() {
- handleHdmiControlStatusChanged(enabled);
-
- }
- });
- }
-
- @Override
public void setSystemAudioVolume(final int oldIndex, final int newIndex,
final int maxIndex) {
enforceAccessPermission();
@@ -1025,30 +1081,6 @@
}
@Override
- public void setOption(final int key, final int value) {
- enforceAccessPermission();
- if (!isTvDevice()) {
- return;
- }
- switch (key) {
- case HdmiTvClient.OPTION_CEC_AUTO_WAKEUP:
- tv().setAutoWakeup(value == HdmiTvClient.ENABLED);
- mCecController.setOption(key, value);
- break;
- case HdmiTvClient.OPTION_CEC_AUTO_DEVICE_OFF:
- // No need to pass this option to HAL.
- tv().setAutoDeviceOff(value == HdmiTvClient.ENABLED);
- break;
- case HdmiTvClient.OPTION_MHL_INPUT_SWITCHING: // Fall through
- case HdmiTvClient.OPTION_MHL_POWER_CHARGE:
- if (mMhlController != null) {
- mMhlController.setOption(key, value);
- }
- break;
- }
- }
-
- @Override
public void setProhibitMode(final boolean enabled) {
enforceAccessPermission();
if (!isTvDevice()) {
@@ -1502,6 +1534,9 @@
for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
device.disableDevice(mStandbyMessageReceived, callback);
}
+ if (isTvDevice()) {
+ unregisterSettingsObserver();
+ }
}
@ServiceThreadOnly
@@ -1527,7 +1562,7 @@
device.onStandby(mStandbyMessageReceived);
}
mStandbyMessageReceived = false;
- mCecController.setOption(HdmiTvClient.OPTION_CEC_SERVICE_CONTROL, HdmiTvClient.DISABLED);
+ mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, DISABLED);
}
private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {
@@ -1572,13 +1607,19 @@
}
@ServiceThreadOnly
- private void handleHdmiControlStatusChanged(boolean enabled) {
+ void setOption(int key, int value) {
+ assertRunOnServiceThread();
+ mCecController.setOption(key, value);
+ }
+
+ @ServiceThreadOnly
+ void setControlEnabled(boolean enabled) {
assertRunOnServiceThread();
- int value = enabled ? HdmiTvClient.ENABLED : HdmiTvClient.DISABLED;
- mCecController.setOption(HdmiTvClient.OPTION_CEC_ENABLE, value);
+ int value = toInt(enabled);
+ mCecController.setOption(OPTION_CEC_ENABLE, value);
if (mMhlController != null) {
- mMhlController.setOption(HdmiTvClient.OPTION_MHL_ENABLE, value);
+ mMhlController.setOption(OPTION_MHL_ENABLE, value);
}
synchronized (mLock) {