Implement OneTouchRecordAction and stop one touch record.

In addition to it, add api for clearTimerRecording as well.
Separately, I will replace logic for notifying message with callback
interface.

Bug: 16160962

Change-Id: I2368f7c697eb44ed4542c0ec4412c63a6ae41a5c
This commit is contained in:
Jungshik Jang
2014-07-23 16:10:23 +09:00
parent 35efc633d0
commit b6591b8e53
9 changed files with 463 additions and 34 deletions

View File

@@ -69,6 +69,76 @@ public final class HdmiControlManager {
public static final int RESULT_INCORRECT_MODE = 6;
public static final int RESULT_COMMUNICATION_FAILED = 7;
// -- Message ids for display osd.
/** Place holder for recording status message. Indicates the status of a recording. */
public static final int MESSAGE_RECORDING_STATUS_MESSAGE_START = 0x100;
/** Recording currently selected source. Indicates the status of a recording. */
public static final int MESSAGE_RECORDING_CURRENTLY_SELECTED_SOURCE = 0x101;
/** Recording Digital Service. Indicates the status of a recording. */
public static final int MESSAGE_RECORDING_DIGITAL_SERVICE = 0x102;
/** Recording Analogue Service. Indicates the status of a recording. */
public static final int MESSAGE_RECORDING_ANALOGUE_SERVICE = 0x103;
/** Recording External input. Indicates the status of a recording. */
public static final int MESSAGE_RECORDING_EXTERNAL_INPUT = 0x104;
/** No recording – unable to record Digital Service. No suitable tuner. */
public static final int MESSAGE_NO_RECORDNIG_UNABLE_DIGITAL_SERVICE = 0x105;
/** No recording – unable to record Analogue Service. No suitable tuner. */
public static final int MESSAGE_NO_RECORDNIG_UNABLE_ANALOGUE_SERVICE = 0x106;
/**
* No recording – unable to select required service. as suitable tuner, but the requested
* parameters are invalid or out of range for that tuner.
*/
public static final int MESSAGE_NO_RECORDNIG_UNABLE_SELECTED_SERVICE = 0x107;
/** No recording – invalid External plug number */
public static final int MESSAGE_NO_RECORDNIG_INVALID_EXTERNAL_PLUG_NUMBER = 0x109;
/** No recording – invalid External Physical Address */
public static final int MESSAGE_NO_RECORDNIG_INVALID_EXTERNAL_PHYSICAL_ADDRESS = 0x10A;
/** No recording – CA system not supported */
public static final int MESSAGE_NO_RECORDNIG_UNSUPPORTED_CA = 0x10B;
/** No Recording – No or Insufficient CA Entitlements” */
public static final int MESSAGE_NO_RECORDNIG_NO_OR_INSUFFICIENT_CA_ENTITLEMENTS = 0x10C;
/** No recording – Not allowed to copy source. Source is “copy never”. */
public static final int MESSAGE_NO_RECORDNIG_DISALLOW_TO_COPY = 0x10D;
/** No recording – No further copies allowed */
public static final int MESSAGE_NO_RECORDNIG_DISALLOW_TO_FUTHER_COPIES = 0x10E;
/** No recording – No media */
public static final int MESSAGE_NO_RECORDNIG_NO_MEDIA = 0x110;
/** No recording – playing */
public static final int MESSAGE_NO_RECORDNIG_PLAYING = 0x111;
/** No recording – already recording */
public static final int MESSAGE_NO_RECORDNIG_ALREADY_RECORDING = 0x112;
/** No recording – media protected */
public static final int MESSAGE_NO_RECORDNIG_MEDIA_PROTECTED = 0x113;
/** No recording – no source signal */
public static final int MESSAGE_NO_RECORDNIG_NO_SOURCE_SIGNAL = 0x114;
/** No recording – media problem */
public static final int MESSAGE_NO_RECORDNIG_MEDIA_PROBLEM = 0x115;
/** No recording – not enough space available */
public static final int MESSAGE_NO_RECORDNIG_NOT_ENOUGH_SPACE = 0x116;
/** No recording – Parental Lock On */
public static final int MESSAGE_NO_RECORDNIG_PARENT_LOCK_ON = 0x117;
/** Recording terminated normally */
public static final int MESSAGE_RECORDING_TERMINATED_NORMALLY = 0x11A;
/** Recording has already terminated */
public static final int MESSAGE_RECORDING_ALREADY_TERMINATED = 0x11B;
/** No recording – other reason */
public static final int MESSAGE_NO_RECORDNIG_OTHER_REASON = 0x11F;
// From here extra message for recording that is not mentioned in CEC spec
/** No recording. Previous recording request in progress. */
public static final int MESSAGE_NO_RECORDING_PREVIOUS_RECORDING_IN_PROGRESS = 0x130;
/** No recording. Please check recorder and connection. */
public static final int MESSAGE_NO_RECORDING_CHECK_RECORDER_CONNECTION = 0x131;
/** Cannot record currently displayed source. */
public static final int MESSAGE_NO_RECORDING_FAIL_TO_RECORD_DISPLAYED_SCREEN = 0x132;
/** Timer recording type for digital service source. */
public static final int TIMER_RECORDING_TYPE_DIGITAL = 1;
/** Timer recording type for analogue service source. */
public static final int TIMER_RECORDING_TYPE_ANALOGUE = 2;
/** Timer recording type for external source. */
public static final int TIMER_RECORDING_TYPE_EXTERNAL = 3;
// True if we have a logical device of type playback hosted in the system.
private final boolean mHasPlaybackDevice;
// True if we have a logical device of type TV hosted in the system.

View File

@@ -103,8 +103,10 @@ public final class HdmiRecordSources {
*/
@SystemApi
public static final class OwnSource extends RecordSource {
protected OwnSource() {
super(RECORD_SOURCE_TYPE_OWN_SOURCE, 0);
private static final int EXTRA_DATA_SIZE = 0;
private OwnSource() {
super(RECORD_SOURCE_TYPE_OWN_SOURCE, EXTRA_DATA_SIZE);
}
@Override
@@ -744,4 +746,27 @@ public final class HdmiRecordSources {
byteArray[index + 1] = (byte) (value & 0xFF);
return 2;
}
/**
* Check the byte array of record source.
* @hide
*/
public static boolean checkRecordSource(byte[] recordSource) {
int recordSourceType = recordSource[0];
int extraDataSize = recordSource.length - 1;
switch (recordSourceType) {
case RECORD_SOURCE_TYPE_OWN_SOURCE:
return extraDataSize == OwnSource.EXTRA_DATA_SIZE;
case RECORD_SOURCE_TYPE_DIGITAL_SERVICE:
return extraDataSize == DigitalServiceSource.EXTRA_DATA_SIZE;
case RECORD_SOURCE_TYPE_ANALOGUE_SERVICE:
return extraDataSize == AnalogueServiceSource.EXTRA_DATA_SIZE;
case RECORD_SOURCE_TYPE_EXTERNAL_PLUG:
return extraDataSize == ExternalPlugData.EXTRA_DATA_SIZE;
case RECORD_SOURCE_TYPE_EXTERNAL_PHYSICAL_ADDRESS:
return extraDataSize == ExternalPhysicalAddress.EXTRA_DATA_SIZE;
default:
return false;
}
}
}

View File

@@ -15,6 +15,9 @@
*/
package android.hardware.hdmi;
import static android.hardware.hdmi.HdmiRecordSources.RecordSource;
import static android.hardware.hdmi.HdmiTimerRecordSources.TimerRecordSource;
import android.annotation.SystemApi;
import android.os.RemoteException;
import android.util.Log;
@@ -162,7 +165,7 @@ public final class HdmiTvClient extends HdmiClient {
*
* @return {@link HdmiRecordSources} to be used to set recording info
*/
HdmiRecordSources.RecordSource onRecordRequestReceived(int recorderAddress);
RecordSource onRecordRequestReceived(int recorderAddress);
}
/**
@@ -187,7 +190,7 @@ public final class HdmiTvClient extends HdmiClient {
* tvClient.startOneTouchRecord(recorderAddress, ownSource);
* </pre>
*/
public void startOneTouchRecord(int recorderAddress, HdmiRecordSources.RecordSource source) {
public void startOneTouchRecord(int recorderAddress, RecordSource source) {
try {
byte[] data = new byte[source.getDataSize(true)];
source.toByteArray(true, data, 0);
@@ -197,6 +200,19 @@ public final class HdmiTvClient extends HdmiClient {
}
}
/**
* Stop one touch record.
*
* @param recorderAddress recorder address where recoding will be stopped
*/
public void stopOneTouchRecord(int recorderAddress) {
try {
mService.stopOneTouchRecord(recorderAddress);
} catch (RemoteException e) {
Log.e(TAG, "failed to stop record: ", e);
}
}
/**
* Start timer recording with the given recoder address and recorder source.
* <p>
@@ -211,13 +227,47 @@ public final class HdmiTvClient extends HdmiClient {
* TimerRecordSource source = HdmiTimerRecourdSources.ofDigitalSource(timerInfo, recordSource);
* tvClient.startTimerRecording(recorderAddress, source);
* </pre>
*
* @param recorderAddress target recorder address
* @param sourceType type of record source. It should be one of
* {@link HdmiControlManager#TIMER_RECORDING_TYPE_DIGITAL},
* {@link HdmiControlManager#TIMER_RECORDING_TYPE_ANALOGUE},
* {@link HdmiControlManager#TIMER_RECORDING_TYPE_EXTERNAL}.
* @param source record source to be used
*/
public void startTimerRecording(int recorderAddress,
HdmiTimerRecordSources.TimerRecordSource source) {
public void startTimerRecording(int recorderAddress, int sourceType, TimerRecordSource source) {
checkTimerRecordingSourceType(sourceType);
try {
byte[] data = new byte[source.getDataSize()];
source.toByteArray(data, 0);
mService.startTimerRecording(recorderAddress, data);
mService.startTimerRecording(recorderAddress, sourceType, data);
} catch (RemoteException e) {
Log.e(TAG, "failed to start record: ", e);
}
}
private void checkTimerRecordingSourceType(int sourceType) {
switch (sourceType) {
case HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL:
case HdmiControlManager.TIMER_RECORDING_TYPE_ANALOGUE:
case HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL:
break;
default:
throw new IllegalArgumentException("Invalid source type:" + sourceType);
}
}
/**
* Clear timer recording with the given recorder address and recording source.
* For more details, please refer {@link #startTimerRecording(int, int, TimerRecordSource)}.
*/
public void clearTimerRecording(int recorderAddress, int sourceType, TimerRecordSource source) {
checkTimerRecordingSourceType(sourceType);
try {
byte[] data = new byte[source.getDataSize()];
source.toByteArray(data, 0);
mService.clearTimerRecording(recorderAddress, sourceType, data);
} catch (RemoteException e) {
Log.e(TAG, "failed to start record: ", e);
}

View File

@@ -64,5 +64,7 @@ interface IHdmiControlService {
void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType);
void setOneTouchRecordRequestListener(IHdmiRecordRequestListener listener);
void startOneTouchRecord(int recorderAddress, in byte[] recordSource);
void startTimerRecording(int recorderAddress, in byte[] recordSource);
void stopOneTouchRecord(int recorderAddress);
void startTimerRecording(int recorderAddress, int sourceType, in byte[] recordSource);
void clearTimerRecording(int recorderAddress, int sourceType, in byte[] recordSource);
}

View File

@@ -200,6 +200,8 @@ abstract class HdmiCecLocalDevice {
return handleVendorCommandWithId(message);
case Constants.MESSAGE_SET_OSD_NAME:
return handleSetOsdName(message);
case Constants.MESSAGE_RECORD_TV_SCREEN:
return handleRecordTvScreen(message);
default:
return false;
}
@@ -403,6 +405,13 @@ abstract class HdmiCecLocalDevice {
return true;
}
protected boolean handleRecordTvScreen(HdmiCecMessage message) {
// The default behavior of <Record TV Screen> is replying <Feature Abort> with "Refused".
mService.sendCecCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand(mAddress,
message.getSource(), message.getOpcode(), Constants.ABORT_REFUSED));
return true;
}
@ServiceThreadOnly
final void handleAddressAllocated(int logicalAddress, boolean fromBootup) {
assertRunOnServiceThread();

View File

@@ -19,6 +19,7 @@ package com.android.server.hdmi;
import android.content.Intent;
import android.hardware.hdmi.HdmiCecDeviceInfo;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiRecordSources;
import android.hardware.hdmi.IHdmiControlCallback;
import android.media.AudioManager;
import android.media.AudioSystem;
@@ -35,6 +36,7 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
@@ -808,6 +810,26 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
return true;
}
// Seq #53
@Override
@ServiceThreadOnly
protected boolean handleRecordTvScreen(HdmiCecMessage message) {
List<OneTouchRecordAction> actions = getActions(OneTouchRecordAction.class);
if (!actions.isEmpty()) {
// Assumes only one OneTouchRecordAction.
OneTouchRecordAction action = actions.get(0);
if (action.getRecorderAddress() != message.getSource()) {
displayOsd(HdmiControlManager.MESSAGE_NO_RECORDING_PREVIOUS_RECORDING_IN_PROGRESS);
}
return super.handleRecordTvScreen(message);
}
int recorderAddress = message.getSource();
byte[] recordSource = mService.invokeRecordRequestListener(recorderAddress);
startOneTouchRecord(recorderAddress, recordSource);
return true;
}
private boolean isMessageForSystemAudio(HdmiCecMessage message) {
if (message.getSource() != Constants.ADDR_AUDIO_SYSTEM
|| message.getDestination() != Constants.ADDR_TV
@@ -1129,6 +1151,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
// LocalDeviceTv.onAddressAllocated() -> launchDeviceDiscovery().
removeAction(DeviceDiscoveryAction.class);
removeAction(HotplugDetectionAction.class);
// Remove one touch record action.
removeAction(OneTouchRecordAction.class);
disableSystemAudioIfExist();
disableArcIfExist();
@@ -1210,4 +1234,72 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
mService.getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
HdmiControlService.PERMISSION);
}
// Seq #54 and #55
@ServiceThreadOnly
void startOneTouchRecord(int recorderAddress, byte[] recordSource) {
assertRunOnServiceThread();
if (!mService.isControlEnabled()) {
Slog.w(TAG, "Can not start one touch record. CEC control is disabled.");
return;
}
if (!checkRecorder(recorderAddress)) {
Slog.w(TAG, "Invalid recorder address:" + recorderAddress);
return;
}
if (!checkRecordSource(recordSource)) {
Slog.w(TAG, "Invalid record source." + Arrays.toString(recordSource));
return;
}
addAndStartAction(new OneTouchRecordAction(this, recorderAddress, recordSource));
Slog.i(TAG, "Start new [One Touch Record]-Target:" + recorderAddress + ", recordSource:"
+ Arrays.toString(recordSource));
}
@ServiceThreadOnly
void stopOneTouchRecord(int recorderAddress) {
assertRunOnServiceThread();
if (!mService.isControlEnabled()) {
Slog.w(TAG, "Can not stop one touch record. CEC control is disabled.");
return;
}
if (!checkRecorder(recorderAddress)) {
Slog.w(TAG, "Invalid recorder address:" + recorderAddress);
return;
}
// Remove one touch record action so that other one touch record can be started.
removeAction(OneTouchRecordAction.class);
mService.sendCecCommand(HdmiCecMessageBuilder.buildRecordOff(mAddress, recorderAddress));
Slog.i(TAG, "Stop [One Touch Record]-Target:" + recorderAddress);
}
private boolean checkRecorder(int recorderAddress) {
HdmiCecDeviceInfo device = getDeviceInfo(recorderAddress);
return (device != null)
&& (HdmiUtils.getTypeFromAddress(recorderAddress)
== HdmiCecDeviceInfo.DEVICE_RECORDER);
}
private boolean checkRecordSource(byte[] recordSource) {
return (recordSource != null) && HdmiRecordSources.checkRecordSource(recordSource);
}
@ServiceThreadOnly
void startTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) {
assertRunOnServiceThread();
// TODO: implement this.
}
@ServiceThreadOnly
void clearTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) {
assertRunOnServiceThread();
// TODO: implement this.
}
}

View File

@@ -455,6 +455,29 @@ public class HdmiCecMessageBuilder {
return buildCommand(src, dest, Constants.MESSAGE_VENDOR_COMMAND_WITH_ID, params);
}
/**
* Build &lt;Record On&gt; command.
*
* @param src source address of command
* @param dest destination address of command
* @param params parameter of command
* @return newly created {@link HdmiCecMessage}
*/
static HdmiCecMessage buildRecordOn(int src, int dest, byte[] params) {
return buildCommand(src, dest, Constants.MESSAGE_RECORD_ON, params);
}
/**
* Build &lt;Record Off&gt; command.
*
* @param src source address of command
* @param dest destination address of command
* @return newly created {@link HdmiCecMessage}
*/
static HdmiCecMessage buildRecordOff(int src, int dest) {
return buildCommand(src, dest, Constants.MESSAGE_RECORD_OFF);
}
/***** Please ADD new buildXXX() methods above. ******/
/**

View File

@@ -55,6 +55,8 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
import com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback;
import libcore.util.EmptyArray;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -157,6 +159,12 @@ public final class HdmiControlService extends SystemService {
@GuardedBy("mLock")
private InputChangeListenerRecord mInputChangeListenerRecord;
@GuardedBy("mLock")
private IHdmiRecordRequestListener mRecordRequestListener;
@GuardedBy("mLock")
private HdmiRecordRequestListenerRecord mRecordRequestListenerRecord;
// Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol
// handling will be disabled and no request will be handled.
@GuardedBy("mLock")
@@ -684,6 +692,15 @@ public final class HdmiControlService extends SystemService {
}
}
private class HdmiRecordRequestListenerRecord implements IBinder.DeathRecipient {
@Override
public void binderDied() {
synchronized (mLock) {
mRecordRequestListener = null;
}
}
}
private void enforceAccessPermission() {
getContext().enforceCallingOrSelfPermission(PERMISSION, TAG);
}
@@ -1014,17 +1031,65 @@ public final class HdmiControlService extends SystemService {
@Override
public void setOneTouchRecordRequestListener(IHdmiRecordRequestListener listener) {
// TODO: implement this.
HdmiControlService.this.setOneTouchRecordRequestListener(listener);
}
@Override
public void startOneTouchRecord(int recorderAddress, byte[] recordSource) {
// TODO: implement this.
public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) {
runOnServiceThread(new Runnable() {
@Override
public void run() {
if (!isTvDevice()) {
Slog.w(TAG, "No TV is available.");
return;
}
tv().startOneTouchRecord(recorderAddress, recordSource);
}
});
}
@Override
public void startTimerRecording(int recorderAddress, byte[] recordSource) {
// TODO: implement this.
public void stopOneTouchRecord(final int recorderAddress) {
runOnServiceThread(new Runnable() {
@Override
public void run() {
if (!isTvDevice()) {
Slog.w(TAG, "No TV is available.");
return;
}
tv().stopOneTouchRecord(recorderAddress);
}
});
}
@Override
public void startTimerRecording(final int recorderAddress, final int sourceType,
final byte[] recordSource) {
runOnServiceThread(new Runnable() {
@Override
public void run() {
if (!isTvDevice()) {
Slog.w(TAG, "No TV is available.");
return;
}
tv().startTimerRecording(recorderAddress, sourceType, recordSource);
}
});
}
@Override
public void clearTimerRecording(final int recorderAddress, final int sourceType,
final byte[] recordSource) {
runOnServiceThread(new Runnable() {
@Override
public void run() {
if (!isTvDevice()) {
Slog.w(TAG, "No TV is available.");
return;
}
tv().clearTimerRecording(recorderAddress, sourceType, recordSource);
}
});
}
}
@@ -1169,6 +1234,32 @@ public final class HdmiControlService extends SystemService {
}
}
private void setOneTouchRecordRequestListener(IHdmiRecordRequestListener listener) {
synchronized (mLock) {
mRecordRequestListenerRecord = new HdmiRecordRequestListenerRecord();
try {
listener.asBinder().linkToDeath(mRecordRequestListenerRecord, 0);
} catch (RemoteException e) {
Slog.w(TAG, "Listener already died", e);
return;
}
mRecordRequestListener = listener;
}
}
byte[] invokeRecordRequestListener(int recorderAddress) {
synchronized (mLock) {
try {
if (mRecordRequestListener != null) {
return mRecordRequestListener.onRecordRequestReceived(recorderAddress);
}
} catch (RemoteException e) {
Slog.w(TAG, "Failed to start record.", e);
}
return EmptyArray.BYTE;
}
}
private void invokeCallback(IHdmiControlCallback callback, int result) {
try {
callback.onComplete(result);

View File

@@ -16,51 +16,118 @@
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;
import static android.hardware.hdmi.HdmiControlManager.MESSAGE_NO_RECORDING_CHECK_RECORDER_CONNECTION;
import static android.hardware.hdmi.HdmiControlManager.MESSAGE_RECORDING_ANALOGUE_SERVICE;
import static android.hardware.hdmi.HdmiControlManager.MESSAGE_RECORDING_CURRENTLY_SELECTED_SOURCE;
import static android.hardware.hdmi.HdmiControlManager.MESSAGE_RECORDING_DIGITAL_SERVICE;
import static android.hardware.hdmi.HdmiControlManager.MESSAGE_RECORDING_EXTERNAL_INPUT;
import static android.hardware.hdmi.HdmiControlManager.MESSAGE_RECORDING_STATUS_MESSAGE_START;
import android.util.Slog;
import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
/**
* 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;
private static final String TAG = "OneTouchRecordAction";
OneTouchRecordAction(HdmiCecLocalDevice source, int recorderAddress, int recordingType) {
// Timer out for waiting <Record Status>
private static final int RECORD_STATUS_TIMEOUT = 120000;
// State that waits for <Record Status> once sending <Record On>
private static final int STATE_WAITING_FOR_RECORD_STATUS = 1;
// State that describes recording in progress.
private static final int STATE_RECORDING_IN_PROGRESS = 2;
private final int mRecorderAddress;
private final byte[] mRecordSource;
OneTouchRecordAction(HdmiCecLocalDevice source, int recorderAddress, byte[] recordSource) {
super(source);
mRecorderAddress = recorderAddress;
mRecordingType = recordingType;
mRecordSource = recordSource;
}
@Override
boolean start() {
return false;
sendRecordOn();
return true;
}
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.
}
private void sendRecordOn() {
sendCommand(HdmiCecMessageBuilder.buildRecordOn(getSourceAddress(), mRecorderAddress,
mRecordSource),
new SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
// if failed to send <Record On>, display error message and finish action.
if (error != Constants.SEND_RESULT_SUCCESS) {
tv().displayOsd(MESSAGE_NO_RECORDING_CHECK_RECORDER_CONNECTION);
finish();
return;
}
mState = STATE_WAITING_FOR_RECORD_STATUS;
addTimer(mState, RECORD_STATUS_TIMEOUT);
}
});
}
@Override
boolean processCommand(HdmiCecMessage cmd) {
if (mState != STATE_WAITING_FOR_RECORD_STATUS) {
return false;
}
switch (cmd.getOpcode()) {
case Constants.MESSAGE_RECORD_STATUS:
return handleRecordStatus(cmd);
}
return false;
}
private boolean handleRecordStatus(HdmiCecMessage cmd) {
// Only handle message coming from original recorder.
if (cmd.getSource() != mRecorderAddress) {
return false;
}
int recordStatus = cmd.getParams()[0];
Slog.i(TAG, "Got record status:" + recordStatus + " from " + cmd.getSource());
int recordStatusMessageCode = recordStatus + MESSAGE_RECORDING_STATUS_MESSAGE_START;
tv().displayOsd(recordStatusMessageCode);
// If recording started successfully, change state and keep this action until <Record Off>
// received. Otherwise, finish action.
switch (recordStatusMessageCode) {
case MESSAGE_RECORDING_CURRENTLY_SELECTED_SOURCE:
case MESSAGE_RECORDING_DIGITAL_SERVICE:
case MESSAGE_RECORDING_ANALOGUE_SERVICE:
case MESSAGE_RECORDING_EXTERNAL_INPUT:
mState = STATE_RECORDING_IN_PROGRESS;
mActionTimer.clearTimerMessage();
break;
default:
finish();
break;
}
return true;
}
@Override
void handleTimerEvent(int state) {
if (mState != state) {
Slog.w(TAG, "Timeout in invalid state:[Expected:" + mState + ", Actual:" + state + "]");
return;
}
tv().displayOsd(MESSAGE_NO_RECORDING_CHECK_RECORDER_CONNECTION);
finish();
}
int getRecorderAddress() {