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 com.android.server.hdmi; 18 19 import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION; 20 import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE; 21 import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE; 22 import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE; 23 import static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT; 24 25 import android.hardware.tv.cec.V1_0.SendMessageResult; 26 import android.util.Slog; 27 import com.android.server.hdmi.HdmiControlService.SendMessageCallback; 28 29 /** 30 * Feature action that performs one touch record. 31 */ 32 public class OneTouchRecordAction extends HdmiCecFeatureAction { 33 private static final String TAG = "OneTouchRecordAction"; 34 35 // Timer out for waiting <Record Status> 120s 36 private static final int RECORD_STATUS_TIMEOUT_MS = 120000; 37 38 // State that waits for <Record Status> once sending <Record On> 39 private static final int STATE_WAITING_FOR_RECORD_STATUS = 1; 40 // State that describes recording in progress. 41 private static final int STATE_RECORDING_IN_PROGRESS = 2; 42 43 private final int mRecorderAddress; 44 private final byte[] mRecordSource; 45 OneTouchRecordAction(HdmiCecLocalDevice source, int recorderAddress, byte[] recordSource)46 OneTouchRecordAction(HdmiCecLocalDevice source, int recorderAddress, byte[] recordSource) { 47 super(source); 48 mRecorderAddress = recorderAddress; 49 mRecordSource = recordSource; 50 } 51 52 @Override start()53 boolean start() { 54 sendRecordOn(); 55 return true; 56 } 57 sendRecordOn()58 private void sendRecordOn() { 59 sendCommand(HdmiCecMessageBuilder.buildRecordOn(getSourceAddress(), mRecorderAddress, 60 mRecordSource), 61 new SendMessageCallback() { 62 @Override 63 public void onSendCompleted(int error) { 64 // if failed to send <Record On>, display error message and finish action. 65 if (error != SendMessageResult.SUCCESS) { 66 tv().announceOneTouchRecordResult( 67 mRecorderAddress, 68 ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION); 69 finish(); 70 return; 71 } 72 } 73 }); 74 mState = STATE_WAITING_FOR_RECORD_STATUS; 75 addTimer(mState, RECORD_STATUS_TIMEOUT_MS); 76 } 77 78 @Override processCommand(HdmiCecMessage cmd)79 boolean processCommand(HdmiCecMessage cmd) { 80 if (mState != STATE_WAITING_FOR_RECORD_STATUS || mRecorderAddress != cmd.getSource()) { 81 return false; 82 } 83 84 switch (cmd.getOpcode()) { 85 case Constants.MESSAGE_RECORD_STATUS: 86 return handleRecordStatus(cmd); 87 } 88 return false; 89 } 90 handleRecordStatus(HdmiCecMessage cmd)91 private boolean handleRecordStatus(HdmiCecMessage cmd) { 92 // Only handle message coming from original recorder. 93 if (cmd.getSource() != mRecorderAddress) { 94 return false; 95 } 96 97 int recordStatus = cmd.getParams()[0]; 98 tv().announceOneTouchRecordResult(mRecorderAddress, recordStatus); 99 Slog.i(TAG, "Got record status:" + recordStatus + " from " + cmd.getSource()); 100 101 // If recording started successfully, change state and keep this action until <Record Off> 102 // received. Otherwise, finish action. 103 switch (recordStatus) { 104 case ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE: 105 case ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE: 106 case ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE: 107 case ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT: 108 mState = STATE_RECORDING_IN_PROGRESS; 109 mActionTimer.clearTimerMessage(); 110 break; 111 default: 112 finish(); 113 break; 114 } 115 return true; 116 } 117 118 @Override handleTimerEvent(int state)119 void handleTimerEvent(int state) { 120 if (mState != state) { 121 Slog.w(TAG, "Timeout in invalid state:[Expected:" + mState + ", Actual:" + state + "]"); 122 return; 123 } 124 125 tv().announceOneTouchRecordResult(mRecorderAddress, 126 ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION); 127 finish(); 128 } 129 getRecorderAddress()130 int getRecorderAddress() { 131 return mRecorderAddress; 132 } 133 } 134