OSDN Git Service

Add two apis for one touch record.
authorJungshik Jang <jayjang@google.com>
Wed, 16 Jul 2014 09:04:49 +0000 (18:04 +0900)
committerJungshik Jang <jayjang@google.com>
Mon, 21 Jul 2014 07:54:53 +0000 (16:54 +0900)
This change introduces new two apis for one touch record.
1. setRecordRequestListener
 It's used to get notified when a recorder device initiates
 "one touch record". As return of callback, client should
 generate "record source" and return it.
2. startRecord
 It's used to initiate "one touch record" from Tv.

Along with this, add HdmiRecordSources which is a helper
class assisting buidling byte array form from the given
record source information.

Bug: 16160962

Change-Id: I403d37b752c9b7f799c6d8188a071ef420fe8ac2

Android.mk
core/java/android/hardware/hdmi/HdmiRecordSources.java [new file with mode: 0644]
core/java/android/hardware/hdmi/HdmiTvClient.java
core/java/android/hardware/hdmi/IHdmiControlService.aidl
core/java/android/hardware/hdmi/IHdmiRecordRequestListener.aidl [new file with mode: 0644]
services/core/java/com/android/server/hdmi/Constants.java
services/core/java/com/android/server/hdmi/HdmiControlService.java
services/core/java/com/android/server/hdmi/OneTouchRecordAction.java

index 3b01f70..0d02be7 100644 (file)
@@ -155,6 +155,7 @@ LOCAL_SRC_FILES += \
        core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl \
        core/java/android/hardware/hdmi/IHdmiHotplugEventListener.aidl \
        core/java/android/hardware/hdmi/IHdmiInputChangeListener.aidl \
+       core/java/android/hardware/hdmi/IHdmiRecordRequestListener.aidl \
        core/java/android/hardware/hdmi/IHdmiSystemAudioModeChangeListener.aidl \
        core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl \
        core/java/android/hardware/input/IInputManager.aidl \
diff --git a/core/java/android/hardware/hdmi/HdmiRecordSources.java b/core/java/android/hardware/hdmi/HdmiRecordSources.java
new file mode 100644 (file)
index 0000000..5a02c34
--- /dev/null
@@ -0,0 +1,743 @@
+/*
+ * Copyright (C) 2014 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.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.util.Log;
+
+/**
+ * Container for record source used for one touch record.
+ * Use one of helper method by source type.
+ * <ul>
+ * <li>Own source: {@link #ofOwnSource()}
+ * <li>Digital service(channel id): {@link #ofDigitalChannelId(int, DigitalChannelData)}
+ * <li>Digital service(ARIB): {@link #ofArib(int, AribData)}
+ * <li>Digital service(ATSC): {@link #ofAtsc(int, AtscData)}
+ * <li>Digital service(DVB): {@link #ofDvb(int, DvbData)}
+ * <li>Analogue: {@link #ofAnalogue(int, int, int)}
+ * <li>External plug: {@link #ofExternalPlug(int)}
+ * <li>External physical address: {@link #ofExternalPhysicalAddress(int)}.
+ * <ul>
+ *
+ * @hide
+ */
+@SystemApi
+public final class HdmiRecordSources {
+    private static final String TAG = "HdmiRecordSources";
+
+    /** Record source type for "Own Source". */
+    private static final int RECORD_SOURCE_TYPE_OWN_SOURCE = 1;
+    /** Record source type for "Digital Service". */
+    private static final int RECORD_SOURCE_TYPE_DIGITAL_SERVICE = 2;
+    /** Record source type for "Analogue Service". */
+    private static final int RECORD_SOURCE_TYPE_ANALOGUE_SERVICE = 3;
+    /** Record source type for "Exteranl Plug". */
+    private static final int RECORD_SOURCE_TYPE_EXTERNAL_PLUG = 4;
+    /** Record source type for "External Physical Address". */
+    private static final int RECORD_SOURCE_TYPE_EXTERNAL_PHYSICAL_ADDRESS = 5;
+
+    private HdmiRecordSources() {}
+
+    /**
+     * Base class for each record source.
+     */
+    static abstract class RecordSource {
+        protected final int mSourceType;
+        protected final int mExtraDataSize;
+
+        protected RecordSource(int sourceType, int extraDataSize) {
+            mSourceType = sourceType;
+            mExtraDataSize = extraDataSize;
+        }
+
+        abstract int extraParamToByteArray(byte[] data, int index);
+
+        final int getDataSize(boolean includeType)  {
+            return includeType ? mExtraDataSize + 1 : mExtraDataSize;
+        }
+
+        public final int toByteArray(boolean includeType, byte[] data, int index) {
+            if (includeType) {
+                // 1 to 8 bytes (depends on source).
+                // {[Record Source Type]} |
+                // {[Record Source Type] [Digital Service Identification]} |
+                // {[Record Source Type] [Analogue Broadcast Type] [Analogue Frequency]
+                // [Broadcast System]} |
+                // {[Record Source Type] [External Plug]} |
+                // {[Record Source Type] [External Physical Address]}
+                // The first byte is used for record source type.
+                data[index++] = (byte) mSourceType;
+            }
+            extraParamToByteArray(data, index);
+            return getDataSize(includeType);
+        }
+    }
+
+    // ---------------------------------------------------------------------------------------------
+    // ---- Own source -----------------------------------------------------------------------------
+    // ---------------------------------------------------------------------------------------------
+    /**
+     * Create {@link OwnSource} of own source.
+     */
+    public static OwnSource ofOwnSource() {
+        return new OwnSource();
+    }
+
+    /**
+     * @hide
+     */
+    @SystemApi
+    public static final class OwnSource extends RecordSource {
+        protected OwnSource() {
+            super(RECORD_SOURCE_TYPE_OWN_SOURCE, 0);
+        }
+
+        @Override
+        int extraParamToByteArray(byte[] data, int index) {
+            return 0;
+        }
+    }
+
+
+    // ---------------------------------------------------------------------------------------------
+    // ---- Digital service data -------------------------------------------------------------------
+    // ---------------------------------------------------------------------------------------------
+    /**
+     * Digital broadcast general types
+     */
+    /** @hide */
+    public static final int DIGITAL_BROADCAST_TYPE_ARIB = 0x0;
+    /** @hide */
+    public static final int DIGITAL_BROADCAST_TYPE_ATSC = 0x1;
+    /** @hide */
+    public static final int DIGITAL_BROADCAST_TYPE_DVB = 0x2;
+
+    /**
+     * Digital broadcast specific types
+     */
+    /** @hide */
+    public static final int DIGITAL_BROADCAST_TYPE_ARIB_BS = 0x8;
+    /** @hide */
+    public static final int DIGITAL_BROADCAST_TYPE_ARIB_CS = 0x9;
+    /** @hide */
+    public static final int DIGITAL_BROADCAST_TYPE_ARIB_T = 0xA;
+    /** @hide */
+    public static final int DIGITAL_BROADCAST_TYPE_ATSC_CABLE = 0x10;
+    /** @hide */
+    public static final int DIGITAL_BROADCAST_TYPE_ATSC_SATELLITE = 0x11;
+    /** @hide */
+    public static final int DIGITAL_BROADCAST_TYPE_ATSC_TERRESTRIAL = 0x12;
+    /** @hide */
+    public static final int DIGITAL_BROADCAST_TYPE_DVB_C = 0x18;
+    /** @hide */
+    public static final int DIGITAL_BROADCAST_TYPE_DVB_S = 0x19;
+    /** @hide */
+    public static final int DIGITAL_BROADCAST_TYPE_DVB_S2 = 0x1A;
+    /** @hide */
+    public static final int DIGITAL_BROADCAST_TYPE_DVB_T = 0x1B;
+
+    /** Channel number formats. */
+    private static final int CHANNEL_NUMBER_FORMAT_1_PART = 0x01;
+    private static final int CHANNEL_NUMBER_FORMAT_2_PART = 0x02;
+
+    /**
+     * Interface for digital source identification.
+     */
+    private interface DigitalServiceIdentification {
+        void toByteArray(byte[] data, int index);
+    }
+
+    /**
+     * Digital service identification for ARIB.
+     * <p>
+     * It consists of the following fields
+     * <ul>
+     * <li>transport stream id: 2bytes
+     * <li>service id: 2bytes
+     * <li>original network id: 2bytes
+     * </ul>
+     * @hide
+     */
+    public static final class AribData implements DigitalServiceIdentification {
+        /** The transport_stream_ID of the transport stream carrying the required service */
+        private final int mTransportStreamId;
+        /** The service_ID of the required service */
+        private final int mServiceId;
+        /**
+         * The original_network_ID of the network carrying the transport stream for the required
+         * service
+         */
+        private final int mOriginalNetworkId;
+
+        public AribData(int transportStreamId, int serviceId, int originalNetworkId) {
+            mTransportStreamId = transportStreamId;
+            mServiceId = serviceId;
+            mOriginalNetworkId = originalNetworkId;
+        }
+
+        @Override
+        public void toByteArray(byte[] data, int index) {
+            threeFieldsToSixBytes(mTransportStreamId, mServiceId, mOriginalNetworkId, data, index);
+        }
+    }
+
+    /**
+     * Digital service identification for ATSC.
+     * <p>
+     * It consists of the following fields
+     * <ul>
+     * <li>transport stream id: 2bytes
+     * <li>program number: 2bytes
+     * <li>reserved: 2bytes
+     * </ul>
+     * @hide
+     */
+    public static final class AtscData implements DigitalServiceIdentification {
+        /** The transport_stream_ID of the transport stream carrying the required service */
+        private final int mTransportStreamId;
+        /** The Program_number of the required service */
+        private final int mProgramNumber;
+
+        public AtscData(int transportStreamId, int programNumber) {
+            mTransportStreamId = transportStreamId;
+            mProgramNumber = programNumber;
+        }
+
+        @Override
+        public void toByteArray(byte[] data, int index) {
+            threeFieldsToSixBytes(mTransportStreamId, mProgramNumber, 0, data, index);
+        }
+    }
+
+    /**
+     * Digital service identification for DVB.
+     * <p>
+     * It consists of the following fields
+     * <ul>
+     * <li>transport stream id: 2bytes
+     * <li>service id: 2bytes
+     * <li>original network id: 2bytes
+     * </ul>
+     * @hide
+     */
+    public static final class DvbData implements DigitalServiceIdentification {
+        /** The transport_stream_ID of the transport stream carrying the required service */
+        private final int mTransportStreamId;
+        /** The service_ID of the required service */
+        private final int mServiceId;
+        /**
+         * The original_network_ID of the network carrying the transport stream for the required
+         * service
+         */
+        private final int mOriginalNetworkId;
+
+        public DvbData(int transportStreamId, int serviceId, int originalNetworkId) {
+            mTransportStreamId = transportStreamId;
+            mServiceId = serviceId;
+            mOriginalNetworkId = originalNetworkId;
+        }
+
+        @Override
+        public void toByteArray(byte[] data, int index) {
+            threeFieldsToSixBytes(mTransportStreamId, mServiceId, mOriginalNetworkId, data, index);
+        }
+    }
+
+    /**
+     * Identifies a 1-part Logical or Virtual Channel Number or a 2-part Major and Minor channel
+     * combination.
+     */
+    private static final class ChannelIdentifier {
+        /** Identifies Channel Format */
+        private final int mChannelNumberFormat;
+        /**
+         * Major Channel Number (if Channel Number Format is 2-part). If format is
+         * CHANNEL_NUMBER_FORMAT_1_PART, this will be ignored(0).
+         */
+        private final int mMajorChannelNumber;
+        /**
+         * 1-part Channel Number, or a Minor Channel Number (if Channel Number Format is 2-part).
+         */
+        private final int mMinorChannelNumber;
+
+        private ChannelIdentifier(int format, int majorNumber, int minorNumer) {
+            mChannelNumberFormat = format;
+            mMajorChannelNumber = majorNumber;
+            mMinorChannelNumber = minorNumer;
+        }
+
+        private void toByteArray(byte[] data, int index) {
+            // The first 6 bits for format, the 10 bits for major number.
+            data[index] = (byte) (((mChannelNumberFormat << 2) | (mMajorChannelNumber >>> 8) & 0x3));
+            data[index + 1] = (byte) (mMajorChannelNumber & 0xFF);
+            // Minor number uses the next 16 bits.
+            shortToByteArray((short) mMinorChannelNumber, data, index + 2);
+        }
+    }
+
+    /**
+     * Digital channel id.
+     * <p>
+     * It consists of the following fields
+     * <ul>
+     * <li>channel number format: 6bits
+     * <li>major number: 10bits
+     * <li>minor number: 16bits
+     * <li>reserved: 2bytes
+     * </ul>
+     * @hide
+     */
+    public static final class DigitalChannelData implements DigitalServiceIdentification {
+        /** Identifies the logical or virtual channel number of a service. */
+        private ChannelIdentifier mChannelIdentifier;
+
+        public static DigitalChannelData ofTwoNumbers(int majorNumber, int minorNumber) {
+            return new DigitalChannelData(
+                    new ChannelIdentifier(CHANNEL_NUMBER_FORMAT_2_PART, majorNumber, minorNumber));
+        }
+
+        public static DigitalChannelData ofOneNumber(int number) {
+            return new DigitalChannelData(
+                    new ChannelIdentifier(CHANNEL_NUMBER_FORMAT_1_PART, 0, number));
+        }
+
+        private DigitalChannelData(ChannelIdentifier id) {
+            mChannelIdentifier = id;
+        }
+
+        @Override
+        public void toByteArray(byte[] data, int index) {
+            mChannelIdentifier.toByteArray(data, index);
+            // The last 2 bytes is reserved for future use.
+            data[index + 4] = 0;
+            data[index + 5] = 0;
+        }
+    }
+
+    /**
+     * Create {@link DigitalServiceSource} with channel type.
+     *
+     * @param broadcastSystem digital broadcast system. It should be one of
+     *            <ul>
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB_BS}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB_CS}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB_T}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC_CABLE}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC_SATELLITE}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC_TERRESTRIAL}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_C}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_S}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_S2}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_T}
+     *            </ul>
+     * @hide
+     */
+    public static DigitalServiceSource ofDigitalChannelId(int broadcastSystem,
+            DigitalChannelData data) {
+        if (data == null) {
+            throw new IllegalArgumentException("data should not be null.");
+        }
+        switch (broadcastSystem) {
+            case DIGITAL_BROADCAST_TYPE_ARIB:
+            case DIGITAL_BROADCAST_TYPE_ATSC:
+            case DIGITAL_BROADCAST_TYPE_DVB:
+            case DIGITAL_BROADCAST_TYPE_ARIB_BS:
+            case DIGITAL_BROADCAST_TYPE_ARIB_CS:
+            case DIGITAL_BROADCAST_TYPE_ARIB_T:
+            case DIGITAL_BROADCAST_TYPE_ATSC_CABLE:
+            case DIGITAL_BROADCAST_TYPE_ATSC_SATELLITE:
+            case DIGITAL_BROADCAST_TYPE_ATSC_TERRESTRIAL:
+            case DIGITAL_BROADCAST_TYPE_DVB_C:
+            case DIGITAL_BROADCAST_TYPE_DVB_S:
+            case DIGITAL_BROADCAST_TYPE_DVB_S2:
+            case DIGITAL_BROADCAST_TYPE_DVB_T:
+                return new DigitalServiceSource(
+                        DigitalServiceSource.DIGITAL_SERVICE_IDENTIFIED_BY_CHANNEL,
+                        broadcastSystem,
+                        data);
+            default:
+                Log.w(TAG, "Invalid broadcast type:" + broadcastSystem);
+                throw new IllegalArgumentException(
+                        "Invalid broadcast system value:" + broadcastSystem);
+        }
+    }
+
+    /**
+     * Create {@link DigitalServiceSource} of ARIB type.
+     *
+     * @param aribType ARIB type. It should be one of
+     *            <ul>
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB_BS}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB_CS}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ARIB_T}
+     *            </ul>
+     * @hide
+     */
+    @Nullable
+    public static DigitalServiceSource ofArib(int aribType, AribData data) {
+        if (data == null) {
+            throw new IllegalArgumentException("data should not be null.");
+        }
+        switch (aribType) {
+            case DIGITAL_BROADCAST_TYPE_ARIB:
+            case DIGITAL_BROADCAST_TYPE_ARIB_BS:
+            case DIGITAL_BROADCAST_TYPE_ARIB_CS:
+            case DIGITAL_BROADCAST_TYPE_ARIB_T:
+                return new DigitalServiceSource(
+                        DigitalServiceSource.DIGITAL_SERVICE_IDENTIFIED_BY_DIGITAL_ID,
+                        aribType, data);
+            default:
+                Log.w(TAG, "Invalid ARIB type:" + aribType);
+                throw new IllegalArgumentException("type should not be null.");
+        }
+    }
+
+    /**
+     * Create {@link DigitalServiceSource} of ATSC type.
+     *
+     * @param atscType ATSC type. It should be one of
+     *            <ul>
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC_CABLE}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC_SATELLITE}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_ATSC_TERRESTRIAL}
+     *            </ul>
+     * @hide
+     */
+    @Nullable
+    public static DigitalServiceSource ofAtsc(int atscType, AtscData data) {
+        if (data == null) {
+            throw new IllegalArgumentException("data should not be null.");
+        }
+        switch (atscType) {
+            case DIGITAL_BROADCAST_TYPE_ATSC:
+            case DIGITAL_BROADCAST_TYPE_ATSC_CABLE:
+            case DIGITAL_BROADCAST_TYPE_ATSC_SATELLITE:
+            case DIGITAL_BROADCAST_TYPE_ATSC_TERRESTRIAL:
+                return new DigitalServiceSource(
+                        DigitalServiceSource.DIGITAL_SERVICE_IDENTIFIED_BY_DIGITAL_ID,
+                        atscType, data);
+            default:
+                Log.w(TAG, "Invalid ATSC type:" + atscType);
+                throw new IllegalArgumentException("Invalid ATSC type:" + atscType);
+        }
+    }
+
+    /**
+     * Create {@link DigitalServiceSource} of ATSC type.
+     *
+     * @param dvbType DVB type. It should be one of
+     *            <ul>
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_C}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_S}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_S2}
+     *            <li>{@link #DIGITAL_BROADCAST_TYPE_DVB_T}
+     *            </ul>
+     * @hide
+     */
+    @Nullable
+    public static DigitalServiceSource ofDvb(int dvbType, DvbData data) {
+        if (data == null) {
+            throw new IllegalArgumentException("data should not be null.");
+        }
+        switch (dvbType) {
+            case DIGITAL_BROADCAST_TYPE_DVB:
+            case DIGITAL_BROADCAST_TYPE_DVB_C:
+            case DIGITAL_BROADCAST_TYPE_DVB_S:
+            case DIGITAL_BROADCAST_TYPE_DVB_S2:
+            case DIGITAL_BROADCAST_TYPE_DVB_T:
+                return new DigitalServiceSource(
+                        DigitalServiceSource.DIGITAL_SERVICE_IDENTIFIED_BY_DIGITAL_ID,
+                        dvbType, data);
+            default:
+                Log.w(TAG, "Invalid DVB type:" + dvbType);
+                throw new IllegalArgumentException("Invalid DVB type:" + dvbType);
+        }
+    }
+
+    /**
+     * Record source container for "Digital Service".
+     * <ul>
+     * <li>[Record Source Type] - 1 byte
+     * <li>[Digital Identification] - 7 bytes
+     * </ul>
+     * @hide
+     */
+    public static final class DigitalServiceSource extends RecordSource {
+        /** Indicates that a service is identified by digital service IDs. */
+        private static final int DIGITAL_SERVICE_IDENTIFIED_BY_DIGITAL_ID = 0;
+        /** Indicates that a service is identified by a logical or virtual channel number. */
+        private static final int DIGITAL_SERVICE_IDENTIFIED_BY_CHANNEL = 1;
+
+        private static final int EXTRA_DATA_SIZE = 7;
+
+        /**
+         * Type of identification. It should be one of DIGITAL_SERVICE_IDENTIFIED_BY_DIGITAL_ID and
+         * DIGITAL_SERVICE_IDENTIFIED_BY_CHANNEL
+         */
+        private final int mIdentificationMethod;
+        /**
+         * Indicates the Digital Broadcast System of required service. This is present irrespective
+         * of the state of [Service Identification Method].
+         */
+        private final int mBroadcastSystem;
+
+        /**
+         * Extra parameter for digital service identification.
+         */
+        private final DigitalServiceIdentification mIdentification;
+
+        private DigitalServiceSource(int identificatinoMethod, int broadcastSystem,
+                DigitalServiceIdentification identification) {
+            super(RECORD_SOURCE_TYPE_DIGITAL_SERVICE, EXTRA_DATA_SIZE);
+            mIdentificationMethod = identificatinoMethod;
+            mBroadcastSystem = broadcastSystem;
+            mIdentification = identification;
+        }
+
+        @Override
+        int extraParamToByteArray(byte[] data, int index) {
+            data[index] = (byte) ((mIdentificationMethod << 7) | (mBroadcastSystem & 0x7F));
+            mIdentification.toByteArray(data, index + 1);
+            return EXTRA_DATA_SIZE;
+
+        }
+    }
+
+
+    // ---------------------------------------------------------------------------------------------
+    // ---- Analogue service data ------------------------------------------------------------------
+    // ---------------------------------------------------------------------------------------------
+    /**
+     * Analogue broadcast types.
+     */
+    /** @hide */
+    public static final int ANALOGUE_BROADCAST_TYPE_CABLE = 0x0;
+    /** @hide */
+    public static final int ANALOGUE_BROADCAST_TYPE_SATELLITE = 0x1;
+    /** @hide */
+    public static final int ANALOGUE_BROADCAST_TYPE_TERRESTRIAL = 0x2;
+
+    /**
+     * Broadcast system values.
+     */
+    /** @hide */
+    public static final int BROADCAST_SYSTEM_PAL_BG = 0;
+    /** @hide */
+    public static final int BROADCAST_SYSTEM_SECAM_LP = 1;
+    /** @hide */
+    public static final int BROADCAST_SYSTEM_PAL_M = 2;
+    /** @hide */
+    public static final int BROADCAST_SYSTEM_NTSC_M = 3;
+    /** @hide */
+    public static final int BROADCAST_SYSTEM_PAL_I = 4;
+    /** @hide */
+    public static final int BROADCAST_SYSTEM_SECAM_DK = 5;
+    /** @hide */
+    public static final int BROADCAST_SYSTEM_SECAM_BG = 6;
+    /** @hide */
+    public static final int BROADCAST_SYSTEM_SECAM_L = 7;
+    /** @hide */
+    public static final int BROADCAST_SYSTEM_PAL_DK = 8;
+    /** @hide */
+    public static final int BROADCAST_SYSTEM_PAL_OTHER_SYSTEM = 31;
+
+    /**
+     * Create {@link AnalogueServiceSource} of analogue service.
+     *
+     * @param broadcastType
+     * @param frequency
+     * @param broadcastSystem
+     * @hide
+     */
+    @Nullable
+    public static AnalogueServiceSource ofAnalogue(int broadcastType, int frequency,
+            int broadcastSystem){
+        if (broadcastType < ANALOGUE_BROADCAST_TYPE_CABLE
+                || broadcastType > ANALOGUE_BROADCAST_TYPE_TERRESTRIAL) {
+            Log.w(TAG, "Invalid Broadcast type:" + broadcastType);
+            throw new IllegalArgumentException("Invalid Broadcast type:" + broadcastType);
+        }
+        if (frequency < 0 || frequency > 0xFFFF) {
+            Log.w(TAG, "Invalid frequency value[0x0000-0xFFFF]:" + frequency);
+            throw new IllegalArgumentException(
+                    "Invalid frequency value[0x0000-0xFFFF]:" + frequency);
+        }
+        if (broadcastSystem < BROADCAST_SYSTEM_PAL_BG
+                || broadcastSystem > BROADCAST_SYSTEM_PAL_OTHER_SYSTEM) {
+
+            Log.w(TAG, "Invalid Broadcast system:" + broadcastSystem);
+            throw new IllegalArgumentException(
+                    "Invalid Broadcast system:" + broadcastSystem);
+        }
+
+        return new AnalogueServiceSource(broadcastType, frequency, broadcastSystem);
+    }
+
+    /**
+     * Record source for analogue service data. It consists of
+     * <ul>
+     * <li>[Record Source Type] - 1 byte
+     * <li>[Analogue Broadcast Type] - 1 byte
+     * <li>[Analogue Frequency] - 2 bytes
+     * <li>[Broadcast System] - 1 byte
+     * </ul>
+     * @hide
+     */
+    public static final class AnalogueServiceSource extends RecordSource {
+        private static final int EXTRA_DATA_SIZE = 4;
+
+        /** Indicates the Analogue broadcast type. */
+        private final int mBroadcastType;
+        /** Used to specify the frequency used by an analogue tuner. 0x0000<N<0xFFFF. */
+        private final int mFrequency;
+        /**
+         * This specifies information about the color system, the sound carrier and the
+         * IF-frequency.
+         */
+        private final int mBroadcastSystem;
+
+        private AnalogueServiceSource(int broadcastType, int frequency, int broadcastSystem) {
+            super(RECORD_SOURCE_TYPE_ANALOGUE_SERVICE, EXTRA_DATA_SIZE);
+            mBroadcastType = broadcastType;
+            mFrequency = frequency;
+            mBroadcastSystem = broadcastSystem;
+        }
+
+        @Override
+        protected int extraParamToByteArray(byte[] data, int index) {
+            // [Analogue Broadcast Type] - 1 byte
+            data[index] = (byte) mBroadcastType;
+            // [Analogue Frequency] - 2 bytes
+            shortToByteArray((short) mFrequency, data, index + 1);
+            // [Broadcast System] - 1 byte
+            data[index + 3] = (byte) mBroadcastSystem;
+            return EXTRA_DATA_SIZE;
+        }
+    }
+
+
+    // ---------------------------------------------------------------------------------------------
+    // ---- External plug data ---------------------------------------------------------------------
+    // ---------------------------------------------------------------------------------------------
+    /**
+     * Create {@link ExternalPlugData} of external plug type.
+     *
+     * @param plugNumber plug number. It should be in range of [1, 255]
+     * @hide
+     */
+    public static ExternalPlugData ofExternalPlug(int plugNumber) {
+        if (plugNumber < 1 || plugNumber > 255) {
+            Log.w(TAG, "Invalid plug number[1-255]" + plugNumber);
+            throw new IllegalArgumentException("Invalid plug number[1-255]" + plugNumber);
+        }
+        return new ExternalPlugData(plugNumber);
+    }
+
+    /**
+     * Record source for external plug (external non-HDMI device connect) type.
+     * <ul>
+     * <li>[Record Source Type] - 1 byte
+     * <li>[External Plug] - 1 byte
+     * </ul>
+     * @hide
+     */
+    public static final class ExternalPlugData extends RecordSource {
+        private static final int EXTRA_DATA_SIZE = 1;
+
+        /** External Plug number on the Recording Device. */
+        private final int mPlugNumber;
+
+        private ExternalPlugData(int plugNumber) {
+            super(RECORD_SOURCE_TYPE_EXTERNAL_PLUG, EXTRA_DATA_SIZE);
+            mPlugNumber = plugNumber;
+        }
+
+        @Override
+        int extraParamToByteArray(byte[] data, int index) {
+            data[index] = (byte) mPlugNumber;
+            return EXTRA_DATA_SIZE;
+        }
+    }
+
+    // ---------------------------------------------------------------------------------------------
+    // ---- External physical address --------------------------------------------------------------
+    // ---------------------------------------------------------------------------------------------
+    /**
+     * Create {@link ExternalPhysicalAddress} of external physical address.
+     *
+     * @param physicalAddress
+     * @hide
+     */
+    public static ExternalPhysicalAddress ofExternalPhysicalAddress(int physicalAddress) {
+        if ((physicalAddress & ~0xFFFF) != 0) {
+            Log.w(TAG, "Invalid physical address:" + physicalAddress);
+            throw new IllegalArgumentException("Invalid physical address:" + physicalAddress);
+        }
+
+        return new ExternalPhysicalAddress(physicalAddress);
+    }
+
+    /**
+     * Record source for external physical address.
+     * <ul>
+     * <li>[Record Source Type] - 1 byte
+     * <li>[Physical address] - 2 byte
+     * </ul>
+     * @hide
+     */
+    public static final class ExternalPhysicalAddress extends RecordSource {
+        private static final int EXTRA_DATA_SIZE = 2;
+
+        private final int mPhysicalAddress;
+
+        private ExternalPhysicalAddress(int physicalAddress) {
+            super(RECORD_SOURCE_TYPE_EXTERNAL_PHYSICAL_ADDRESS, EXTRA_DATA_SIZE);
+            mPhysicalAddress = physicalAddress;
+        }
+
+        @Override
+        int extraParamToByteArray(byte[] data, int index) {
+            shortToByteArray((short) mPhysicalAddress, data, index);
+            return EXTRA_DATA_SIZE;
+        }
+    }
+
+
+    // ---------------------------------------------------------------------------------------------
+    // ------- Helper methods ----------------------------------------------------------------------
+    // ---------------------------------------------------------------------------------------------
+    private static int threeFieldsToSixBytes(int first, int second, int third, byte[] data,
+            int index) {
+        shortToByteArray((short) first, data, index);
+        shortToByteArray((short) second, data, index + 2);
+        shortToByteArray((short) third, data, index + 4);
+        return 6;
+    }
+
+    private static int shortToByteArray(short value, byte[] byteArray, int index) {
+        byteArray[index] = (byte) ((value >>> 8) & 0xFF);
+        byteArray[index + 1] = (byte) (value & 0xFF);
+        return 2;
+    }
+}
index 1285ccb..6d64a1d 100644 (file)
 package android.hardware.hdmi;
 
 import android.annotation.SystemApi;
-import android.hardware.hdmi.HdmiControlManager.VendorCommandListener;
-import android.hardware.hdmi.IHdmiVendorCommandListener;
 import android.os.RemoteException;
 import android.util.Log;
 
+import libcore.util.EmptyArray;
+
 /**
  * HdmiTvClient represents HDMI-CEC logical device of type TV in the Android system
  * which acts as TV/Display. It provides with methods that manage, interact with other
@@ -91,6 +91,7 @@ public final class HdmiTvClient extends HdmiClient {
         return new HdmiTvClient(service);
     }
 
+    @Override
     public int getDeviceType() {
         return HdmiCecDeviceInfo.DEVICE_TV;
     }
@@ -150,6 +151,51 @@ public final class HdmiTvClient extends HdmiClient {
         }
     }
 
+    /**
+     * Callback interface to used to get notified when a record request from recorder device.
+     */
+    public interface RecordRequestListener {
+        /**
+         * Called when tv receives request request from recorder device. When it's called,
+         * it should return record source in byte array so that hdmi control service
+         * can start recording with the given source info.
+         *
+         * @return {@link HdmiRecordSources} to be used to set recording info
+         */
+        HdmiRecordSources.RecordSource onRecordRequestReceived(int recorderAddress);
+    }
+
+    /**
+     * Set {@link RecordRequestListener} to hdmi control service.
+     */
+    public void setRecordRequestListener(RecordRequestListener listener) {
+        try {
+            mService.setRecordRequestListener(getCallbackWrapper(listener));
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to set record request listener: ", e);
+        }
+    }
+
+    /**
+     * Start recording with the given recorder address and recorder source.
+     * <p>Usage
+     * <pre>
+     * HdmiTvClient tvClient = ....;
+     * // for own source.
+     * OwnSource ownSource = ownHdmiRecordSources.ownSource();
+     * tvClient.startRecord(recorderAddress, ownSource);
+     * </pre>
+     */
+    public void startRecord(int recorderAddress, HdmiRecordSources.RecordSource source) {
+        try {
+            byte[] data = new byte[source.getDataSize(true)];
+            source.toByteArray(true, data, 0);
+            mService.startRecord(recorderAddress, data);
+        } catch (RemoteException e) {
+            Log.e(TAG, "failed to start record: ", e);
+        }
+    }
+
     private static IHdmiControlCallback getCallbackWrapper(final SelectCallback callback) {
         return new IHdmiControlCallback.Stub() {
             @Override
@@ -158,4 +204,21 @@ public final class HdmiTvClient extends HdmiClient {
             }
         };
     }
+
+    private static IHdmiRecordRequestListener getCallbackWrapper(
+            final RecordRequestListener listener) {
+        return new IHdmiRecordRequestListener.Stub() {
+            @Override
+            public byte[] onRecordRequestReceived(int recorderAddress) throws RemoteException {
+                HdmiRecordSources.RecordSource source =
+                        listener.onRecordRequestReceived(recorderAddress);
+                if (source == null) {
+                    return EmptyArray.BYTE;
+                }
+                byte[] data = new byte[source.getDataSize(true)];
+                source.toByteArray(true, data, 0);
+                return data;
+            }
+        };
+    }
 }
index f3931e3..6f3763b 100644 (file)
@@ -22,6 +22,7 @@ import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.hdmi.IHdmiDeviceEventListener;
 import android.hardware.hdmi.IHdmiHotplugEventListener;
 import android.hardware.hdmi.IHdmiInputChangeListener;
+import android.hardware.hdmi.IHdmiRecordRequestListener;
 import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
 import android.hardware.hdmi.IHdmiVendorCommandListener;
 
@@ -61,4 +62,6 @@ interface IHdmiControlService {
     void sendVendorCommand(int deviceType, int targetAddress, in byte[] params,
             boolean hasVendorId);
     void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType);
+    void setRecordRequestListener(IHdmiRecordRequestListener listener);
+    void startRecord(int recorderAddress, in byte[] recordSource);
 }
diff --git a/core/java/android/hardware/hdmi/IHdmiRecordRequestListener.aidl b/core/java/android/hardware/hdmi/IHdmiRecordRequestListener.aidl
new file mode 100644 (file)
index 0000000..f8f9e5f
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 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 fill record source info
+ * when it gets record start request.
+ *
+ * @hide
+ */
+interface IHdmiRecordRequestListener {
+    byte[] onRecordRequestReceived(int recorderAddress);
+}
\ No newline at end of file
index 384cd4a..85c7747 100644 (file)
@@ -206,5 +206,10 @@ final class Constants {
     static final String PROPERTY_PREFERRED_ADDRESS_PLAYBACK = "hdmi_cec.prefaddr.playback";
     static final String PROPERTY_PREFERRED_ADDRESS_TV = "hdmi_cec.prefaddr.tv";
 
+    static final int RECORDING_TYPE_DIGITAL_RF = 1;
+    static final int RECORDING_TYPE_ANALOGUE_RF = 2;
+    static final int RECORDING_TYPE_EXTERNAL_PHYSICAL_ADDRESS = 3;
+    static final int RECORDING_TYPE_OWN_SOURCE = 4;
+
     private Constants() { /* cannot be instantiated */ }
 }
index 0239c83..560ee84 100644 (file)
@@ -32,6 +32,7 @@ import android.hardware.hdmi.IHdmiControlService;
 import android.hardware.hdmi.IHdmiDeviceEventListener;
 import android.hardware.hdmi.IHdmiHotplugEventListener;
 import android.hardware.hdmi.IHdmiInputChangeListener;
+import android.hardware.hdmi.IHdmiRecordRequestListener;
 import android.hardware.hdmi.IHdmiSystemAudioModeChangeListener;
 import android.hardware.hdmi.IHdmiVendorCommandListener;
 import android.media.AudioManager;
@@ -1010,6 +1011,16 @@ public final class HdmiControlService extends SystemService {
                 }
             });
          }
+
+        @Override
+        public void setRecordRequestListener(IHdmiRecordRequestListener listener) {
+            // TODO: implement this.
+        }
+
+        @Override
+        public void startRecord(int recorderAddress, byte[] recordSource) {
+            // TODO: implement this.
+        }
     }
 
     @ServiceThreadOnly
index 7646027..51aa984 100644 (file)
 
 package com.android.server.hdmi;
 
+import static com.android.server.hdmi.Constants.RECORDING_TYPE_ANALOGUE_RF;
+import static com.android.server.hdmi.Constants.RECORDING_TYPE_DIGITAL_RF;
+import static com.android.server.hdmi.Constants.RECORDING_TYPE_EXTERNAL_PHYSICAL_ADDRESS;
+import static com.android.server.hdmi.Constants.RECORDING_TYPE_OWN_SOURCE;
+
 /**
- * Feature action that performs one touch record.
- * This class only provides a skeleton of one touch play and has no detail implementaion.
+ * Feature action that performs one touch record. This class only provides a skeleton of one touch
+ * play and has no detail implementation.
  */
 public class OneTouchRecordAction extends FeatureAction {
     private final int mRecorderAddress;
+    private final int mRecordingType;
 
-    OneTouchRecordAction(HdmiCecLocalDevice source, int recorderAddress) {
+    OneTouchRecordAction(HdmiCecLocalDevice source, int recorderAddress, int recordingType) {
         super(source);
         mRecorderAddress = recorderAddress;
+        mRecordingType = recordingType;
     }
 
     @Override
@@ -33,6 +40,20 @@ public class OneTouchRecordAction extends FeatureAction {
         return false;
     }
 
+    private void sendRecordOn(int recordingType) {
+        switch (recordingType) {
+            case RECORDING_TYPE_DIGITAL_RF:
+                break;
+            case RECORDING_TYPE_ANALOGUE_RF:
+                break;
+            case RECORDING_TYPE_EXTERNAL_PHYSICAL_ADDRESS:
+                break;
+            case RECORDING_TYPE_OWN_SOURCE:
+                break;
+            // TODO: implement this.
+        }
+    }
+
     @Override
     boolean processCommand(HdmiCecMessage cmd) {
         return false;