diff options
6 files changed, 119 insertions, 36 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index 7c63e774e079..32fc2880ba67 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -26305,11 +26305,15 @@ package android.media.tv { method public int describeContents(); method public java.lang.String getAudioAddress(); method public int getAudioType(); + method public int getCableConnectionStatus(); method public int getDeviceId(); method public int getHdmiPortId(); method public int getType(); method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); + field public static final int CABLE_CONNECTION_STATUS_CONNECTED = 1; // 0x1 + field public static final int CABLE_CONNECTION_STATUS_DISCONNECTED = 2; // 0x2 + field public static final int CABLE_CONNECTION_STATUS_UNKNOWN = 0; // 0x0 field public static final android.os.Parcelable.Creator<android.media.tv.TvInputHardwareInfo> CREATOR; field public static final int TV_INPUT_TYPE_COMPONENT = 6; // 0x6 field public static final int TV_INPUT_TYPE_COMPOSITE = 3; // 0x3 @@ -26328,6 +26332,7 @@ package android.media.tv { method public android.media.tv.TvInputHardwareInfo.Builder audioAddress(java.lang.String); method public android.media.tv.TvInputHardwareInfo.Builder audioType(int); method public android.media.tv.TvInputHardwareInfo build(); + method public android.media.tv.TvInputHardwareInfo.Builder cableConnectionStatus(int); method public android.media.tv.TvInputHardwareInfo.Builder deviceId(int); method public android.media.tv.TvInputHardwareInfo.Builder hdmiPortId(int); method public android.media.tv.TvInputHardwareInfo.Builder type(int); diff --git a/media/java/android/media/tv/TvInputHardwareInfo.java b/media/java/android/media/tv/TvInputHardwareInfo.java index 51fa036a77c4..957c5820838e 100644 --- a/media/java/android/media/tv/TvInputHardwareInfo.java +++ b/media/java/android/media/tv/TvInputHardwareInfo.java @@ -16,11 +16,15 @@ package android.media.tv; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.annotation.IntDef; import android.annotation.SystemApi; import android.media.AudioManager; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; +import java.lang.annotation.Retention; /** * Simple container for information about TV input hardware. @@ -44,6 +48,28 @@ public final class TvInputHardwareInfo implements Parcelable { public static final int TV_INPUT_TYPE_HDMI = 9; public static final int TV_INPUT_TYPE_DISPLAY_PORT = 10; + /** @hide */ + @Retention(SOURCE) + @IntDef({CABLE_CONNECTION_STATUS_UNKNOWN, CABLE_CONNECTION_STATUS_CONNECTED, + CABLE_CONNECTION_STATUS_DISCONNECTED}) + public @interface CableConnectionStatus {} + + // Match hardware/interfaces/tv/input/1.0/types.hal + /** + * The hardware is unsure about the connection status or does not support cable detection. + */ + public static final int CABLE_CONNECTION_STATUS_UNKNOWN = 0; + + /** + * Cable is connected to the hardware. + */ + public static final int CABLE_CONNECTION_STATUS_CONNECTED = 1; + + /** + * Cable is disconnected to the hardware. + */ + public static final int CABLE_CONNECTION_STATUS_DISCONNECTED = 2; + public static final Parcelable.Creator<TvInputHardwareInfo> CREATOR = new Parcelable.Creator<TvInputHardwareInfo>() { @Override @@ -69,6 +95,8 @@ public final class TvInputHardwareInfo implements Parcelable { private int mAudioType; private String mAudioAddress; private int mHdmiPortId; + @CableConnectionStatus + private int mCableConnectionStatus; private TvInputHardwareInfo() { } @@ -96,6 +124,19 @@ public final class TvInputHardwareInfo implements Parcelable { return mHdmiPortId; } + /** + * Gets the cable connection status of the hardware. + * + * @return {@code CABLE_CONNECTION_STATUS_CONNECTED} if cable is connected. + * {@code CABLE_CONNECTION_STATUS_DISCONNECTED} if cable is disconnected. + * {@code CABLE_CONNECTION_STATUS_UNKNOWN} if the hardware is unsure about the + * connection status or does not support cable detection. + */ + @CableConnectionStatus + public int getCableConnectionStatus() { + return mCableConnectionStatus; + } + @Override public String toString() { StringBuilder b = new StringBuilder(128); @@ -106,6 +147,7 @@ public final class TvInputHardwareInfo implements Parcelable { if (mType == TV_INPUT_TYPE_HDMI) { b.append(", hdmi_port=").append(mHdmiPortId); } + b.append(", cable_connection_status=").append(mCableConnectionStatus); b.append("}"); return b.toString(); } @@ -125,6 +167,7 @@ public final class TvInputHardwareInfo implements Parcelable { if (mType == TV_INPUT_TYPE_HDMI) { dest.writeInt(mHdmiPortId); } + dest.writeInt(mCableConnectionStatus); } public void readFromParcel(Parcel source) { @@ -135,6 +178,7 @@ public final class TvInputHardwareInfo implements Parcelable { if (mType == TV_INPUT_TYPE_HDMI) { mHdmiPortId = source.readInt(); } + mCableConnectionStatus = source.readInt(); } public static final class Builder { @@ -143,6 +187,7 @@ public final class TvInputHardwareInfo implements Parcelable { private int mAudioType = AudioManager.DEVICE_NONE; private String mAudioAddress = ""; private Integer mHdmiPortId = null; + private Integer mCableConnectionStatus = CABLE_CONNECTION_STATUS_UNKNOWN; public Builder() { } @@ -172,6 +217,14 @@ public final class TvInputHardwareInfo implements Parcelable { return this; } + /** + * Sets cable connection status. + */ + public Builder cableConnectionStatus(@CableConnectionStatus int cableConnectionStatus) { + mCableConnectionStatus = cableConnectionStatus; + return this; + } + public TvInputHardwareInfo build() { if (mDeviceId == null || mType == null) { throw new UnsupportedOperationException(); @@ -191,6 +244,7 @@ public final class TvInputHardwareInfo implements Parcelable { if (mHdmiPortId != null) { info.mHdmiPortId = mHdmiPortId; } + info.mCableConnectionStatus = mCableConnectionStatus; return info; } } diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index 1eae8db60833..09b2050b1b1a 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -224,9 +224,8 @@ public final class TvInputManager { * {@link TvInputCallback#onInputStateChanged(String, int)}: The input source is connected. * * <p>This state indicates that a source device is connected to the input port and is in the - * normal operation mode. It is mostly relevant to hardware inputs such as HDMI input. This is - * the default state for any hardware inputs where their states are unknown. Non-hardware inputs - * are considered connected all the time. + * normal operation mode. It is mostly relevant to hardware inputs such as HDMI input. + * Non-hardware inputs are considered connected all the time. */ public static final int INPUT_STATE_CONNECTED = 0; @@ -236,7 +235,8 @@ public final class TvInputManager { * in standby mode. * * <p>This state indicates that a source device is connected to the input port but is in standby - * mode. It is mostly relevant to hardware inputs such as HDMI input. + * or low power mode. It is mostly relevant to hardware inputs such as HDMI input and Component + * inputs. */ public static final int INPUT_STATE_CONNECTED_STANDBY = 1; diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java index 8043c651751c..08eca73e1702 100644 --- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java +++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java @@ -17,6 +17,7 @@ package com.android.server.tv; import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED; +import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED_STANDBY; import static android.media.tv.TvInputManager.INPUT_STATE_DISCONNECTED; import android.content.BroadcastReceiver; @@ -109,7 +110,6 @@ class TvInputHardwareManager implements TvInputHal.Callback { private int mCurrentIndex = 0; private int mCurrentMaxIndex = 0; - // TODO: Should handle STANDBY case. private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray(); private final List<Message> mPendingHdmiDeviceEvents = new LinkedList<>(); @@ -209,11 +209,13 @@ class TvInputHardwareManager implements TvInputHal.Callback { + deviceId); return; } + int previousConfigsLength = connection.getConfigsLengthLocked(); connection.updateConfigsLocked(configs); String inputId = mHardwareInputIdMap.get(deviceId); - if (inputId != null) { + if (inputId != null + && (previousConfigsLength == 0) != (connection.getConfigsLengthLocked() == 0)) { mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, - convertConnectedToState(configs.length > 0), 0, inputId).sendToTarget(); + connection.getInputStateLocked(), 0, inputId).sendToTarget(); } ITvInputHardwareCallback callback = connection.getCallbackLocked(); if (callback != null) { @@ -263,14 +265,6 @@ class TvInputHardwareManager implements TvInputHal.Callback { || connectionCallingUid != callingUid || connectionResolvedUserId != resolvedUserId; } - private int convertConnectedToState(boolean connected) { - if (connected) { - return INPUT_STATE_CONNECTED; - } else { - return INPUT_STATE_DISCONNECTED; - } - } - public void addHardwareInput(int deviceId, TvInputInfo info) { synchronized (mLock) { String oldInputId = mHardwareInputIdMap.get(deviceId); @@ -293,18 +287,22 @@ class TvInputHardwareManager implements TvInputHal.Callback { } String inputId = mHardwareInputIdMap.get(hardwareInfo.getDeviceId()); if (inputId != null && inputId.equals(info.getId())) { - mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, - convertConnectedToState(mHdmiStateMap.valueAt(i)), 0, - inputId).sendToTarget(); + // No HDMI hotplug does not necessarily mean disconnected, as old devices may + // not report hotplug state correctly. Using INPUT_STATE_CONNECTED_STANDBY to + // denote unknown state. + int state = mHdmiStateMap.valueAt(i) + ? INPUT_STATE_CONNECTED + : INPUT_STATE_CONNECTED_STANDBY; + mHandler.obtainMessage( + ListenerHandler.STATE_CHANGED, state, 0, inputId).sendToTarget(); return; } } - // For the rest of the devices, we can tell by the number of available streams. + // For the rest of the devices, we can tell by the cable connection status. Connection connection = mConnections.get(deviceId); if (connection != null) { mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, - convertConnectedToState(connection.getConfigsLocked().length > 0), 0, - info.getId()).sendToTarget(); + connection.getInputStateLocked(), 0, info.getId()).sendToTarget(); } } } @@ -716,6 +714,26 @@ class TvInputHardwareManager implements TvInputHal.Callback { + ", mResolvedUserId: " + mResolvedUserId + " }"; } + + private int getConfigsLengthLocked() { + return mConfigs == null ? 0 : mConfigs.length; + } + + private int getInputStateLocked() { + int configsLength = getConfigsLengthLocked(); + if (configsLength > 0) { + return INPUT_STATE_CONNECTED; + } + switch (mHardwareInfo.getCableConnectionStatus()) { + case TvInputHardwareInfo.CABLE_CONNECTION_STATUS_CONNECTED: + return INPUT_STATE_CONNECTED; + case TvInputHardwareInfo.CABLE_CONNECTION_STATUS_DISCONNECTED: + return INPUT_STATE_DISCONNECTED; + case TvInputHardwareInfo.CABLE_CONNECTION_STATUS_UNKNOWN: + default: + return INPUT_STATE_CONNECTED_STANDBY; + } + } } private class TvInputHardwareImpl extends ITvInputHardware.Stub { @@ -1199,8 +1217,14 @@ class TvInputHardwareManager implements TvInputHal.Callback { if (inputId == null) { return; } - mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, - convertConnectedToState(event.isConnected()), 0, inputId).sendToTarget(); + // No HDMI hotplug does not necessarily mean disconnected, as old devices may + // not report hotplug state correctly. Using INPUT_STATE_CONNECTED_STANDBY to + // denote unknown state. + int state = event.isConnected() + ? INPUT_STATE_CONNECTED + : INPUT_STATE_CONNECTED_STANDBY; + mHandler.obtainMessage( + ListenerHandler.STATE_CHANGED, state, 0, inputId).sendToTarget(); } } } diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index e0261304f0f0..52763a179e73 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -288,7 +288,7 @@ public final class TvInputManagerService extends SystemService { userState.serviceStateMap.put(component, serviceState); updateServiceConnectionLocked(component, userId); } else { - inputList.addAll(serviceState.hardwareInputList); + inputList.addAll(serviceState.hardwareInputMap.values()); } } else { try { @@ -2105,7 +2105,7 @@ public final class TvInputManagerService extends SystemService { private final ServiceConnection connection; private final ComponentName component; private final boolean isHardware; - private final List<TvInputInfo> hardwareInputList = new ArrayList<>(); + private final Map<String, TvInputInfo> hardwareInputMap = new HashMap<>(); private ITvInputService service; private ServiceCallback callback; @@ -2216,7 +2216,7 @@ public final class TvInputManagerService extends SystemService { } if (serviceState.isHardware) { - serviceState.hardwareInputList.clear(); + serviceState.hardwareInputMap.clear(); for (TvInputHardwareInfo hardware : mTvInputHardwareManager.getHardwareList()) { try { serviceState.service.notifyHardwareAdded(hardware); @@ -2283,7 +2283,7 @@ public final class TvInputManagerService extends SystemService { private void addHardwareInputLocked(TvInputInfo inputInfo) { ServiceState serviceState = getServiceStateLocked(mComponent, mUserId); - serviceState.hardwareInputList.add(inputInfo); + serviceState.hardwareInputMap.put(inputInfo.getId(), inputInfo); buildTvInputListLocked(mUserId, null); } @@ -2309,15 +2309,7 @@ public final class TvInputManagerService extends SystemService { ensureHardwarePermission(); synchronized (mLock) { ServiceState serviceState = getServiceStateLocked(mComponent, mUserId); - boolean removed = false; - for (Iterator<TvInputInfo> it = serviceState.hardwareInputList.iterator(); - it.hasNext(); ) { - if (it.next().getId().equals(inputId)) { - it.remove(); - removed = true; - break; - } - } + boolean removed = serviceState.hardwareInputMap.remove(inputId) != null; if (removed) { buildTvInputListLocked(mUserId, null); mTvInputHardwareManager.removeHardwareInput(inputId); diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp index 9f528b1bec6a..b4333508a84a 100644 --- a/services/core/jni/com_android_server_tv_TvInputHal.cpp +++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp @@ -81,6 +81,7 @@ static struct { jmethodID deviceId; jmethodID type; jmethodID hdmiPortId; + jmethodID cableConnectionStatus; jmethodID audioType; jmethodID audioAddress; jmethodID build; @@ -469,6 +470,9 @@ void JTvInputHal::onDeviceAvailable(const TvInputDeviceInfo& info) { builder, gTvInputHardwareInfoBuilderClassInfo.hdmiPortId, info.portId); } env->CallObjectMethod( + builder, gTvInputHardwareInfoBuilderClassInfo.cableConnectionStatus, + info.cableConnectionStatus); + env->CallObjectMethod( builder, gTvInputHardwareInfoBuilderClassInfo.audioType, info.audioType); if (info.audioType != AudioDevice::NONE) { uint8_t buffer[info.audioAddress.size() + 1]; @@ -743,6 +747,10 @@ int register_android_server_tv_TvInputHal(JNIEnv* env) { gTvInputHardwareInfoBuilderClassInfo.clazz, "hdmiPortId", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;"); GET_METHOD_ID( + gTvInputHardwareInfoBuilderClassInfo.cableConnectionStatus, + gTvInputHardwareInfoBuilderClassInfo.clazz, + "cableConnectionStatus", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;"); + GET_METHOD_ID( gTvInputHardwareInfoBuilderClassInfo.audioType, gTvInputHardwareInfoBuilderClassInfo.clazz, "audioType", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;"); |