am 7722d859: am c1d403f6: am da251030: Add startTimerRecording api to IHdmiControlService.

* commit '7722d859bb4c4e54632ddf7529e4bfca7dff00a7':
  Add startTimerRecording api to IHdmiControlService.
This commit is contained in:
Jungshik Jang
2014-07-23 13:26:10 +00:00
committed by Android Git Automerger
4 changed files with 461 additions and 13 deletions

View File

@@ -0,0 +1,415 @@
/*
* 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.SystemApi;
import android.hardware.hdmi.HdmiRecordSources.AnalogueServiceSource;
import android.hardware.hdmi.HdmiRecordSources.DigitalServiceSource;
import android.hardware.hdmi.HdmiRecordSources.ExternalPhysicalAddress;
import android.hardware.hdmi.HdmiRecordSources.ExternalPlugData;
import android.hardware.hdmi.HdmiRecordSources.RecordSource;
import android.util.Log;
/**
* Container for timer record source used for timer recording. Timer source consists of two parts,
* timer info and record source.
* <p>
* Timer info contains all timing information used for recording. It consists of the following
* values.
* <ul>
* <li>[Day of Month]
* <li>[Month of Year]
* <li>[Start Time]
* <li>[Duration]
* <li>[Recording Sequence]
* </ul>
* <p>
* Record source containers all program information used for recording.
* For more details, look at {@link HdmiRecordSources}.
* <p>
* Usage
* <pre>
* TimeOrDuration startTime = HdmiTimerRecordSources.ofTime(18, 00); // 6PM.
* TimeOrDuration duration = HdmiTimerRecordSource.ofDuration(1, 00); // 1 hour duration.
* // For 1 hour from 6PM, August 10th every SaturDay and Sunday.
* TimerInfo timerInfo = HdmiTimerRecordSource.timerInfoOf(10, 8, starTime, duration,
* HdmiTimerRecordSource.RECORDING_SEQUENCE_REPEAT_SATURDAY |
* HdmiTimerRecordSource.RECORDING_SEQUENCE_REPEAT_SUNDAY);
* // create digital source.
* DigitalServiceSource recordSource = HdmiRecordSource.ofDvb(...);
* TimerRecordSource source = ofDigitalSource(timerInfo, recordSource);
* </pre>
*
* @hide
*/
@SystemApi
public class HdmiTimerRecordSources {
private static final String TAG = "HdmiTimerRecordingSources";
private HdmiTimerRecordSources() {}
/**
* Create {@link TimerRecordSource} for digital source which is used for &lt;Set Digital
* Timer&gt;.
*
* @param timerInfo timer info used for timer recording
* @param source digital source used for timer recording
* @return {@link TimerRecordSource}
* @throws IllegalArgumentException if {@code timerInfo} or {@code source} is null
*/
public static TimerRecordSource ofDigitalSource(TimerInfo timerInfo,
DigitalServiceSource source) {
checkTimerRecordSourceInputs(timerInfo, source);
return new TimerRecordSource(timerInfo, source);
}
/**
* Create {@link TimerRecordSource} for analogue source which is used for &lt;Set Analogue
* Timer&gt;.
*
* @param timerInfo timer info used for timer recording
* @param source digital source used for timer recording
* @return {@link TimerRecordSource}
* @throws IllegalArgumentException if {@code timerInfo} or {@code source} is null
*/
public static TimerRecordSource ofAnalogueSource(TimerInfo timerInfo,
AnalogueServiceSource source) {
checkTimerRecordSourceInputs(timerInfo, source);
return new TimerRecordSource(timerInfo, source);
}
/**
* Create {@link TimerRecordSource} for external plug which is used for &lt;Set External
* Timer&gt;.
*
* @param timerInfo timer info used for timer recording
* @param source digital source used for timer recording
* @return {@link TimerRecordSource}
* @throws IllegalArgumentException if {@code timerInfo} or {@code source} is null
*/
public static TimerRecordSource ofExternalPlug(TimerInfo timerInfo, ExternalPlugData source) {
checkTimerRecordSourceInputs(timerInfo, source);
return new TimerRecordSource(timerInfo,
new ExternalSourceDecorator(source, EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PLUG));
}
/**
* Create {@link TimerRecordSource} for external physical address which is used for &lt;Set
* External Timer&gt;.
*
* @param timerInfo timer info used for timer recording
* @param source digital source used for timer recording
* @return {@link TimerRecordSource}
* @throws IllegalArgumentException if {@code timerInfo} or {@code source} is null
*/
public static TimerRecordSource ofExternalPhysicalAddress(TimerInfo timerInfo,
ExternalPhysicalAddress source) {
checkTimerRecordSourceInputs(timerInfo, source);
return new TimerRecordSource(timerInfo,
new ExternalSourceDecorator(source,
EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PHYSICAL_ADDRESS));
}
private static void checkTimerRecordSourceInputs(TimerInfo timerInfo, RecordSource source) {
if (timerInfo == null) {
Log.w(TAG, "TimerInfo should not be null.");
throw new IllegalArgumentException("TimerInfo should not be null.");
}
if (source == null) {
Log.w(TAG, "source should not be null.");
throw new IllegalArgumentException("source should not be null.");
}
}
/**
* Create {@link Duration} for time value.
*
* @param hour hour in range of [0, 24]
* @param minute minute in range of [0, 60]
* @return {@link Duration}
* @throw IllegalArgumentException if hour or minute is out of range
*/
public static Time ofTime(int hour, int minute) {
checkTimeValue(hour, minute);
return new Time(hour, minute);
}
private static void checkTimeValue(int hour, int minute) {
if (hour < 0 || hour > 24) {
throw new IllegalArgumentException("Hour should be in rage of [0, 24]:" + hour);
}
if (minute < 0 || minute > 60) {
throw new IllegalArgumentException("Minute should be in rage of [0, 60]:" + minute);
}
}
/**
* Create {@link Duration} for duration value.
*
* @param hour hour in range of [0, 90]
* @param minute minute in range of [0, 60]
* @return {@link Duration}
* @throw IllegalArgumentException if hour or minute is out of range
*/
public static Duration ofDuration(int hour, int minute) {
checkDurationValue(hour, minute);
return new Duration(hour, minute);
}
private static void checkDurationValue(int hour, int minute) {
if (hour < 0 || hour > 99) {
throw new IllegalArgumentException("Hour should be in rage of [0, 99]:" + hour);
}
if (minute < 0 || minute > 60) {
throw new IllegalArgumentException("minute should be in rage of [0, 60]:" + minute);
}
}
private static class TimeUnit {
protected final int mHour;
protected final int mMinute;
protected TimeUnit(int hour, int minute) {
mHour = hour;
mMinute = minute;
}
protected int toByteArray(byte[] data, int index) {
data[index] = toBcdByte(mHour);
data[index + 1] = toBcdByte(mMinute);
return 2;
}
protected static byte toBcdByte(int value) {
int digitOfTen = (value / 10) % 10;
int digitOfOne = value % 10;
return (byte) ((digitOfTen << 4) | digitOfOne);
}
}
/**
* Place holder for time value.
*/
public static class Time extends TimeUnit {
private Time(int hour, int minute) {
super(hour, minute);
}
}
/**
* Place holder for duration value.
*/
public static class Duration extends TimeUnit {
private Duration(int hour, int minute) {
super(hour, minute);
}
}
/**
* Fields for recording sequence.
* The following can be merged by OR(|) operation.
*/
public static final int RECORDING_SEQUENCE_REPEAT_ONCE_ONLY = 0;
public static final int RECORDING_SEQUENCE_REPEAT_SUNDAY = 1 << 0;
public static final int RECORDING_SEQUENCE_REPEAT_MONDAY = 1 << 1;
public static final int RECORDING_SEQUENCE_REPEAT_TUESDAY = 1 << 2;
public static final int RECORDING_SEQUENCE_REPEAT_WEDNESDAY = 1 << 3;
public static final int RECORDING_SEQUENCE_REPEAT_THURSDAY = 1 << 4;
public static final int RECORDING_SEQUENCE_REPEAT_FRIDAY = 1 << 5;
public static final int RECORDING_SEQUENCE_REPEAT_SATUREDAY = 1 << 6;
private static final int RECORDING_SEQUENCE_REPEAT_MASK =
(RECORDING_SEQUENCE_REPEAT_SUNDAY | RECORDING_SEQUENCE_REPEAT_MONDAY |
RECORDING_SEQUENCE_REPEAT_TUESDAY | RECORDING_SEQUENCE_REPEAT_WEDNESDAY |
RECORDING_SEQUENCE_REPEAT_THURSDAY | RECORDING_SEQUENCE_REPEAT_FRIDAY |
RECORDING_SEQUENCE_REPEAT_SATUREDAY);
/**
* Create {@link TimerInfo} with the given information.
*
* @param dayOfMonth day of month
* @param monthOfYear month of year
* @param startTime start time in {@link Time}
* @param duration duration in {@link Duration}
* @param recordingSequence recording sequence. Use RECORDING_SEQUENCE_REPEAT_ONCE_ONLY for no
* repeat. Otherwise use combination of {@link #RECORDING_SEQUENCE_REPEAT_SUNDAY},
* {@link #RECORDING_SEQUENCE_REPEAT_MONDAY},
* {@link #RECORDING_SEQUENCE_REPEAT_TUESDAY},
* {@link #RECORDING_SEQUENCE_REPEAT_WEDNESDAY},
* {@link #RECORDING_SEQUENCE_REPEAT_THURSDAY},
* {@link #RECORDING_SEQUENCE_REPEAT_FRIDAY},
* {@link #RECORDING_SEQUENCE_REPEAT_SATUREDAY}.
* @return {@link TimerInfo}.
* @throw IllegalArgumentException if input value is invalid
*/
public static TimerInfo timerInfoOf(int dayOfMonth, int monthOfYear, Time startTime,
Duration duration, int recordingSequence) {
if (dayOfMonth < 0 || dayOfMonth > 31) {
throw new IllegalArgumentException(
"Day of month should be in range of [0, 31]:" + dayOfMonth);
}
if (monthOfYear < 1 || monthOfYear > 12) {
throw new IllegalArgumentException(
"Month of year should be in range of [1, 12]:" + monthOfYear);
}
checkTimeValue(startTime.mHour, startTime.mMinute);
checkDurationValue(duration.mHour, duration.mMinute);
// Recording sequence should use least 7 bits or no bits.
if ((recordingSequence != 0)
&& ((recordingSequence & ~RECORDING_SEQUENCE_REPEAT_MASK) != 0)) {
throw new IllegalArgumentException(
"Invalid reecording sequence value:" + recordingSequence);
}
return new TimerInfo(dayOfMonth, monthOfYear, startTime, duration, recordingSequence);
}
/**
* Container basic timer information. It consists of the following fields.
* <ul>
* <li>[Day of Month]
* <li>[Month of Year]
* <li>[Start Time]
* <li>[Duration]
* <li>[Recording Sequence]
* </ul>
*/
public static class TimerInfo {
private static final int DAY_OF_MONTH_SIZE = 1;
private static final int MONTH_OF_YEAR_SIZE = 1;
private static final int START_TIME_SIZE = 2; // 1byte for hour and 1byte for minute.
private static final int DURATION_SIZE = 2; // 1byte for hour and 1byte for minute.
private static final int RECORDING_SEQUENCE_SIZE = 1;
private static final int BASIC_INFO_SIZE = DAY_OF_MONTH_SIZE + MONTH_OF_YEAR_SIZE
+ START_TIME_SIZE + DURATION_SIZE + RECORDING_SEQUENCE_SIZE;
/** Day of month. */
private final int mDayOfMonth;
/** Month of year. */
private final int mMonthOfYear;
/**
* Time of day.
* [Hour][Minute]. 0 &lt;= Hour &lt;= 24, 0 &lt;= Minute &lt;= 60 in BCD format.
*/
private final Time mStartTime;
/**
* Duration. [Hour][Minute].
* 0 &lt;= Hour &lt;= 99, 0 &lt;= Minute &lt;= 60 in BCD format.
* */
private final Duration mDuration;
/**
* Indicates if recording is repeated and, if so, on which days. For repeated recordings,
* the recording sequence value is the bitwise OR of the days when recordings are required.
* [Recording Sequence] shall be set to 0x00 when the recording is not repeated. Bit 7 is
* reserved and shall be set to zero.
*/
private final int mRecordingSequence;
private TimerInfo(int dayOfMonth, int monthOfYear, Time startTime,
Duration duration, int recordingSequence) {
mDayOfMonth = dayOfMonth;
mMonthOfYear = monthOfYear;
mStartTime = startTime;
mDuration = duration;
mRecordingSequence = recordingSequence;
}
int toByteArray(byte[] data, int index) {
// [Day of Month]
data[index] = (byte) mDayOfMonth;
index += DAY_OF_MONTH_SIZE;
// [Month of Year]
data[index] = (byte) mMonthOfYear;
index += MONTH_OF_YEAR_SIZE;
// [Start Time]
index += mStartTime.toByteArray(data, index);
index += mDuration.toByteArray(data, index);
// [Duration]
// [Recording Sequence]
data[index] = (byte) mRecordingSequence;
return getDataSize();
}
int getDataSize() {
return BASIC_INFO_SIZE;
}
}
/**
* Record source container for timer record. This is used to set parameter for &lt;Set Digital
* Timer&gt;, &lt;Set Analogue Timer&gt;, and &lt;Set External Timer&gt; message.
* <p>
* In order to create this from each source type, use one of helper method.
* <ul>
* <li>{@link #ofDigitalSource} for digital source
* <li>{@link #ofAnalogueSource} for analogue source
* <li>{@link #ofExternalPlug} for external plug type
* <li>{@link #ofExternalPhysicalAddress} for external physical address type.
* </ul>
*/
public static class TimerRecordSource {
private final RecordSource mRecordSource;
private final TimerInfo mTimerInfo;
private TimerRecordSource(TimerInfo timerInfo, RecordSource recordSource) {
mTimerInfo = timerInfo;
mRecordSource = recordSource;
}
int getDataSize() {
return mTimerInfo.getDataSize() + mRecordSource.getDataSize(false);
}
int toByteArray(byte[] data, int index) {
// Basic infos including [Day of Month] [Month of Year] [Start Time] [Duration]
// [Recording Sequence]
index += mTimerInfo.toByteArray(data, index);
// [Record Source]
mRecordSource.toByteArray(false, data, index);
return getDataSize();
}
}
/**
* External source specifier types.
*/
private static final int EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PLUG = 4;
private static final int EXTERNAL_SOURCE_SPECIFIER_EXTERNAL_PHYSICAL_ADDRESS = 5;
/**
* Decorator for external source. Beside digital or analogue source, external source starts with
* [External Source Specifier] because it covers both external plug type and external specifier.
*/
private static class ExternalSourceDecorator extends RecordSource {
private final RecordSource mRecordSource;
private final int mExternalSourceSpecifier;
private ExternalSourceDecorator(RecordSource recordSource, int externalSourceSpecifier) {
// External source has one byte field for [External Source Specifier].
super(recordSource.mSourceType, recordSource.getDataSize(false) + 1);
mRecordSource = recordSource;
mExternalSourceSpecifier = externalSourceSpecifier;
}
@Override
int extraParamToByteArray(byte[] data, int index) {
data[index] = (byte) mExternalSourceSpecifier;
mRecordSource.toByteArray(false, data, index + 1);
return getDataSize(false);
}
}
}

View File

@@ -168,29 +168,56 @@ public final class HdmiTvClient extends HdmiClient {
/**
* Set {@link RecordRequestListener} to hdmi control service.
*/
public void setRecordRequestListener(RecordRequestListener listener) {
public void setOneTouchRecordRequestListener(RecordRequestListener listener) {
try {
mService.setRecordRequestListener(getCallbackWrapper(listener));
mService.setOneTouchRecordRequestListener(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
* Start one touch 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);
* tvClient.startOneTouchRecord(recorderAddress, ownSource);
* </pre>
*/
public void startRecord(int recorderAddress, HdmiRecordSources.RecordSource source) {
public void startOneTouchRecord(int recorderAddress, HdmiRecordSources.RecordSource source) {
try {
byte[] data = new byte[source.getDataSize(true)];
source.toByteArray(true, data, 0);
mService.startRecord(recorderAddress, data);
mService.startOneTouchRecord(recorderAddress, data);
} catch (RemoteException e) {
Log.e(TAG, "failed to start record: ", e);
}
}
/**
* Start timer recording with the given recoder address and recorder source.
* <p>
* Usage
* <pre>
* HdmiTvClient tvClient = ....;
* // create timer info
* TimerInfo timerInfo = HdmiTimerRecourdSources.timerInfoOf(...);
* // for digital source.
* DigitalServiceSource recordSource = HdmiRecordSources.ofDigitalService(...);
* // create timer recording source.
* TimerRecordSource source = HdmiTimerRecourdSources.ofDigitalSource(timerInfo, recordSource);
* tvClient.startTimerRecording(recorderAddress, source);
* </pre>
*/
public void startTimerRecording(int recorderAddress,
HdmiTimerRecordSources.TimerRecordSource source) {
try {
byte[] data = new byte[source.getDataSize()];
source.toByteArray(data, 0);
mService.startTimerRecording(recorderAddress, data);
} catch (RemoteException e) {
Log.e(TAG, "failed to start record: ", e);
}

View File

@@ -55,13 +55,14 @@ interface IHdmiControlService {
void setArcMode(boolean enabled);
void setOption(int option, int value);
void setProhibitMode(boolean enabled);
oneway void setSystemAudioVolume(int oldIndex, int newIndex, int maxIndex);
oneway void setSystemAudioMute(boolean mute);
void setSystemAudioVolume(int oldIndex, int newIndex, int maxIndex);
void setSystemAudioMute(boolean mute);
void setInputChangeListener(IHdmiInputChangeListener listener);
List<HdmiCecDeviceInfo> getInputDevices();
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);
void setOneTouchRecordRequestListener(IHdmiRecordRequestListener listener);
void startOneTouchRecord(int recorderAddress, in byte[] recordSource);
void startTimerRecording(int recorderAddress, in byte[] recordSource);
}

View File

@@ -1013,12 +1013,17 @@ public final class HdmiControlService extends SystemService {
}
@Override
public void setRecordRequestListener(IHdmiRecordRequestListener listener) {
public void setOneTouchRecordRequestListener(IHdmiRecordRequestListener listener) {
// TODO: implement this.
}
@Override
public void startRecord(int recorderAddress, byte[] recordSource) {
public void startOneTouchRecord(int recorderAddress, byte[] recordSource) {
// TODO: implement this.
}
@Override
public void startTimerRecording(int recorderAddress, byte[] recordSource) {
// TODO: implement this.
}
}