Loading core/java/android/hardware/hdmi/HdmiControlManager.java +91 −0 Original line number Diff line number Diff line Loading @@ -684,6 +684,28 @@ public final class HdmiControlManager { private final ArrayMap<HotplugEventListener, IHdmiHotplugEventListener> mHotplugEventListeners = new ArrayMap<>(); /** * Listener used to get HDMI Control (CEC) status (enabled/disabled) and the connected display * status. * @hide */ public interface HdmiControlStatusChangeListener { /** * Called when HDMI Control (CEC) is enabled/disabled. * * @param isCecEnabled status of HDMI Control * {@link android.provider.Settings.Global#HDMI_CONTROL_ENABLED}: {@code true} if enabled. * @param isCecAvailable status of CEC support of the connected display (the TV). * {@code true} if supported. * * Note: Value of isCecAvailable is only valid when isCecEnabled is true. **/ void onStatusChange(boolean isCecEnabled, boolean isCecAvailable); } private final ArrayMap<HdmiControlStatusChangeListener, IHdmiControlStatusChangeListener> mHdmiControlStatusChangeListeners = new ArrayMap<>(); /** * Listener used to get vendor-specific commands. */ Loading Loading @@ -777,4 +799,73 @@ public final class HdmiControlManager { } }; } /** * Adds a listener to get informed of {@link HdmiControlStatusChange}. * * <p>To stop getting the notification, * use {@link #removeHdmiControlStatusChangeListener(HdmiControlStatusChangeListener)}. * * @param listener {@link HdmiControlStatusChangeListener} instance * @see HdmiControlManager#removeHdmiControlStatusChangeListener( * HdmiControlStatusChangeListener) * * @hide */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHdmiControlStatusChangeListener(HdmiControlStatusChangeListener listener) { if (mService == null) { Log.e(TAG, "HdmiControlService is not available"); return; } if (mHdmiControlStatusChangeListeners.containsKey(listener)) { Log.e(TAG, "listener is already registered"); return; } IHdmiControlStatusChangeListener wrappedListener = getHdmiControlStatusChangeListenerWrapper(listener); mHdmiControlStatusChangeListeners.put(listener, wrappedListener); try { mService.addHdmiControlStatusChangeListener(wrappedListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Removes a listener to stop getting informed of {@link HdmiControlStatusChange}. * * @param listener {@link HdmiControlStatusChangeListener} instance to be removed * * @hide */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHdmiControlStatusChangeListener(HdmiControlStatusChangeListener listener) { if (mService == null) { Log.e(TAG, "HdmiControlService is not available"); return; } IHdmiControlStatusChangeListener wrappedListener = mHdmiControlStatusChangeListeners.remove(listener); if (wrappedListener == null) { Log.e(TAG, "tried to remove not-registered listener"); return; } try { mService.removeHdmiControlStatusChangeListener(wrappedListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private IHdmiControlStatusChangeListener getHdmiControlStatusChangeListenerWrapper( final HdmiControlStatusChangeListener listener) { return new IHdmiControlStatusChangeListener.Stub() { @Override public void onStatusChange(boolean isCecEnabled, boolean isCecAvailable) { listener.onStatusChange(isCecEnabled, isCecAvailable); } }; } } core/java/android/hardware/hdmi/IHdmiControlService.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.hardware.hdmi; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiPortInfo; import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.hdmi.IHdmiControlStatusChangeListener; import android.hardware.hdmi.IHdmiDeviceEventListener; import android.hardware.hdmi.IHdmiHotplugEventListener; import android.hardware.hdmi.IHdmiInputChangeListener; Loading @@ -41,6 +42,8 @@ interface IHdmiControlService { HdmiDeviceInfo getActiveSource(); void oneTouchPlay(IHdmiControlCallback callback); void queryDisplayStatus(IHdmiControlCallback callback); void addHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener); void removeHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener); void addHotplugEventListener(IHdmiHotplugEventListener listener); void removeHotplugEventListener(IHdmiHotplugEventListener listener); void addDeviceEventListener(IHdmiDeviceEventListener listener); Loading core/java/android/hardware/hdmi/IHdmiControlStatusChangeListener.aidl 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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; import android.hardware.hdmi.HdmiDeviceInfo; /** * Callback interface definition for HDMI client to get informed of * the CEC availability change event. * * @hide */ oneway interface IHdmiControlStatusChangeListener { /** * Called when HDMI Control (CEC) is enabled/disabled. * * @param isCecEnabled status of HDMI Control * {@link android.provider.Settings.Global#HDMI_CONTROL_ENABLED}: {@code true} if enabled. * @param isCecAvailable status of CEC support of the connected display (the TV). * {@code true} if supported. * * Note: Value of isCecAvailable is only valid when isCecEnabled is true. **/ void onStatusChange(boolean isCecEnabled, boolean isCecAvailable); } core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java +10 −0 Original line number Diff line number Diff line Loading @@ -193,6 +193,16 @@ public class HdmiAudioSystemClientTest { public void queryDisplayStatus(final IHdmiControlCallback callback) { } @Override public void addHdmiControlStatusChangeListener( final IHdmiControlStatusChangeListener listener) { } @Override public void removeHdmiControlStatusChangeListener( final IHdmiControlStatusChangeListener listener) { } @Override public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { } Loading services/core/java/com/android/server/audio/AudioService.java +37 −27 Original line number Diff line number Diff line Loading @@ -845,7 +845,12 @@ public class AudioService extends IAudioService.Stub if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) { synchronized (mHdmiClientLock) { mHdmiCecSink = false; mHdmiManager = mContext.getSystemService(HdmiControlManager.class); if (mHdmiManager != null) { mHdmiManager.addHdmiControlStatusChangeListener( mHdmiControlStatusChangeListenerCallback); } mHdmiTvClient = mHdmiManager.getTvClient(); if (mHdmiTvClient != null) { mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER; Loading @@ -856,7 +861,6 @@ public class AudioService extends IAudioService.Stub mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI; mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI; } mHdmiCecSink = false; mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient(); } } Loading Loading @@ -1113,8 +1117,7 @@ public class AudioService extends IAudioService.Stub checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, caller); synchronized (mHdmiClientLock) { if (mHdmiManager != null && mHdmiPlaybackClient != null) { mHdmiCecSink = false; mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback); updateHdmiCecSinkLocked(mHdmiCecSink | false); } } } Loading @@ -1124,7 +1127,7 @@ public class AudioService extends IAudioService.Stub if (isPlatformTelevision()) { synchronized (mHdmiClientLock) { if (mHdmiManager != null) { mHdmiCecSink = false; updateHdmiCecSinkLocked(mHdmiCecSink | false); } } } Loading Loading @@ -5774,12 +5777,9 @@ public class AudioService extends IAudioService.Stub // are transformed into key events for the HDMI playback client. //========================================================================================== private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback { public void onComplete(int status) { synchronized (mHdmiClientLock) { if (mHdmiManager != null) { mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN); // Television devices without CEC service apply software volume on HDMI output @GuardedBy("mHdmiClientLock") private void updateHdmiCecSinkLocked(boolean hdmiCecSink) { mHdmiCecSink = hdmiCecSink; if (mHdmiCecSink) { if (DEBUG_VOL) { Log.d(TAG, "CEC sink: setting HDMI as full vol device"); Loading @@ -5793,12 +5793,20 @@ public class AudioService extends IAudioService.Stub // HDMI output mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI; } checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, "HdmiPlaybackClient.DisplayStatusCallback"); } private class MyHdmiControlStatusChangeListenerCallback implements HdmiControlManager.HdmiControlStatusChangeListener { public void onStatusChange(boolean isCecEnabled, boolean isCecAvailable) { synchronized (mHdmiClientLock) { if (mHdmiManager == null) return; updateHdmiCecSinkLocked(isCecEnabled ? isCecAvailable : false); } } } }; private final Object mHdmiClientLock = new Object(); Loading @@ -5815,12 +5823,14 @@ public class AudioService extends IAudioService.Stub @GuardedBy("mHdmiClientLock") private HdmiPlaybackClient mHdmiPlaybackClient; // true if we are a set-top box, an HDMI sink is connected and it supports CEC. @GuardedBy("mHdmiClientLock") private boolean mHdmiCecSink; // Set only when device is an audio system. @GuardedBy("mHdmiClientLock") private HdmiAudioSystemClient mHdmiAudioSystemClient; private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback(); private MyHdmiControlStatusChangeListenerCallback mHdmiControlStatusChangeListenerCallback = new MyHdmiControlStatusChangeListenerCallback(); @Override public int setHdmiSystemAudioSupported(boolean on) { Loading Loading
core/java/android/hardware/hdmi/HdmiControlManager.java +91 −0 Original line number Diff line number Diff line Loading @@ -684,6 +684,28 @@ public final class HdmiControlManager { private final ArrayMap<HotplugEventListener, IHdmiHotplugEventListener> mHotplugEventListeners = new ArrayMap<>(); /** * Listener used to get HDMI Control (CEC) status (enabled/disabled) and the connected display * status. * @hide */ public interface HdmiControlStatusChangeListener { /** * Called when HDMI Control (CEC) is enabled/disabled. * * @param isCecEnabled status of HDMI Control * {@link android.provider.Settings.Global#HDMI_CONTROL_ENABLED}: {@code true} if enabled. * @param isCecAvailable status of CEC support of the connected display (the TV). * {@code true} if supported. * * Note: Value of isCecAvailable is only valid when isCecEnabled is true. **/ void onStatusChange(boolean isCecEnabled, boolean isCecAvailable); } private final ArrayMap<HdmiControlStatusChangeListener, IHdmiControlStatusChangeListener> mHdmiControlStatusChangeListeners = new ArrayMap<>(); /** * Listener used to get vendor-specific commands. */ Loading Loading @@ -777,4 +799,73 @@ public final class HdmiControlManager { } }; } /** * Adds a listener to get informed of {@link HdmiControlStatusChange}. * * <p>To stop getting the notification, * use {@link #removeHdmiControlStatusChangeListener(HdmiControlStatusChangeListener)}. * * @param listener {@link HdmiControlStatusChangeListener} instance * @see HdmiControlManager#removeHdmiControlStatusChangeListener( * HdmiControlStatusChangeListener) * * @hide */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void addHdmiControlStatusChangeListener(HdmiControlStatusChangeListener listener) { if (mService == null) { Log.e(TAG, "HdmiControlService is not available"); return; } if (mHdmiControlStatusChangeListeners.containsKey(listener)) { Log.e(TAG, "listener is already registered"); return; } IHdmiControlStatusChangeListener wrappedListener = getHdmiControlStatusChangeListenerWrapper(listener); mHdmiControlStatusChangeListeners.put(listener, wrappedListener); try { mService.addHdmiControlStatusChangeListener(wrappedListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Removes a listener to stop getting informed of {@link HdmiControlStatusChange}. * * @param listener {@link HdmiControlStatusChangeListener} instance to be removed * * @hide */ @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHdmiControlStatusChangeListener(HdmiControlStatusChangeListener listener) { if (mService == null) { Log.e(TAG, "HdmiControlService is not available"); return; } IHdmiControlStatusChangeListener wrappedListener = mHdmiControlStatusChangeListeners.remove(listener); if (wrappedListener == null) { Log.e(TAG, "tried to remove not-registered listener"); return; } try { mService.removeHdmiControlStatusChangeListener(wrappedListener); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private IHdmiControlStatusChangeListener getHdmiControlStatusChangeListenerWrapper( final HdmiControlStatusChangeListener listener) { return new IHdmiControlStatusChangeListener.Stub() { @Override public void onStatusChange(boolean isCecEnabled, boolean isCecAvailable) { listener.onStatusChange(isCecEnabled, isCecAvailable); } }; } }
core/java/android/hardware/hdmi/IHdmiControlService.aidl +3 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.hardware.hdmi; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.HdmiPortInfo; import android.hardware.hdmi.IHdmiControlCallback; import android.hardware.hdmi.IHdmiControlStatusChangeListener; import android.hardware.hdmi.IHdmiDeviceEventListener; import android.hardware.hdmi.IHdmiHotplugEventListener; import android.hardware.hdmi.IHdmiInputChangeListener; Loading @@ -41,6 +42,8 @@ interface IHdmiControlService { HdmiDeviceInfo getActiveSource(); void oneTouchPlay(IHdmiControlCallback callback); void queryDisplayStatus(IHdmiControlCallback callback); void addHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener); void removeHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener); void addHotplugEventListener(IHdmiHotplugEventListener listener); void removeHotplugEventListener(IHdmiHotplugEventListener listener); void addDeviceEventListener(IHdmiDeviceEventListener listener); Loading
core/java/android/hardware/hdmi/IHdmiControlStatusChangeListener.aidl 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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; import android.hardware.hdmi.HdmiDeviceInfo; /** * Callback interface definition for HDMI client to get informed of * the CEC availability change event. * * @hide */ oneway interface IHdmiControlStatusChangeListener { /** * Called when HDMI Control (CEC) is enabled/disabled. * * @param isCecEnabled status of HDMI Control * {@link android.provider.Settings.Global#HDMI_CONTROL_ENABLED}: {@code true} if enabled. * @param isCecAvailable status of CEC support of the connected display (the TV). * {@code true} if supported. * * Note: Value of isCecAvailable is only valid when isCecEnabled is true. **/ void onStatusChange(boolean isCecEnabled, boolean isCecAvailable); }
core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java +10 −0 Original line number Diff line number Diff line Loading @@ -193,6 +193,16 @@ public class HdmiAudioSystemClientTest { public void queryDisplayStatus(final IHdmiControlCallback callback) { } @Override public void addHdmiControlStatusChangeListener( final IHdmiControlStatusChangeListener listener) { } @Override public void removeHdmiControlStatusChangeListener( final IHdmiControlStatusChangeListener listener) { } @Override public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { } Loading
services/core/java/com/android/server/audio/AudioService.java +37 −27 Original line number Diff line number Diff line Loading @@ -845,7 +845,12 @@ public class AudioService extends IAudioService.Stub if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) { synchronized (mHdmiClientLock) { mHdmiCecSink = false; mHdmiManager = mContext.getSystemService(HdmiControlManager.class); if (mHdmiManager != null) { mHdmiManager.addHdmiControlStatusChangeListener( mHdmiControlStatusChangeListenerCallback); } mHdmiTvClient = mHdmiManager.getTvClient(); if (mHdmiTvClient != null) { mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER; Loading @@ -856,7 +861,6 @@ public class AudioService extends IAudioService.Stub mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI; mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI; } mHdmiCecSink = false; mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient(); } } Loading Loading @@ -1113,8 +1117,7 @@ public class AudioService extends IAudioService.Stub checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, caller); synchronized (mHdmiClientLock) { if (mHdmiManager != null && mHdmiPlaybackClient != null) { mHdmiCecSink = false; mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback); updateHdmiCecSinkLocked(mHdmiCecSink | false); } } } Loading @@ -1124,7 +1127,7 @@ public class AudioService extends IAudioService.Stub if (isPlatformTelevision()) { synchronized (mHdmiClientLock) { if (mHdmiManager != null) { mHdmiCecSink = false; updateHdmiCecSinkLocked(mHdmiCecSink | false); } } } Loading Loading @@ -5774,12 +5777,9 @@ public class AudioService extends IAudioService.Stub // are transformed into key events for the HDMI playback client. //========================================================================================== private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback { public void onComplete(int status) { synchronized (mHdmiClientLock) { if (mHdmiManager != null) { mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN); // Television devices without CEC service apply software volume on HDMI output @GuardedBy("mHdmiClientLock") private void updateHdmiCecSinkLocked(boolean hdmiCecSink) { mHdmiCecSink = hdmiCecSink; if (mHdmiCecSink) { if (DEBUG_VOL) { Log.d(TAG, "CEC sink: setting HDMI as full vol device"); Loading @@ -5793,12 +5793,20 @@ public class AudioService extends IAudioService.Stub // HDMI output mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI; } checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, "HdmiPlaybackClient.DisplayStatusCallback"); } private class MyHdmiControlStatusChangeListenerCallback implements HdmiControlManager.HdmiControlStatusChangeListener { public void onStatusChange(boolean isCecEnabled, boolean isCecAvailable) { synchronized (mHdmiClientLock) { if (mHdmiManager == null) return; updateHdmiCecSinkLocked(isCecEnabled ? isCecAvailable : false); } } } }; private final Object mHdmiClientLock = new Object(); Loading @@ -5815,12 +5823,14 @@ public class AudioService extends IAudioService.Stub @GuardedBy("mHdmiClientLock") private HdmiPlaybackClient mHdmiPlaybackClient; // true if we are a set-top box, an HDMI sink is connected and it supports CEC. @GuardedBy("mHdmiClientLock") private boolean mHdmiCecSink; // Set only when device is an audio system. @GuardedBy("mHdmiClientLock") private HdmiAudioSystemClient mHdmiAudioSystemClient; private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback(); private MyHdmiControlStatusChangeListenerCallback mHdmiControlStatusChangeListenerCallback = new MyHdmiControlStatusChangeListenerCallback(); @Override public int setHdmiSystemAudioSupported(boolean on) { Loading