Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c2d26a08 authored by Wonsik Kim's avatar Wonsik Kim Committed by Android (Google) Code Review
Browse files

Merge "TIF: add signal detection feature for HW inputs"

parents a416cd02 102d0b7b
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -23791,6 +23791,7 @@ package android.media.tv {
  public class TvStreamConfig implements android.os.Parcelable {
    method public int describeContents();
    method public int getFlags();
    method public int getGeneration();
    method public int getMaxHeight();
    method public int getMaxWidth();
@@ -23798,6 +23799,7 @@ package android.media.tv {
    method public int getType();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.media.tv.TvStreamConfig> CREATOR;
    field public static final int FLAG_MASK_SIGNAL_DETECTION = 1; // 0x1
    field public static final int STREAM_TYPE_BUFFER_PRODUCER = 2; // 0x2
    field public static final int STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE = 1; // 0x1
  }
@@ -23805,6 +23807,7 @@ package android.media.tv {
  public static final class TvStreamConfig.Builder {
    ctor public TvStreamConfig.Builder();
    method public android.media.tv.TvStreamConfig build();
    method public android.media.tv.TvStreamConfig.Builder flags(int);
    method public android.media.tv.TvStreamConfig.Builder generation(int);
    method public android.media.tv.TvStreamConfig.Builder maxHeight(int);
    method public android.media.tv.TvStreamConfig.Builder maxWidth(int);
+4 −4
Original line number Diff line number Diff line
@@ -129,9 +129,8 @@ public final class TvInputManager {
     * The TV input 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.
     *
     * @see #getInputState
     * @see TvInputManager.TvInputCallback#onInputStateChanged
@@ -141,7 +140,8 @@ public final class TvInputManager {
     * The TV input is connected but 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 inputs and Component
     * inputs.
     *
     * @see #getInputState
     * @see TvInputManager.TvInputCallback#onInputStateChanged
+27 −2
Original line number Diff line number Diff line
@@ -28,8 +28,15 @@ import android.util.Log;
public class TvStreamConfig implements Parcelable {
    static final String TAG = TvStreamConfig.class.getSimpleName();

    // Must be in sync with tv_input.h
    public final static int STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE = 1;
    public final static int STREAM_TYPE_BUFFER_PRODUCER = 2;
    /**
     * A flag indicating whether the HAL is sure about signal at this stream. Note that
     * value of 0 here does not necessarily mean no signal. It just means that it may not have
     * signal and the underlying layer is not sure.
     */
    public static final int FLAG_MASK_SIGNAL_DETECTION = 0x1;

    private int mStreamId;
    private int mType;
@@ -41,6 +48,10 @@ public class TvStreamConfig implements Parcelable {
     * via tv_input_device::get_stream_configurations().
     */
    private int mGeneration;
    /**
     * Flags for stream status. See FLAG_MASK_* for details.
     */
    private int mFlags;

    public static final Parcelable.Creator<TvStreamConfig> CREATOR =
            new Parcelable.Creator<TvStreamConfig>() {
@@ -52,7 +63,8 @@ public class TvStreamConfig implements Parcelable {
                        type(source.readInt()).
                        maxWidth(source.readInt()).
                        maxHeight(source.readInt()).
                        generation(source.readInt()).build();
                        generation(source.readInt()).
                        flags(source.readInt()).build();
            } catch (Exception e) {
                Log.e(TAG, "Exception creating TvStreamConfig from parcel", e);
                return null;
@@ -87,6 +99,10 @@ public class TvStreamConfig implements Parcelable {
        return mGeneration;
    }

    public int getFlags() {
        return mFlags;
    }

    @Override
    public String toString() {
        return "TvStreamConfig {mStreamId=" + mStreamId + ";" + "mType=" + mType + ";mGeneration="
@@ -106,6 +122,7 @@ public class TvStreamConfig implements Parcelable {
        dest.writeInt(mMaxWidth);
        dest.writeInt(mMaxHeight);
        dest.writeInt(mGeneration);
        dest.writeInt(mFlags);
    }

    /**
@@ -117,6 +134,7 @@ public class TvStreamConfig implements Parcelable {
        private Integer mMaxWidth;
        private Integer mMaxHeight;
        private Integer mGeneration;
        private int mFlags = 0;

        public Builder() {
        }
@@ -146,6 +164,11 @@ public class TvStreamConfig implements Parcelable {
            return this;
        }

        public Builder flags(int flag) {
            mFlags = flag;
            return this;
        }

        public TvStreamConfig build() {
            if (mStreamId == null || mType == null || mMaxWidth == null || mMaxHeight == null
                    || mGeneration == null) {
@@ -158,6 +181,7 @@ public class TvStreamConfig implements Parcelable {
            config.mMaxWidth = mMaxWidth;
            config.mMaxHeight = mMaxHeight;
            config.mGeneration = mGeneration;
            config.mFlags = mFlags;
            return config;
        }
    }
@@ -172,6 +196,7 @@ public class TvStreamConfig implements Parcelable {
            && config.mStreamId == mStreamId
            && config.mType == mType
            && config.mMaxWidth == mMaxWidth
            && config.mMaxHeight == mMaxHeight;
            && config.mMaxHeight == mMaxHeight
            && config.mFlags == mFlags;
    }
}
+25 −13
Original line number Diff line number Diff line
@@ -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;
@@ -102,7 +103,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<>();

@@ -206,7 +206,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
            String inputId = mHardwareInputIdMap.get(deviceId);
            if (inputId != null) {
                mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
                        convertConnectedToState(configs.length > 0), 0, inputId).sendToTarget();
                        obtainStateFromConfigs(configs), 0, inputId).sendToTarget();
            }
            ITvInputHardwareCallback callback = connection.getCallbackLocked();
            if (callback != null) {
@@ -256,13 +256,14 @@ class TvInputHardwareManager implements TvInputHal.Callback {
                || connectionCallingUid != callingUid || connectionResolvedUserId != resolvedUserId;
    }

    private int convertConnectedToState(boolean connected) {
        if (connected) {
    private int obtainStateFromConfigs(TvStreamConfig[] configs) {
        for (TvStreamConfig config : configs) {
            if ((config.getFlags() & TvStreamConfig.FLAG_MASK_SIGNAL_DETECTION) != 0) {
                return INPUT_STATE_CONNECTED;
        } else {
            return INPUT_STATE_DISCONNECTED;
            }
        }
        return (configs.length > 0) ? INPUT_STATE_CONNECTED_STANDBY : INPUT_STATE_DISCONNECTED;
    }

    public void addHardwareTvInput(int deviceId, TvInputInfo info) {
        synchronized (mLock) {
@@ -286,9 +287,14 @@ 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;
                }
            }
@@ -296,7 +302,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
            Connection connection = mConnections.get(deviceId);
            if (connection != null) {
                mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
                        convertConnectedToState(connection.getConfigsLocked().length > 0), 0,
                        obtainStateFromConfigs(connection.getConfigsLocked()), 0,
                        info.getId()).sendToTarget();
            }
        }
@@ -1110,8 +1116,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();
            }
        }
    }
+60 −21
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ static struct {
    jmethodID maxWidth;
    jmethodID maxHeight;
    jmethodID generation;
    jmethodID flags;
    jmethodID build;
} gTvStreamConfigBuilderClassInfo;

@@ -239,7 +240,7 @@ public:

    int addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface);
    int removeStream(int deviceId, int streamId);
    const tv_stream_config_t* getStreamConfigs(int deviceId, int* numConfigs);
    const tv_stream_config_ext_t* getStreamConfigs(int deviceId, int* numConfigs);

    void onDeviceAvailable(const tv_input_device_info_t& info);
    void onDeviceUnavailable(int deviceId);
@@ -288,10 +289,15 @@ private:
    sp<Looper> mLooper;

    KeyedVector<int, KeyedVector<int, Connection> > mConnections;

    tv_stream_config_ext_t* mConfigBuffer;
    int mConfigBufferSize;
};

JTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* device,
        const sp<Looper>& looper) {
        const sp<Looper>& looper)
    : mConfigBuffer(NULL),
      mConfigBufferSize(0) {
    mThiz = env->NewWeakGlobalRef(thiz);
    mDevice = device;
    mCallback.notify = &JTvInputHal::notify;
@@ -306,6 +312,10 @@ JTvInputHal::~JTvInputHal() {
    JNIEnv* env = AndroidRuntime::getJNIEnv();
    env->DeleteWeakGlobalRef(mThiz);
    mThiz = NULL;

    if (mConfigBuffer != NULL) {
        delete[] mConfigBuffer;
    }
}

JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz, const sp<Looper>& looper) {
@@ -354,15 +364,14 @@ int JTvInputHal::addOrUpdateStream(int deviceId, int streamId, const sp<Surface>
    if (connection.mSourceHandle == NULL && connection.mThread == NULL) {
        // Need to configure stream
        int numConfigs = 0;
        const tv_stream_config_t* configs = NULL;
        if (mDevice->get_stream_configurations(
                mDevice, deviceId, &numConfigs, &configs) != 0) {
        const tv_stream_config_ext_t* configs = getStreamConfigs(deviceId, &numConfigs);
        if (configs == NULL) {
            ALOGE("Couldn't get stream configs");
            return UNKNOWN_ERROR;
        }
        int configIndex = -1;
        for (int i = 0; i < numConfigs; ++i) {
            if (configs[i].stream_id == streamId) {
            if (configs[i].config.stream_id == streamId) {
                configIndex = i;
                break;
            }
@@ -371,13 +380,13 @@ int JTvInputHal::addOrUpdateStream(int deviceId, int streamId, const sp<Surface>
            ALOGE("Cannot find a config with given stream ID: %d", streamId);
            return BAD_VALUE;
        }
        connection.mStreamType = configs[configIndex].type;
        connection.mStreamType = configs[configIndex].config.type;

        tv_stream_t stream;
        stream.stream_id = configs[configIndex].stream_id;
        stream.stream_id = configs[configIndex].config.stream_id;
        if (connection.mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER) {
            stream.buffer_producer.width = configs[configIndex].max_video_width;
            stream.buffer_producer.height = configs[configIndex].max_video_height;
            stream.buffer_producer.width = configs[configIndex].config.max_video_width;
            stream.buffer_producer.height = configs[configIndex].config.max_video_height;
        }
        if (mDevice->open_stream(mDevice, deviceId, &stream) != 0) {
            ALOGE("Couldn't add stream");
@@ -431,13 +440,34 @@ int JTvInputHal::removeStream(int deviceId, int streamId) {
    return NO_ERROR;
}

const tv_stream_config_t* JTvInputHal::getStreamConfigs(int deviceId, int* numConfigs) {
    const tv_stream_config_t* configs = NULL;
    if (mDevice->get_stream_configurations(
const tv_stream_config_ext_t* JTvInputHal::getStreamConfigs(int deviceId, int* numConfigs) {
    const tv_stream_config_ext_t* configs = NULL;
    if (mDevice->common.version >= TV_INPUT_DEVICE_API_VERSION_0_2) {
        if (mDevice->get_stream_configurations_ext(
                mDevice, deviceId, numConfigs, &configs) != 0) {
            ALOGE("Couldn't get stream configs");
            return NULL;
        }
    } else {
        const tv_stream_config_t* oldConfigs;
        if (mDevice->get_stream_configurations(
                mDevice, deviceId, numConfigs, &oldConfigs) != 0) {
            ALOGE("Couldn't get stream configs");
            return NULL;
        }
        if (mConfigBufferSize < *numConfigs) {
            mConfigBufferSize = (*numConfigs / 16 + 1) * 16;
            if (mConfigBuffer != NULL) {
                delete[] mConfigBuffer;
            }
            mConfigBuffer = new tv_stream_config_ext_t[mConfigBufferSize];
        }
        for (int i = 0; i < *numConfigs; ++i) {
            mConfigBuffer[i].config = oldConfigs[i];
            mConfigBuffer[i].flags = 0;
        }
        configs = mConfigBuffer;
    }
    return configs;
}

@@ -629,7 +659,7 @@ static jobjectArray nativeGetStreamConfigs(JNIEnv* env, jclass clazz,
        jlong ptr, jint deviceId, jint generation) {
    JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
    int numConfigs = 0;
    const tv_stream_config_t* configs = tvInputHal->getStreamConfigs(deviceId, &numConfigs);
    const tv_stream_config_ext_t* configs = tvInputHal->getStreamConfigs(deviceId, &numConfigs);

    jobjectArray result = env->NewObjectArray(numConfigs, gTvStreamConfigClassInfo.clazz, NULL);
    for (int i = 0; i < numConfigs; ++i) {
@@ -637,15 +667,20 @@ static jobjectArray nativeGetStreamConfigs(JNIEnv* env, jclass clazz,
                gTvStreamConfigBuilderClassInfo.clazz,
                gTvStreamConfigBuilderClassInfo.constructor);
        env->CallObjectMethod(
                builder, gTvStreamConfigBuilderClassInfo.streamId, configs[i].stream_id);
                builder, gTvStreamConfigBuilderClassInfo.streamId, configs[i].config.stream_id);
        env->CallObjectMethod(
                builder, gTvStreamConfigBuilderClassInfo.type, configs[i].type);
                builder, gTvStreamConfigBuilderClassInfo.type, configs[i].config.type);
        env->CallObjectMethod(
                builder, gTvStreamConfigBuilderClassInfo.maxWidth, configs[i].max_video_width);
                builder, gTvStreamConfigBuilderClassInfo.maxWidth,
                configs[i].config.max_video_width);
        env->CallObjectMethod(
                builder, gTvStreamConfigBuilderClassInfo.maxHeight, configs[i].max_video_height);
                builder, gTvStreamConfigBuilderClassInfo.maxHeight,
                configs[i].config.max_video_height);
        env->CallObjectMethod(
                builder, gTvStreamConfigBuilderClassInfo.generation, generation);
        env->CallObjectMethod(
                builder, gTvStreamConfigBuilderClassInfo.flags,
                configs[i].flags);

        jobject config = env->CallObjectMethod(builder, gTvStreamConfigBuilderClassInfo.build);

@@ -736,6 +771,10 @@ int register_android_server_tv_TvInputHal(JNIEnv* env) {
            gTvStreamConfigBuilderClassInfo.generation,
            gTvStreamConfigBuilderClassInfo.clazz,
            "generation", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
    GET_METHOD_ID(
            gTvStreamConfigBuilderClassInfo.flags,
            gTvStreamConfigBuilderClassInfo.clazz,
            "flags", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
    GET_METHOD_ID(
            gTvStreamConfigBuilderClassInfo.build,
            gTvStreamConfigBuilderClassInfo.clazz,