Home | History | Annotate | Download | only in hdmi
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.hardware.hdmi;
     18 
     19 import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_ANALOGUE;
     20 import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL;
     21 import static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL;
     22 
     23 import android.annotation.SystemApi;
     24 import android.hardware.hdmi.HdmiRecordSources.AnalogueServiceSource;
     25 import android.hardware.hdmi.HdmiRecordSources.DigitalServiceSource;
     26 import android.hardware.hdmi.HdmiRecordSources.ExternalPhysicalAddress;
     27 import android.hardware.hdmi.HdmiRecordSources.ExternalPlugData;
     28 import android.hardware.hdmi.HdmiRecordSources.RecordSource;
     29 import android.util.Log;
     30 
     31 /**
     32  * Container for timer record source used for timer recording. Timer source consists of two parts,
     33  * timer info and record source.
     34  * <p>
     35  * Timer info contains all timing information used for recording. It consists of the following
     36  * values.
     37  * <ul>
     38  * <li>[Day of Month]
     39  * <li>[Month of Year]
     40  * <li>[Start Time]
     41  * <li>[Duration]
     42  * <li>[Recording Sequence]
     43  * </ul>
     44  * <p>
     45  * Record source containers all program information used for recording.
     46  * For more details, look at {@link HdmiRecordSources}.
     47  * <p>
     48  * Usage
     49  * <pre>
     50  * TimeOrDuration startTime = HdmiTimerRecordSources.ofTime(18, 00);  // 6PM.
     51  * TimeOrDuration duration = HdmiTimerRecordSource.ofDuration(1, 00);  // 1 hour duration.
     52  * // For 1 hour from 6PM, August 10th every SaturDay and Sunday.
     53  * TimerInfo timerInfo = HdmiTimerRecordSource.timerInfoOf(10, 8, starTime, duration,
     54  *            HdmiTimerRecordSource.RECORDING_SEQUENCE_REPEAT_SATURDAY |
     55  *            HdmiTimerRecordSource.RECORDING_SEQUENCE_REPEAT_SUNDAY);
     56  * // create digital source.
     57  * DigitalServiceSource recordSource = HdmiRecordSource.ofDvb(...);
     58  * TimerRecordSource source = ofDigitalSource(timerInfo, recordSource);
     59  * </pre>
     60  *
     61  * @hide
     62  */
     63 @SystemApi
     64 public class HdmiTimerRecordSources {
     65     private static final String TAG = "HdmiTimerRecordingSources";
     66 
     67     private HdmiTimerRecordSources() {}
     68 
     69     /**
     70      * Creates {@link TimerRecordSource} for digital source which is used for &lt;Set Digital
     71      * Timer&gt;.
     72      *
     73      * @param timerInfo timer info used for timer recording
     74      * @param source digital source used for timer recording
     75      * @return {@link TimerRecordSource}
     76      * @throws IllegalArgumentException if {@code timerInfo} or {@code source} is null
     77      */
     78     public static TimerRecordSource ofDigitalSource(TimerInfo timerInfo,
     79             DigitalServiceSource source) {
     80         checkTimerRecordSourceInputs(timerInfo, source);
     81         return new TimerRecordSource(timerInfo, source);
     82     }
     83 
     84     /**
     85      * Creates {@link TimerRecordSource} for analogue source which is used for &lt;Set Analogue
     86      * Timer&gt;.
     87      *
     88      * @param timerInfo timer info used for timer recording
     89      * @param source digital source used for timer recording
     90      * @return {@link TimerRecordSource}
     91      * @throws IllegalArgumentException if {@code timerInfo} or {@code source} is null
     92      */
     93     public static TimerRecordSource ofAnalogueSource(TimerInfo timerInfo,
     94             AnalogueServiceSource source) {
     95         checkTimerRecordSourceInputs(timerInfo, source);
     96         return new TimerRecordSource(timerInfo, source);
     97     }
     98 
     99     /**
    100      * Creates {@link TimerRecordSource} for external plug which is used for &lt;Set External
    101      * Timer&gt;.
    102      *
    103      * @param timerInfo timer info used for timer recording
    104      * @param source digital source used for timer recording
    105      * @return {@link TimerRecordSource}
    106      * @throws IllegalArgumentException if {@code timerInfo} or {@code source} is null
    107      */
    108     public static TimerRecordSource ofExternalPlug(TimerInfo timerInfo, ExternalPlugData source) {
    109         checkTimerRecordSourceInputs(timerInfo, source);
    110         return new TimerRecordSource(timerInfo,
    111                 new ExternalSourceDecorator(source, EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PLUG));
    112     }
    113 
    114     /**
    115      * Creates {@link TimerRecordSource} for external physical address which is used for &lt;Set
    116      * External Timer&gt;.
    117      *
    118      * @param timerInfo timer info used for timer recording
    119      * @param source digital source used for timer recording
    120      * @return {@link TimerRecordSource}
    121      * @throws IllegalArgumentException if {@code timerInfo} or {@code source} is null
    122      */
    123     public static TimerRecordSource ofExternalPhysicalAddress(TimerInfo timerInfo,
    124             ExternalPhysicalAddress source) {
    125         checkTimerRecordSourceInputs(timerInfo, source);
    126         return new TimerRecordSource(timerInfo,
    127                 new ExternalSourceDecorator(source,
    128                         EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PHYSICAL_ADDRESS));
    129     }
    130 
    131     private static void checkTimerRecordSourceInputs(TimerInfo timerInfo, RecordSource source) {
    132         if (timerInfo == null) {
    133             Log.w(TAG, "TimerInfo should not be null.");
    134             throw new IllegalArgumentException("TimerInfo should not be null.");
    135         }
    136         if (source == null) {
    137             Log.w(TAG, "source should not be null.");
    138             throw new IllegalArgumentException("source should not be null.");
    139         }
    140     }
    141 
    142     /**
    143      * Creates {@link Duration} for time value.
    144      *
    145      * @param hour hour in range of [0, 23]
    146      * @param minute minute in range of [0, 60]
    147      * @return {@link Duration}
    148      * @throws IllegalArgumentException if hour or minute is out of range
    149      */
    150     public static Time timeOf(int hour, int minute) {
    151         checkTimeValue(hour, minute);
    152         return new Time(hour, minute);
    153     }
    154 
    155     private static void checkTimeValue(int hour, int minute) {
    156         if (hour < 0 || hour > 23) {
    157             throw new IllegalArgumentException("Hour should be in rage of [0, 23]:" + hour);
    158         }
    159         if (minute < 0 || minute > 59) {
    160             throw new IllegalArgumentException("Minute should be in rage of [0, 59]:" + minute);
    161         }
    162     }
    163 
    164     /**
    165      * Creates {@link Duration} for duration value.
    166      *
    167      * @param hour hour in range of [0, 99]
    168      * @param minute minute in range of [0, 59]
    169      * @return {@link Duration}
    170      * @throws IllegalArgumentException if hour or minute is out of range
    171      */
    172     public static Duration durationOf(int hour, int minute) {
    173         checkDurationValue(hour, minute);
    174         return new Duration(hour, minute);
    175     }
    176 
    177     private static void checkDurationValue(int hour, int minute) {
    178         if (hour < 0 || hour > 99) {
    179             throw new IllegalArgumentException("Hour should be in rage of [0, 99]:" + hour);
    180         }
    181         if (minute < 0 || minute > 59) {
    182             throw new IllegalArgumentException("minute should be in rage of [0, 59]:" + minute);
    183         }
    184     }
    185 
    186     /**
    187      * Base class for time-related information.
    188      * @hide
    189      */
    190     /* package */ static class TimeUnit {
    191         /* package */ final int mHour;
    192         /* package */ final int mMinute;
    193 
    194         /* package */ TimeUnit(int hour, int minute) {
    195             mHour = hour;
    196             mMinute = minute;
    197         }
    198 
    199         /* package */ int toByteArray(byte[] data, int index) {
    200             data[index] = toBcdByte(mHour);
    201             data[index + 1] = toBcdByte(mMinute);
    202             return 2;
    203         }
    204 
    205         /* package */ static byte toBcdByte(int value) {
    206             int digitOfTen = (value / 10) % 10;
    207             int digitOfOne = value % 10;
    208             return (byte) ((digitOfTen << 4) | digitOfOne);
    209         }
    210     }
    211 
    212     /**
    213      * Place holder for time value.
    214      * @hide
    215      */
    216     @SystemApi
    217     public static final class Time extends TimeUnit {
    218         private Time(int hour, int minute) {
    219             super(hour, minute);
    220         }
    221     }
    222 
    223     /**
    224      * Place holder for duration value.
    225      * @hide
    226      */
    227     @SystemApi
    228     public static final class Duration extends TimeUnit {
    229         private Duration(int hour, int minute) {
    230             super(hour, minute);
    231         }
    232     }
    233 
    234     /**
    235      * Fields for recording sequence.
    236      * The following can be merged by OR(|) operation.
    237      */
    238     public static final int RECORDING_SEQUENCE_REPEAT_ONCE_ONLY = 0;
    239     public static final int RECORDING_SEQUENCE_REPEAT_SUNDAY = 1 << 0;
    240     public static final int RECORDING_SEQUENCE_REPEAT_MONDAY = 1 << 1;
    241     public static final int RECORDING_SEQUENCE_REPEAT_TUESDAY = 1 << 2;
    242     public static final int RECORDING_SEQUENCE_REPEAT_WEDNESDAY = 1 << 3;
    243     public static final int RECORDING_SEQUENCE_REPEAT_THURSDAY = 1 << 4;
    244     public static final int RECORDING_SEQUENCE_REPEAT_FRIDAY = 1 << 5;
    245     public static final int RECORDING_SEQUENCE_REPEAT_SATUREDAY = 1 << 6;
    246 
    247     private static final int RECORDING_SEQUENCE_REPEAT_MASK =
    248             (RECORDING_SEQUENCE_REPEAT_SUNDAY | RECORDING_SEQUENCE_REPEAT_MONDAY |
    249             RECORDING_SEQUENCE_REPEAT_TUESDAY | RECORDING_SEQUENCE_REPEAT_WEDNESDAY |
    250             RECORDING_SEQUENCE_REPEAT_THURSDAY | RECORDING_SEQUENCE_REPEAT_FRIDAY |
    251             RECORDING_SEQUENCE_REPEAT_SATUREDAY);
    252 
    253     /**
    254      * Creates {@link TimerInfo} with the given information.
    255      *
    256      * @param dayOfMonth day of month
    257      * @param monthOfYear month of year
    258      * @param startTime start time in {@link Time}
    259      * @param duration duration in {@link Duration}
    260      * @param recordingSequence recording sequence. Use RECORDING_SEQUENCE_REPEAT_ONCE_ONLY for no
    261      *            repeat. Otherwise use combination of {@link #RECORDING_SEQUENCE_REPEAT_SUNDAY},
    262      *            {@link #RECORDING_SEQUENCE_REPEAT_MONDAY},
    263      *            {@link #RECORDING_SEQUENCE_REPEAT_TUESDAY},
    264      *            {@link #RECORDING_SEQUENCE_REPEAT_WEDNESDAY},
    265      *            {@link #RECORDING_SEQUENCE_REPEAT_THURSDAY},
    266      *            {@link #RECORDING_SEQUENCE_REPEAT_FRIDAY},
    267      *            {@link #RECORDING_SEQUENCE_REPEAT_SATUREDAY}.
    268      * @return {@link TimerInfo}.
    269      * @throws IllegalArgumentException if input value is invalid
    270      */
    271     public static TimerInfo timerInfoOf(int dayOfMonth, int monthOfYear, Time startTime,
    272             Duration duration, int recordingSequence) {
    273         if (dayOfMonth < 0 || dayOfMonth > 31) {
    274             throw new IllegalArgumentException(
    275                     "Day of month should be in range of [0, 31]:" + dayOfMonth);
    276         }
    277         if (monthOfYear < 1 || monthOfYear > 12) {
    278             throw new IllegalArgumentException(
    279                     "Month of year should be in range of [1, 12]:" + monthOfYear);
    280         }
    281         checkTimeValue(startTime.mHour, startTime.mMinute);
    282         checkDurationValue(duration.mHour, duration.mMinute);
    283         // Recording sequence should use least 7 bits or no bits.
    284         if ((recordingSequence != 0)
    285                 && ((recordingSequence & ~RECORDING_SEQUENCE_REPEAT_MASK) != 0)) {
    286             throw new IllegalArgumentException(
    287                     "Invalid reecording sequence value:" + recordingSequence);
    288         }
    289 
    290         return new TimerInfo(dayOfMonth, monthOfYear, startTime, duration, recordingSequence);
    291     }
    292 
    293     /**
    294      * Container basic timer information. It consists of the following fields.
    295      * <ul>
    296      * <li>[Day of Month]
    297      * <li>[Month of Year]
    298      * <li>[Start Time]
    299      * <li>[Duration]
    300      * <li>[Recording Sequence]
    301      * </ul>
    302      * @hide
    303      */
    304     @SystemApi
    305     public static final class TimerInfo {
    306         private static final int DAY_OF_MONTH_SIZE = 1;
    307         private static final int MONTH_OF_YEAR_SIZE = 1;
    308         private static final int START_TIME_SIZE = 2; // 1byte for hour and 1byte for minute.
    309         private static final int DURATION_SIZE = 2; // 1byte for hour and 1byte for minute.
    310         private static final int RECORDING_SEQUENCE_SIZE = 1;
    311         private static final int BASIC_INFO_SIZE = DAY_OF_MONTH_SIZE + MONTH_OF_YEAR_SIZE
    312                 + START_TIME_SIZE + DURATION_SIZE + RECORDING_SEQUENCE_SIZE;
    313 
    314         /** Day of month. */
    315         private final int mDayOfMonth;
    316         /** Month of year. */
    317         private final int mMonthOfYear;
    318         /**
    319          * Time of day.
    320          * [Hour][Minute]. 0 &lt;= Hour &lt;= 24, 0 &lt;= Minute &lt;= 60 in BCD format.
    321          */
    322         private final Time mStartTime;
    323         /**
    324          * Duration. [Hour][Minute].
    325          * 0 &lt;= Hour &lt;= 99, 0 &lt;= Minute &lt;= 60 in BCD format.
    326          * */
    327         private final Duration mDuration;
    328         /**
    329          * Indicates if recording is repeated and, if so, on which days. For repeated recordings,
    330          * the recording sequence value is the bitwise OR of the days when recordings are required.
    331          * [Recording Sequence] shall be set to 0x00 when the recording is not repeated. Bit 7 is
    332          * reserved and shall be set to zero.
    333          */
    334         private final int mRecordingSequence;
    335 
    336         private TimerInfo(int dayOfMonth, int monthOfYear, Time startTime,
    337                 Duration duration, int recordingSequence) {
    338             mDayOfMonth = dayOfMonth;
    339             mMonthOfYear = monthOfYear;
    340             mStartTime = startTime;
    341             mDuration = duration;
    342             mRecordingSequence = recordingSequence;
    343         }
    344 
    345         int toByteArray(byte[] data, int index) {
    346             // [Day of Month]
    347             data[index] = (byte) mDayOfMonth;
    348             index += DAY_OF_MONTH_SIZE;
    349             // [Month of Year]
    350             data[index] = (byte) mMonthOfYear;
    351             index += MONTH_OF_YEAR_SIZE;
    352             // [Start Time]
    353             index += mStartTime.toByteArray(data, index);
    354             index += mDuration.toByteArray(data, index);
    355             // [Duration]
    356             // [Recording Sequence]
    357             data[index] = (byte) mRecordingSequence;
    358             return getDataSize();
    359         }
    360 
    361         int getDataSize() {
    362             return BASIC_INFO_SIZE;
    363         }
    364     }
    365 
    366     /**
    367      * Record source container for timer record. This is used to set parameter for &lt;Set Digital
    368      * Timer&gt;, &lt;Set Analogue Timer&gt;, and &lt;Set External Timer&gt; message.
    369      * <p>
    370      * In order to create this from each source type, use one of helper method.
    371      * <ul>
    372      * <li>{@link #ofDigitalSource} for digital source
    373      * <li>{@link #ofAnalogueSource} for analogue source
    374      * <li>{@link #ofExternalPlug} for external plug type
    375      * <li>{@link #ofExternalPhysicalAddress} for external physical address type.
    376      * </ul>
    377      * @hide
    378      */
    379     @SystemApi
    380     public static final class TimerRecordSource {
    381         private final RecordSource mRecordSource;
    382         private final TimerInfo mTimerInfo;
    383 
    384         private TimerRecordSource(TimerInfo timerInfo, RecordSource recordSource) {
    385             mTimerInfo = timerInfo;
    386             mRecordSource = recordSource;
    387         }
    388 
    389         int getDataSize() {
    390             return mTimerInfo.getDataSize() + mRecordSource.getDataSize(false);
    391         }
    392 
    393         int toByteArray(byte[] data, int index) {
    394             // Basic infos including [Day of Month] [Month of Year] [Start Time] [Duration]
    395             // [Recording Sequence]
    396             index += mTimerInfo.toByteArray(data, index);
    397             // [Record Source]
    398             mRecordSource.toByteArray(false, data, index);
    399             return getDataSize();
    400         }
    401     }
    402 
    403     /**
    404      * External source specifier types.
    405      */
    406     private static final int EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PLUG = 4;
    407     private static final int EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PHYSICAL_ADDRESS = 5;
    408 
    409     /**
    410      * Decorator for external source. Beside digital or analogue source, external source starts with
    411      * [External Source Specifier] because it covers both external plug type and external specifier.
    412      */
    413     private static class ExternalSourceDecorator extends RecordSource {
    414         private final RecordSource mRecordSource;
    415         private final int mExternalSourceSpecifier;
    416 
    417         private ExternalSourceDecorator(RecordSource recordSource, int externalSourceSpecifier) {
    418             // External source has one byte field for [External Source Specifier].
    419             super(recordSource.mSourceType, recordSource.getDataSize(false) + 1);
    420             mRecordSource = recordSource;
    421             mExternalSourceSpecifier = externalSourceSpecifier;
    422         }
    423 
    424         @Override
    425         int extraParamToByteArray(byte[] data, int index) {
    426             data[index] = (byte) mExternalSourceSpecifier;
    427             mRecordSource.toByteArray(false, data, index + 1);
    428             return getDataSize(false);
    429         }
    430     }
    431 
    432     /**
    433      * Checks the byte array of timer record source.
    434      * @param sourcetype
    435      * @param recordSource
    436      * @hide
    437      */
    438     @SystemApi
    439     public static boolean checkTimerRecordSource(int sourcetype, byte[] recordSource) {
    440         int recordSourceSize = recordSource.length - TimerInfo.BASIC_INFO_SIZE;
    441         switch (sourcetype) {
    442             case TIMER_RECORDING_TYPE_DIGITAL:
    443                 return DigitalServiceSource.EXTRA_DATA_SIZE == recordSourceSize;
    444             case TIMER_RECORDING_TYPE_ANALOGUE:
    445                 return AnalogueServiceSource.EXTRA_DATA_SIZE == recordSourceSize;
    446             case TIMER_RECORDING_TYPE_EXTERNAL:
    447                 int specifier = recordSource[TimerInfo.BASIC_INFO_SIZE];
    448                 if (specifier == EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PLUG) {
    449                     // One byte for specifier.
    450                     return ExternalPlugData.EXTRA_DATA_SIZE + 1 == recordSourceSize;
    451                 } else if (specifier == EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PHYSICAL_ADDRESS) {
    452                     // One byte for specifier.
    453                     return ExternalPhysicalAddress.EXTRA_DATA_SIZE + 1 == recordSourceSize;
    454                 } else {
    455                     // Invalid specifier.
    456                     return false;
    457                 }
    458             default:
    459                 return false;
    460         }
    461     }
    462 }
    463