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