Merge "Honor HDMI_CONTROL_ENABLED setting in AudioService"
am: 4efb0c510d
Change-Id: Ic60d7d5bf75288f9f6cdf02d414bf69dbfe74159
This commit is contained in:
@@ -684,6 +684,28 @@ public final class HdmiControlManager {
|
|||||||
private final ArrayMap<HotplugEventListener, IHdmiHotplugEventListener>
|
private final ArrayMap<HotplugEventListener, IHdmiHotplugEventListener>
|
||||||
mHotplugEventListeners = new ArrayMap<>();
|
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.
|
* Listener used to get vendor-specific commands.
|
||||||
*/
|
*/
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package android.hardware.hdmi;
|
|||||||
import android.hardware.hdmi.HdmiDeviceInfo;
|
import android.hardware.hdmi.HdmiDeviceInfo;
|
||||||
import android.hardware.hdmi.HdmiPortInfo;
|
import android.hardware.hdmi.HdmiPortInfo;
|
||||||
import android.hardware.hdmi.IHdmiControlCallback;
|
import android.hardware.hdmi.IHdmiControlCallback;
|
||||||
|
import android.hardware.hdmi.IHdmiControlStatusChangeListener;
|
||||||
import android.hardware.hdmi.IHdmiDeviceEventListener;
|
import android.hardware.hdmi.IHdmiDeviceEventListener;
|
||||||
import android.hardware.hdmi.IHdmiHotplugEventListener;
|
import android.hardware.hdmi.IHdmiHotplugEventListener;
|
||||||
import android.hardware.hdmi.IHdmiInputChangeListener;
|
import android.hardware.hdmi.IHdmiInputChangeListener;
|
||||||
@@ -41,6 +42,8 @@ interface IHdmiControlService {
|
|||||||
HdmiDeviceInfo getActiveSource();
|
HdmiDeviceInfo getActiveSource();
|
||||||
void oneTouchPlay(IHdmiControlCallback callback);
|
void oneTouchPlay(IHdmiControlCallback callback);
|
||||||
void queryDisplayStatus(IHdmiControlCallback callback);
|
void queryDisplayStatus(IHdmiControlCallback callback);
|
||||||
|
void addHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener);
|
||||||
|
void removeHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener);
|
||||||
void addHotplugEventListener(IHdmiHotplugEventListener listener);
|
void addHotplugEventListener(IHdmiHotplugEventListener listener);
|
||||||
void removeHotplugEventListener(IHdmiHotplugEventListener listener);
|
void removeHotplugEventListener(IHdmiHotplugEventListener listener);
|
||||||
void addDeviceEventListener(IHdmiDeviceEventListener listener);
|
void addDeviceEventListener(IHdmiDeviceEventListener listener);
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
@@ -193,6 +193,16 @@ public class HdmiAudioSystemClientTest {
|
|||||||
public void queryDisplayStatus(final IHdmiControlCallback callback) {
|
public void queryDisplayStatus(final IHdmiControlCallback callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addHdmiControlStatusChangeListener(
|
||||||
|
final IHdmiControlStatusChangeListener listener) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeHdmiControlStatusChangeListener(
|
||||||
|
final IHdmiControlStatusChangeListener listener) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addHotplugEventListener(final IHdmiHotplugEventListener listener) {
|
public void addHotplugEventListener(final IHdmiHotplugEventListener listener) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -845,7 +845,12 @@ public class AudioService extends IAudioService.Stub
|
|||||||
|
|
||||||
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) {
|
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) {
|
||||||
synchronized (mHdmiClientLock) {
|
synchronized (mHdmiClientLock) {
|
||||||
|
mHdmiCecSink = false;
|
||||||
mHdmiManager = mContext.getSystemService(HdmiControlManager.class);
|
mHdmiManager = mContext.getSystemService(HdmiControlManager.class);
|
||||||
|
if (mHdmiManager != null) {
|
||||||
|
mHdmiManager.addHdmiControlStatusChangeListener(
|
||||||
|
mHdmiControlStatusChangeListenerCallback);
|
||||||
|
}
|
||||||
mHdmiTvClient = mHdmiManager.getTvClient();
|
mHdmiTvClient = mHdmiManager.getTvClient();
|
||||||
if (mHdmiTvClient != null) {
|
if (mHdmiTvClient != null) {
|
||||||
mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
|
mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
|
||||||
@@ -856,7 +861,6 @@ public class AudioService extends IAudioService.Stub
|
|||||||
mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
|
mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
|
||||||
mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
|
mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
|
||||||
}
|
}
|
||||||
mHdmiCecSink = false;
|
|
||||||
mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient();
|
mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1113,8 +1117,7 @@ public class AudioService extends IAudioService.Stub
|
|||||||
checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, caller);
|
checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, caller);
|
||||||
synchronized (mHdmiClientLock) {
|
synchronized (mHdmiClientLock) {
|
||||||
if (mHdmiManager != null && mHdmiPlaybackClient != null) {
|
if (mHdmiManager != null && mHdmiPlaybackClient != null) {
|
||||||
mHdmiCecSink = false;
|
updateHdmiCecSinkLocked(mHdmiCecSink | false);
|
||||||
mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1124,7 +1127,7 @@ public class AudioService extends IAudioService.Stub
|
|||||||
if (isPlatformTelevision()) {
|
if (isPlatformTelevision()) {
|
||||||
synchronized (mHdmiClientLock) {
|
synchronized (mHdmiClientLock) {
|
||||||
if (mHdmiManager != null) {
|
if (mHdmiManager != null) {
|
||||||
mHdmiCecSink = false;
|
updateHdmiCecSinkLocked(mHdmiCecSink | false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5774,31 +5777,36 @@ public class AudioService extends IAudioService.Stub
|
|||||||
// are transformed into key events for the HDMI playback client.
|
// are transformed into key events for the HDMI playback client.
|
||||||
//==========================================================================================
|
//==========================================================================================
|
||||||
|
|
||||||
private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
|
@GuardedBy("mHdmiClientLock")
|
||||||
public void onComplete(int status) {
|
private void updateHdmiCecSinkLocked(boolean hdmiCecSink) {
|
||||||
|
mHdmiCecSink = hdmiCecSink;
|
||||||
|
if (mHdmiCecSink) {
|
||||||
|
if (DEBUG_VOL) {
|
||||||
|
Log.d(TAG, "CEC sink: setting HDMI as full vol device");
|
||||||
|
}
|
||||||
|
mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
|
||||||
|
} else {
|
||||||
|
if (DEBUG_VOL) {
|
||||||
|
Log.d(TAG, "TV, no CEC: setting HDMI as regular vol device");
|
||||||
|
}
|
||||||
|
// Android TV devices without CEC service apply software volume on
|
||||||
|
// 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) {
|
synchronized (mHdmiClientLock) {
|
||||||
if (mHdmiManager != null) {
|
if (mHdmiManager == null) return;
|
||||||
mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
|
updateHdmiCecSinkLocked(isCecEnabled ? isCecAvailable : false);
|
||||||
// Television devices without CEC service apply software volume on HDMI output
|
|
||||||
if (mHdmiCecSink) {
|
|
||||||
if (DEBUG_VOL) {
|
|
||||||
Log.d(TAG, "CEC sink: setting HDMI as full vol device");
|
|
||||||
}
|
|
||||||
mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
|
|
||||||
} else {
|
|
||||||
if (DEBUG_VOL) {
|
|
||||||
Log.d(TAG, "TV, no CEC: setting HDMI as regular vol device");
|
|
||||||
}
|
|
||||||
// Android TV devices without CEC service apply software volume on
|
|
||||||
// HDMI output
|
|
||||||
mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
|
|
||||||
}
|
|
||||||
checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI,
|
|
||||||
"HdmiPlaybackClient.DisplayStatusCallback");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
private final Object mHdmiClientLock = new Object();
|
private final Object mHdmiClientLock = new Object();
|
||||||
|
|
||||||
@@ -5815,12 +5823,14 @@ public class AudioService extends IAudioService.Stub
|
|||||||
@GuardedBy("mHdmiClientLock")
|
@GuardedBy("mHdmiClientLock")
|
||||||
private HdmiPlaybackClient mHdmiPlaybackClient;
|
private HdmiPlaybackClient mHdmiPlaybackClient;
|
||||||
// true if we are a set-top box, an HDMI sink is connected and it supports CEC.
|
// true if we are a set-top box, an HDMI sink is connected and it supports CEC.
|
||||||
|
@GuardedBy("mHdmiClientLock")
|
||||||
private boolean mHdmiCecSink;
|
private boolean mHdmiCecSink;
|
||||||
// Set only when device is an audio system.
|
// Set only when device is an audio system.
|
||||||
@GuardedBy("mHdmiClientLock")
|
@GuardedBy("mHdmiClientLock")
|
||||||
private HdmiAudioSystemClient mHdmiAudioSystemClient;
|
private HdmiAudioSystemClient mHdmiAudioSystemClient;
|
||||||
|
|
||||||
private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
|
private MyHdmiControlStatusChangeListenerCallback mHdmiControlStatusChangeListenerCallback =
|
||||||
|
new MyHdmiControlStatusChangeListenerCallback();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int setHdmiSystemAudioSupported(boolean on) {
|
public int setHdmiSystemAudioSupported(boolean on) {
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import android.hardware.hdmi.HdmiHotplugEvent;
|
|||||||
import android.hardware.hdmi.HdmiPortInfo;
|
import android.hardware.hdmi.HdmiPortInfo;
|
||||||
import android.hardware.hdmi.IHdmiControlCallback;
|
import android.hardware.hdmi.IHdmiControlCallback;
|
||||||
import android.hardware.hdmi.IHdmiControlService;
|
import android.hardware.hdmi.IHdmiControlService;
|
||||||
|
import android.hardware.hdmi.IHdmiControlStatusChangeListener;
|
||||||
import android.hardware.hdmi.IHdmiDeviceEventListener;
|
import android.hardware.hdmi.IHdmiDeviceEventListener;
|
||||||
import android.hardware.hdmi.IHdmiHotplugEventListener;
|
import android.hardware.hdmi.IHdmiHotplugEventListener;
|
||||||
import android.hardware.hdmi.IHdmiInputChangeListener;
|
import android.hardware.hdmi.IHdmiInputChangeListener;
|
||||||
@@ -251,6 +252,11 @@ public class HdmiControlService extends SystemService {
|
|||||||
// Type of logical devices hosted in the system. Stored in the unmodifiable list.
|
// Type of logical devices hosted in the system. Stored in the unmodifiable list.
|
||||||
private final List<Integer> mLocalDevices;
|
private final List<Integer> mLocalDevices;
|
||||||
|
|
||||||
|
// List of records for HDMI control status change listener for death monitoring.
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
private final ArrayList<HdmiControlStatusChangeListenerRecord>
|
||||||
|
mHdmiControlStatusChangeListenerRecords = new ArrayList<>();
|
||||||
|
|
||||||
// List of records for hotplug event listener to handle the the caller killed in action.
|
// List of records for hotplug event listener to handle the the caller killed in action.
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords =
|
private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords =
|
||||||
@@ -564,6 +570,7 @@ public class HdmiControlService extends SystemService {
|
|||||||
}
|
}
|
||||||
if (reason != -1) {
|
if (reason != -1) {
|
||||||
invokeVendorCommandListenersOnControlStateChanged(true, reason);
|
invokeVendorCommandListenersOnControlStateChanged(true, reason);
|
||||||
|
announceHdmiControlStatusChange(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1315,6 +1322,37 @@ public class HdmiControlService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Record class that monitors the event of the caller of being killed. Used to clean up
|
||||||
|
// the listener list and record list accordingly.
|
||||||
|
private final class HdmiControlStatusChangeListenerRecord implements IBinder.DeathRecipient {
|
||||||
|
private final IHdmiControlStatusChangeListener mListener;
|
||||||
|
|
||||||
|
HdmiControlStatusChangeListenerRecord(IHdmiControlStatusChangeListener listener) {
|
||||||
|
mListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void binderDied() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
mHdmiControlStatusChangeListenerRecords.remove(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (!(obj instanceof HdmiControlStatusChangeListenerRecord)) return false;
|
||||||
|
if (obj == this) return true;
|
||||||
|
HdmiControlStatusChangeListenerRecord other =
|
||||||
|
(HdmiControlStatusChangeListenerRecord) obj;
|
||||||
|
return other.mListener == this.mListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return mListener.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Record class that monitors the event of the caller of being killed. Used to clean up
|
// Record class that monitors the event of the caller of being killed. Used to clean up
|
||||||
// the listener list and record list accordingly.
|
// the listener list and record list accordingly.
|
||||||
private final class HotplugEventListenerRecord implements IBinder.DeathRecipient {
|
private final class HotplugEventListenerRecord implements IBinder.DeathRecipient {
|
||||||
@@ -1620,6 +1658,20 @@ public class HdmiControlService extends SystemService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addHdmiControlStatusChangeListener(
|
||||||
|
final IHdmiControlStatusChangeListener listener) {
|
||||||
|
enforceAccessPermission();
|
||||||
|
HdmiControlService.this.addHdmiControlStatusChangeListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeHdmiControlStatusChangeListener(
|
||||||
|
final IHdmiControlStatusChangeListener listener) {
|
||||||
|
enforceAccessPermission();
|
||||||
|
HdmiControlService.this.removeHdmiControlStatusChangeListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addHotplugEventListener(final IHdmiHotplugEventListener listener) {
|
public void addHotplugEventListener(final IHdmiHotplugEventListener listener) {
|
||||||
enforceAccessPermission();
|
enforceAccessPermission();
|
||||||
@@ -2135,6 +2187,51 @@ public class HdmiControlService extends SystemService {
|
|||||||
source.queryDisplayStatus(callback);
|
source.queryDisplayStatus(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addHdmiControlStatusChangeListener(
|
||||||
|
final IHdmiControlStatusChangeListener listener) {
|
||||||
|
final HdmiControlStatusChangeListenerRecord record =
|
||||||
|
new HdmiControlStatusChangeListenerRecord(listener);
|
||||||
|
try {
|
||||||
|
listener.asBinder().linkToDeath(record, 0);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Slog.w(TAG, "Listener already died");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
synchronized (mLock) {
|
||||||
|
mHdmiControlStatusChangeListenerRecords.add(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inform the listener of the initial state of each HDMI port by generating
|
||||||
|
// hotplug events.
|
||||||
|
runOnServiceThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
synchronized (mLock) {
|
||||||
|
if (!mHdmiControlStatusChangeListenerRecords.contains(record)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the current status of mHdmiControlEnabled;
|
||||||
|
synchronized (mLock) {
|
||||||
|
invokeHdmiControlStatusChangeListenerLocked(listener, mHdmiControlEnabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeHdmiControlStatusChangeListener(
|
||||||
|
final IHdmiControlStatusChangeListener listener) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
for (HdmiControlStatusChangeListenerRecord record :
|
||||||
|
mHdmiControlStatusChangeListenerRecords) {
|
||||||
|
if (record.mListener.asBinder() == listener.asBinder()) {
|
||||||
|
listener.asBinder().unlinkToDeath(record, 0);
|
||||||
|
mHdmiControlStatusChangeListenerRecords.remove(record);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void addHotplugEventListener(final IHdmiHotplugEventListener listener) {
|
private void addHotplugEventListener(final IHdmiHotplugEventListener listener) {
|
||||||
final HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener);
|
final HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener);
|
||||||
try {
|
try {
|
||||||
@@ -2367,6 +2464,47 @@ public class HdmiControlService extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void announceHdmiControlStatusChange(boolean isEnabled) {
|
||||||
|
assertRunOnServiceThread();
|
||||||
|
synchronized (mLock) {
|
||||||
|
for (HdmiControlStatusChangeListenerRecord record :
|
||||||
|
mHdmiControlStatusChangeListenerRecords) {
|
||||||
|
invokeHdmiControlStatusChangeListenerLocked(record.mListener, isEnabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invokeHdmiControlStatusChangeListenerLocked(
|
||||||
|
IHdmiControlStatusChangeListener listener, boolean isEnabled) {
|
||||||
|
if (isEnabled) {
|
||||||
|
queryDisplayStatus(new IHdmiControlCallback.Stub() {
|
||||||
|
public void onComplete(int status) {
|
||||||
|
boolean isAvailable = true;
|
||||||
|
if (status == HdmiControlManager.POWER_STATUS_UNKNOWN
|
||||||
|
|| status == HdmiControlManager.RESULT_EXCEPTION
|
||||||
|
|| status == HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE) {
|
||||||
|
isAvailable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
listener.onStatusChange(isEnabled, isAvailable);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Slog.e(TAG, "Failed to report HdmiControlStatusChange: " + isEnabled
|
||||||
|
+ " isAvailable: " + isAvailable, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
listener.onStatusChange(isEnabled, false);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Slog.e(TAG, "Failed to report HdmiControlStatusChange: " + isEnabled
|
||||||
|
+ " isAvailable: " + false, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public HdmiCecLocalDeviceTv tv() {
|
public HdmiCecLocalDeviceTv tv() {
|
||||||
return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV);
|
return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV);
|
||||||
}
|
}
|
||||||
@@ -2736,6 +2874,8 @@ public class HdmiControlService extends SystemService {
|
|||||||
disableHdmiControlService();
|
disableHdmiControlService();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
announceHdmiControlStatusChange(enabled);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user