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     @SystemApi
    191     /* package */ static class TimeUnit {
    192         /* package */ final int mHour;
    193         /* package */ final int mMinute;
    194 
    195         /* package */ TimeUnit(int hour, int minute) {
    196             mHour = hour;
    197             mMinute = minute;
    198         }
    199 
    200         /* package */ int toByteArray(byte[] data, int index) {
    201             data[index] = toBcdByte(mHour);
    202             data[index + 1] = toBcdByte(mMinute);
    203             return 2;
    204         }
    205 
    206         /* package */ static byte toBcdByte(int value) {
    207             int digitOfTen = (value / 10) % 10;
    208             int digitOfOne = value % 10;
    209             return (byte) ((digitOfTen << 4) | digitOfOne);
    210         }
    211     }
    212 
    213     /**
    214      * Place holder for time value.
    215      * @hide
    216      */
    217     @SystemApi
    218     public static final class Time extends TimeUnit {
    219         private Time(int hour, int minute) {
    220             super(hour, minute);
    221         }
    222     }
    223 
    224     /**
    225      * Place holder for duration value.
    226      * @hide
    227      */
    228     @SystemApi
    229     public static final class Duration extends TimeUnit {
    230         private Duration(int hour, int minute) {
    231             super(hour, minute);
    232         }
    233     }
    234 
    235     /**
    236      * Fields for recording sequence.
    237      * The following can be merged by OR(|) operation.
    238      */
    239     public static final int RECORDING_SEQUENCE_REPEAT_ONCE_ONLY = 0;
    240     public static final int RECORDING_SEQUENCE_REPEAT_SUNDAY = 1 << 0;
    241     public static final int RECORDING_SEQUENCE_REPEAT_MONDAY = 1 << 1;
    242     public static final int RECORDING_SEQUENCE_REPEAT_TUESDAY = 1 << 2;
    243     public static final int RECORDING_SEQUENCE_REPEAT_WEDNESDAY = 1 << 3;
    244     public static final int RECORDING_SEQUENCE_REPEAT_THURSDAY = 1 << 4;
    245     public static final int RECORDING_SEQUENCE_REPEAT_FRIDAY = 1 << 5;
    246     public static final int RECORDING_SEQUENCE_REPEAT_SATUREDAY = 1 << 6;
    247 
    248     private static final int RECORDING_SEQUENCE_REPEAT_MASK =
    249             (RECORDING_SEQUENCE_REPEAT_SUNDAY | RECORDING_SEQUENCE_REPEAT_MONDAY |
    250             RECORDING_SEQUENCE_REPEAT_TUESDAY | RECORDING_SEQUENCE_REPEAT_WEDNESDAY |
    251             RECORDING_SEQUENCE_REPEAT_THURSDAY | RECORDING_SEQUENCE_REPEAT_FRIDAY |
    252             RECORDING_SEQUENCE_REPEAT_SATUREDAY);
    253 
    254     /**
    255      * Creates {@link TimerInfo} with the given information.
    256      *
    257      * @param dayOfMonth day of month
    258      * @param monthOfYear month of year
    259      * @param startTime start time in {@link Time}
    260      * @param duration duration in {@link Duration}
    261      * @param recordingSequence recording sequence. Use RECORDING_SEQUENCE_REPEAT_ONCE_ONLY for no
    262      *            repeat. Otherwise use combination of {@link #RECORDING_SEQUENCE_REPEAT_SUNDAY},
    263      *            {@link #RECORDING_SEQUENCE_REPEAT_MONDAY},
    264      *            {@link #RECORDING_SEQUENCE_REPEAT_TUESDAY},
    265      *            {@link #RECORDING_SEQUENCE_REPEAT_WEDNESDAY},
    266      *            {@link #RECORDING_SEQUENCE_REPEAT_THURSDAY},
    267      *            {@link #RECORDING_SEQUENCE_REPEAT_FRIDAY},
    268      *            {@link #RECORDING_SEQUENCE_REPEAT_SATUREDAY}.
    269      * @return {@link TimerInfo}.
    270      * @throws IllegalArgumentException if input value is invalid
    271      */
    272     public static TimerInfo timerInfoOf(int dayOfMonth, int monthOfYear, Time startTime,
    273             Duration duration, int recordingSequence) {
    274         if (dayOfMonth < 0 || dayOfMonth > 31) {
    275             throw new IllegalArgumentException(
    276                     "Day of month should be in range of [0, 31]:" + dayOfMonth);
    277         }
    278         if (monthOfYear < 1 || monthOfYear > 12) {
    279             throw new IllegalArgumentException(
    280                     "Month of year should be in range of [1, 12]:" + monthOfYear);
    281         }
    282         checkTimeValue(startTime.mHour, startTime.mMinute);
    283         checkDurationValue(duration.mHour, duration.mMinute);
    284         // Recording sequence should use least 7 bits or no bits.
    285         if ((recordingSequence != 0)
    286                 && ((recordingSequence & ~RECORDING_SEQUENCE_REPEAT_MASK) != 0)) {
    287             throw new IllegalArgumentException(
    288                     "Invalid reecording sequence value:" + recordingSequence);
    289         }
    290 
    291         return new TimerInfo(dayOfMonth, monthOfYear, startTime, duration, recordingSequence);
    292     }
    293 
    294     /**
    295      * Container basic timer information. It consists of the following fields.
    296      * <ul>
    297      * <li>[Day of Month]
    298      * <li>[Month of Year]
    299      * <li>[Start Time]
    300      * <li>[Duration]
    301      * <li>[Recording Sequence]
    302      * </ul>
    303      * @hide
    304      */
    305     @SystemApi
    306     public static final class TimerInfo {
    307         private static final int DAY_OF_MONTH_SIZE = 1;
    308         private static final int MONTH_OF_YEAR_SIZE = 1;
    309         private static final int START_TIME_SIZE = 2; // 1byte for hour and 1byte for minute.
    310         private static final int DURATION_SIZE = 2; // 1byte for hour and 1byte for minute.
    311         private static final int RECORDING_SEQUENCE_SIZE = 1;
    312         private static final int BASIC_INFO_SIZE = DAY_OF_MONTH_SIZE + MONTH_OF_YEAR_SIZE
    313                 + START_TIME_SIZE + DURATION_SIZE + RECORDING_SEQUENCE_SIZE;
    314 
    315         /** Day of month. */
    316         private final int mDayOfMonth;
    317         /** Month of year. */
    318         private final int mMonthOfYear;
    319         /**
    320          * Time of day.
    321          * [Hour][Minute]. 0 &lt;= Hour &lt;= 24, 0 &lt;= Minute &lt;= 60 in BCD format.
    322          */
    323         private final Time mStartTime;
    324         /**
    325          * Duration. [Hour][Minute].
    326          * 0 &lt;= Hour &lt;= 99, 0 &lt;= Minute &lt;= 60 in BCD format.
    327          * */
    328         private final Duration mDuration;
    329         /**
    330          * Indicates if recording is repeated and, if so, on which days. For repeated recordings,
    331          * the recording sequence value is the bitwise OR of the days when recordings are required.
    332          * [Recording Sequence] shall be set to 0x00 when the recording is not repeated. Bit 7 is
    333          * reserved and shall be set to zero.
    334          */
    335         private final int mRecordingSequence;
    336 
    337         private TimerInfo(int dayOfMonth, int monthOfYear, Time startTime,
    338                 Duration duration, int recordingSequence) {
    339             mDayOfMonth = dayOfMonth;
    340             mMonthOfYear = monthOfYear;
    341             mStartTime = startTime;
    342             mDuration = duration;
    343             mRecordingSequence = recordingSequence;
    344         }
    345 
    346         int toByteArray(byte[] data, int index) {
    347             // [Day of Month]
    348             data[index] = (byte) mDayOfMonth;
    349             index += DAY_OF_MONTH_SIZE;
    350             // [Month of Year]
    351             data[index] = (byte) mMonthOfYear;
    352             index += MONTH_OF_YEAR_SIZE;
    353             // [Start Time]
    354             index += mStartTime.toByteArray(data, index);
    355             index += mDuration.toByteArray(data, index);
    356             // [Duration]
    357             // [Recording Sequence]
    358             data[index] = (byte) mRecordingSequence;
    359             return getDataSize();
    360         }
    361 
    362         int getDataSize() {
    363             return BASIC_INFO_SIZE;
    364         }
    365     }
    366 
    367     /**
    368      * Record source container for timer record. This is used to set parameter for &lt;Set Digital
    369      * Timer&gt;, &lt;Set Analogue Timer&gt;, and &lt;Set External Timer&gt; message.
    370      * <p>
    371      * In order to create this from each source type, use one of helper method.
    372      * <ul>
    373      * <li>{@link #ofDigitalSource} for digital source
    374      * <li>{@link #ofAnalogueSource} for analogue source
    375      * <li>{@link #ofExternalPlug} for external plug type
    376      * <li>{@link #ofExternalPhysicalAddress} for external physical address type.
    377      * </ul>
    378      * @hide
    379      */
    380     @SystemApi
    381     public static final class TimerRecordSource {
    382         private final RecordSource mRecordSource;
    383         private final TimerInfo mTimerInfo;
    384 
    385         private TimerRecordSource(TimerInfo timerInfo, RecordSource recordSource) {
    386             mTimerInfo = timerInfo;
    387             mRecordSource = recordSource;
    388         }
    389 
    390         int getDataSize() {
    391             return mTimerInfo.getDataSize() + mRecordSource.getDataSize(false);
    392         }
    393 
    394         int toByteArray(byte[] data, int index) {
    395             // Basic infos including [Day of Month] [Month of Year] [Start Time] [Duration]
    396             // [Recording Sequence]
    397             index += mTimerInfo.toByteArray(data, index);
    398             // [Record Source]
    399             mRecordSource.toByteArray(false, data, index);
    400             return getDataSize();
    401         }
    402     }
    403 
    404     /**
    405      * External source specifier types.
    406      */
    407     private static final int EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PLUG = 4;
    408     private static final int EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PHYSICAL_ADDRESS = 5;
    409 
    410     /**
    411      * Decorator for external source. Beside digital or analogue source, external source starts with
    412      * [External Source Specifier] because it covers both external plug type and external specifier.
    413      */
    414     private static class ExternalSourceDecorator extends RecordSource {
    415         private final RecordSource mRecordSource;
    416         private final int mExternalSourceSpecifier;
    417 
    418         private ExternalSourceDecorator(RecordSource recordSource, int externalSourceSpecifier) {
    419             // External source has one byte field for [External Source Specifier].
    420             super(recordSource.mSourceType, recordSource.getDataSize(false) + 1);
    421             mRecordSource = recordSource;
    422             mExternalSourceSpecifier = externalSourceSpecifier;
    423         }
    424 
    425         @Override
    426         int extraParamToByteArray(byte[] data, int index) {
    427             data[index] = (byte) mExternalSourceSpecifier;
    428             mRecordSource.toByteArray(false, data, index + 1);
    429             return getDataSize(false);
    430         }
    431     }
    432 
    433     /**
    434      * Checks the byte array of timer record source.
    435      * @param sourcetype
    436      * @param recordSource
    437      * @hide
    438      */
    439     @SystemApi
    440     public static boolean checkTimerRecordSource(int sourcetype, byte[] recordSource) {
    441         int recordSourceSize = recordSource.length - TimerInfo.BASIC_INFO_SIZE;
    442         switch (sourcetype) {
    443             case TIMER_RECORDING_TYPE_DIGITAL:
    444                 return DigitalServiceSource.EXTRA_DATA_SIZE == recordSourceSize;
    445             case TIMER_RECORDING_TYPE_ANALOGUE:
    446                 return AnalogueServiceSource.EXTRA_DATA_SIZE == recordSourceSize;
    447             case TIMER_RECORDING_TYPE_EXTERNAL:
    448                 int specifier = recordSource[TimerInfo.BASIC_INFO_SIZE];
    449                 if (specifier == EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PLUG) {
    450                     // One byte for specifier.
    451                     return ExternalPlugData.EXTRA_DATA_SIZE + 1 == recordSourceSize;
    452                 } else if (specifier == EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PHYSICAL_ADDRESS) {
    453                     // One byte for specifier.
    454                     return ExternalPhysicalAddress.EXTRA_DATA_SIZE + 1 == recordSourceSize;
    455                 } else {
    456                     // Invalid specifier.
    457                     return false;
    458                 }
    459             default:
    460                 return false;
    461         }
    462     }
    463 }
    464