[CEC Configuration] Add listener system API
Bug: 174731501 Bug: 172637440 Bug: 172905515 Test: atest com.google.android.gts.hdmicec.HdmiControlManagerHostTest Change-Id: I830f3e312d5cf70fc84e389a12ecd50c2e1bfae6
This commit is contained in:
@@ -2741,6 +2741,8 @@ package android.hardware.hdmi {
|
||||
}
|
||||
|
||||
public final class HdmiControlManager {
|
||||
method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHdmiCecEnabledChangeListener(@NonNull android.hardware.hdmi.HdmiControlManager.CecSettingChangeListener);
|
||||
method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHdmiCecEnabledChangeListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.hdmi.HdmiControlManager.CecSettingChangeListener);
|
||||
method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
|
||||
method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHotplugEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public java.util.List<java.lang.Integer> getAllowedCecSettingIntValues(@NonNull String);
|
||||
@@ -2759,6 +2761,7 @@ package android.hardware.hdmi {
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public java.util.List<java.lang.String> getUserCecSettings();
|
||||
method public boolean isDeviceConnected(@NonNull android.hardware.hdmi.HdmiDeviceInfo);
|
||||
method public void powerOffDevice(@NonNull android.hardware.hdmi.HdmiDeviceInfo);
|
||||
method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHdmiCecEnabledChangeListener(@NonNull android.hardware.hdmi.HdmiControlManager.CecSettingChangeListener);
|
||||
method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
|
||||
method public void setActiveSource(@NonNull android.hardware.hdmi.HdmiDeviceInfo);
|
||||
method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setHdmiCecEnabled(@NonNull int);
|
||||
@@ -2871,6 +2874,10 @@ package android.hardware.hdmi {
|
||||
field public static final int TIMER_STATUS_PROGRAMMED_INFO_NO_MEDIA_INFO = 10; // 0xa
|
||||
}
|
||||
|
||||
public static interface HdmiControlManager.CecSettingChangeListener {
|
||||
method public void onChange(@NonNull String);
|
||||
}
|
||||
|
||||
@IntDef({android.hardware.hdmi.HdmiControlManager.RESULT_SUCCESS, android.hardware.hdmi.HdmiControlManager.RESULT_TIMEOUT, android.hardware.hdmi.HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE, android.hardware.hdmi.HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE, android.hardware.hdmi.HdmiControlManager.RESULT_ALREADY_IN_PROGRESS, android.hardware.hdmi.HdmiControlManager.RESULT_EXCEPTION, android.hardware.hdmi.HdmiControlManager.RESULT_INCORRECT_MODE, android.hardware.hdmi.HdmiControlManager.RESULT_COMMUNICATION_FAILED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public static @interface HdmiControlManager.ControlCallbackResult {
|
||||
}
|
||||
|
||||
|
||||
@@ -1371,6 +1371,87 @@ public final class HdmiControlManager {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener used to get setting change notification.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public interface CecSettingChangeListener {
|
||||
/**
|
||||
* Called when value of a setting changes.
|
||||
*
|
||||
* @param setting name of a CEC setting that changed
|
||||
*/
|
||||
void onChange(@NonNull @CecSettingName String setting);
|
||||
}
|
||||
|
||||
private final ArrayMap<String,
|
||||
ArrayMap<CecSettingChangeListener, IHdmiCecSettingChangeListener>>
|
||||
mCecSettingChangeListeners = new ArrayMap<>();
|
||||
|
||||
private void addCecSettingChangeListener(
|
||||
@NonNull @CecSettingName String setting,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull CecSettingChangeListener listener) {
|
||||
if (mService == null) {
|
||||
Log.e(TAG, "HdmiControlService is not available");
|
||||
return;
|
||||
}
|
||||
if (mCecSettingChangeListeners.containsKey(setting)
|
||||
&& mCecSettingChangeListeners.get(setting).containsKey(listener)) {
|
||||
Log.e(TAG, "listener is already registered");
|
||||
return;
|
||||
}
|
||||
IHdmiCecSettingChangeListener wrappedListener =
|
||||
getCecSettingChangeListenerWrapper(executor, listener);
|
||||
if (!mCecSettingChangeListeners.containsKey(setting)) {
|
||||
mCecSettingChangeListeners.put(setting, new ArrayMap<>());
|
||||
}
|
||||
mCecSettingChangeListeners.get(setting).put(listener, wrappedListener);
|
||||
try {
|
||||
mService.addCecSettingChangeListener(setting, wrappedListener);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
private void removeCecSettingChangeListener(
|
||||
@NonNull @CecSettingName String setting,
|
||||
@NonNull CecSettingChangeListener listener) {
|
||||
if (mService == null) {
|
||||
Log.e(TAG, "HdmiControlService is not available");
|
||||
return;
|
||||
}
|
||||
IHdmiCecSettingChangeListener wrappedListener =
|
||||
!mCecSettingChangeListeners.containsKey(setting) ? null :
|
||||
mCecSettingChangeListeners.get(setting).remove(listener);
|
||||
if (wrappedListener == null) {
|
||||
Log.e(TAG, "tried to remove not-registered listener");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mService.removeCecSettingChangeListener(setting, wrappedListener);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
private IHdmiCecSettingChangeListener getCecSettingChangeListenerWrapper(
|
||||
Executor executor, final CecSettingChangeListener listener) {
|
||||
return new IHdmiCecSettingChangeListener.Stub() {
|
||||
@Override
|
||||
public void onChange(String setting) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
executor.execute(() -> listener.onChange(setting));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a set of user-modifiable settings.
|
||||
*
|
||||
@@ -1492,6 +1573,53 @@ public final class HdmiControlManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add change listener for global status of HDMI CEC.
|
||||
*
|
||||
* <p>To stop getting the notification,
|
||||
* use {@link #removeHdmiCecEnabledChangeListener(CecSettingChangeListener)}.
|
||||
*
|
||||
* Note that each invocation of the callback will be executed on an arbitrary
|
||||
* Binder thread. This means that all callback implementations must be
|
||||
* thread safe. To specify the execution thread, use
|
||||
* {@link addHdmiCecEnabledChangeListener(Executor, CecSettingChangeListener)}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
|
||||
public void addHdmiCecEnabledChangeListener(@NonNull CecSettingChangeListener listener) {
|
||||
addHdmiCecEnabledChangeListener(ConcurrentUtils.DIRECT_EXECUTOR, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add change listener for global status of HDMI CEC.
|
||||
*
|
||||
* <p>To stop getting the notification,
|
||||
* use {@link #removeHdmiCecEnabledChangeListener(CecSettingChangeListener)}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
|
||||
public void addHdmiCecEnabledChangeListener(
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull CecSettingChangeListener listener) {
|
||||
addCecSettingChangeListener(CEC_SETTING_NAME_HDMI_CEC_ENABLED, executor, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove change listener for global status of HDMI CEC.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
|
||||
public void removeHdmiCecEnabledChangeListener(
|
||||
@NonNull CecSettingChangeListener listener) {
|
||||
removeCecSettingChangeListener(CEC_SETTING_NAME_HDMI_CEC_ENABLED, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the version of the HDMI CEC specification currently used.
|
||||
*
|
||||
|
||||
@@ -305,6 +305,18 @@ public final class HdmiControlServiceWrapper {
|
||||
HdmiControlServiceWrapper.this.removeHdmiCecVolumeControlFeatureListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCecSettingChangeListener(String name,
|
||||
IHdmiCecSettingChangeListener listener) {
|
||||
HdmiControlServiceWrapper.this.addCecSettingChangeListener(name, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCecSettingChangeListener(String name,
|
||||
IHdmiCecSettingChangeListener listener) {
|
||||
HdmiControlServiceWrapper.this.removeCecSettingChangeListener(name, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUserCecSettings() {
|
||||
return HdmiControlServiceWrapper.this.getUserCecSettings();
|
||||
@@ -521,6 +533,14 @@ public final class HdmiControlServiceWrapper {
|
||||
public void removeHdmiCecVolumeControlFeatureListener(
|
||||
IHdmiCecVolumeControlFeatureListener listener) {}
|
||||
|
||||
/** @hide */
|
||||
public void addCecSettingChangeListener(String name,
|
||||
IHdmiCecSettingChangeListener listener) {}
|
||||
|
||||
/** @hide */
|
||||
public void removeCecSettingChangeListener(String name,
|
||||
IHdmiCecSettingChangeListener listener) {}
|
||||
|
||||
/** @hide */
|
||||
public List<String> getUserCecSettings() {
|
||||
return new ArrayList<>();
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.hardware.hdmi;
|
||||
|
||||
/**
|
||||
* Callback interface definition for HDMI client to get informed of
|
||||
* CEC setting change.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IHdmiCecSettingChangeListener {
|
||||
void onChange(in String setting);
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package android.hardware.hdmi;
|
||||
|
||||
import android.hardware.hdmi.HdmiDeviceInfo;
|
||||
import android.hardware.hdmi.HdmiPortInfo;
|
||||
import android.hardware.hdmi.IHdmiCecSettingChangeListener;
|
||||
import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
|
||||
import android.hardware.hdmi.IHdmiControlCallback;
|
||||
import android.hardware.hdmi.IHdmiControlStatusChangeListener;
|
||||
@@ -89,6 +90,8 @@ interface IHdmiControlService {
|
||||
boolean isHdmiCecVolumeControlEnabled();
|
||||
void reportAudioStatus(int deviceType, int volume, int maxVolume, boolean isMute);
|
||||
void setSystemAudioModeOnForAudioOnlySource();
|
||||
void addCecSettingChangeListener(String name, IHdmiCecSettingChangeListener listener);
|
||||
void removeCecSettingChangeListener(String name, IHdmiCecSettingChangeListener listener);
|
||||
List<String> getUserCecSettings();
|
||||
List<String> getAllowedCecSettingStringValues(String name);
|
||||
int[] getAllowedCecSettingIntValues(String name);
|
||||
|
||||
@@ -394,6 +394,16 @@ public class HdmiAudioSystemClientTest {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCecSettingChangeListener(String name,
|
||||
IHdmiCecSettingChangeListener listener) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCecSettingChangeListener(String name,
|
||||
IHdmiCecSettingChangeListener listener) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getAllowedCecSettingIntValues(String name) {
|
||||
return new int[0];
|
||||
|
||||
@@ -40,6 +40,7 @@ import android.hardware.hdmi.HdmiControlManager;
|
||||
import android.hardware.hdmi.HdmiDeviceInfo;
|
||||
import android.hardware.hdmi.HdmiHotplugEvent;
|
||||
import android.hardware.hdmi.HdmiPortInfo;
|
||||
import android.hardware.hdmi.IHdmiCecSettingChangeListener;
|
||||
import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
|
||||
import android.hardware.hdmi.IHdmiControlCallback;
|
||||
import android.hardware.hdmi.IHdmiControlService;
|
||||
@@ -74,6 +75,7 @@ import android.os.UserHandle;
|
||||
import android.provider.Settings.Global;
|
||||
import android.sysprop.HdmiProperties;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
|
||||
@@ -308,6 +310,11 @@ public class HdmiControlService extends SystemService {
|
||||
private final ArrayList<VendorCommandListenerRecord> mVendorCommandListenerRecords =
|
||||
new ArrayList<>();
|
||||
|
||||
// List of records for CEC setting change listener to handle the caller killed in action.
|
||||
@GuardedBy("mLock")
|
||||
private final ArrayMap<String, RemoteCallbackList<IHdmiCecSettingChangeListener>>
|
||||
mHdmiCecSettingChangeListenerRecords = new ArrayMap<>();
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private InputChangeListenerRecord mInputChangeListenerRecord;
|
||||
|
||||
@@ -2221,6 +2228,20 @@ public class HdmiControlService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCecSettingChangeListener(String name,
|
||||
final IHdmiCecSettingChangeListener listener) {
|
||||
enforceAccessPermission();
|
||||
HdmiControlService.this.addCecSettingChangeListener(name, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCecSettingChangeListener(String name,
|
||||
final IHdmiCecSettingChangeListener listener) {
|
||||
enforceAccessPermission();
|
||||
HdmiControlService.this.removeCecSettingChangeListener(name, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUserCecSettings() {
|
||||
enforceAccessPermission();
|
||||
@@ -3450,4 +3471,53 @@ public class HdmiControlService extends SystemService {
|
||||
protected HdmiCecConfig getHdmiCecConfig() {
|
||||
return mHdmiCecConfig;
|
||||
}
|
||||
|
||||
private HdmiCecConfig.SettingChangeListener mSettingChangeListener =
|
||||
new HdmiCecConfig.SettingChangeListener() {
|
||||
@Override
|
||||
public void onChange(String name) {
|
||||
synchronized (mLock) {
|
||||
if (!mHdmiCecSettingChangeListenerRecords.containsKey(name)) {
|
||||
return;
|
||||
}
|
||||
mHdmiCecSettingChangeListenerRecords.get(name).broadcast(listener -> {
|
||||
invokeCecSettingChangeListenerLocked(name, listener);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void addCecSettingChangeListener(String name,
|
||||
final IHdmiCecSettingChangeListener listener) {
|
||||
synchronized (mLock) {
|
||||
if (!mHdmiCecSettingChangeListenerRecords.containsKey(name)) {
|
||||
mHdmiCecSettingChangeListenerRecords.put(name, new RemoteCallbackList<>());
|
||||
mHdmiCecConfig.registerChangeListener(name, mSettingChangeListener);
|
||||
}
|
||||
mHdmiCecSettingChangeListenerRecords.get(name).register(listener);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeCecSettingChangeListener(String name,
|
||||
final IHdmiCecSettingChangeListener listener) {
|
||||
synchronized (mLock) {
|
||||
if (!mHdmiCecSettingChangeListenerRecords.containsKey(name)) {
|
||||
return;
|
||||
}
|
||||
mHdmiCecSettingChangeListenerRecords.get(name).unregister(listener);
|
||||
if (mHdmiCecSettingChangeListenerRecords.get(name).getRegisteredCallbackCount() == 0) {
|
||||
mHdmiCecSettingChangeListenerRecords.remove(name);
|
||||
mHdmiCecConfig.removeChangeListener(name, mSettingChangeListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void invokeCecSettingChangeListenerLocked(String name,
|
||||
final IHdmiCecSettingChangeListener listener) {
|
||||
try {
|
||||
listener.onChange(name);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to report setting change", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user