13dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang/* 23dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang * Copyright (C) 2014 The Android Open Source Project 33dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang * 43dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang * Licensed under the Apache License, Version 2.0 (the "License"); 53dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang * you may not use this file except in compliance with the License. 63dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang * You may obtain a copy of the License at 73dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang * 83dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang * http://www.apache.org/licenses/LICENSE-2.0 93dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang * 103dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang * Unless required by applicable law or agreed to in writing, software 113dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang * distributed under the License is distributed on an "AS IS" BASIS, 123dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang * See the License for the specific language governing permissions and 143dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang * limitations under the License. 153dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang */ 163dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang 173dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jangpackage com.android.server.hdmi; 183dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang 1912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION; 2012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE; 2112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE; 2212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE; 2312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT; 24b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 25b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangimport android.util.Slog; 26b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 27b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangimport com.android.server.hdmi.HdmiControlService.SendMessageCallback; 28a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 293dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang/** 3012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang * Feature action that performs one touch record. 313dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang */ 32b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jangpublic class OneTouchRecordAction extends HdmiCecFeatureAction { 33b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang private static final String TAG = "OneTouchRecordAction"; 34b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 3512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang // Timer out for waiting <Record Status> 120s 3612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private static final int RECORD_STATUS_TIMEOUT_MS = 120000; 37b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 38b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang // State that waits for <Record Status> once sending <Record On> 39b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang private static final int STATE_WAITING_FOR_RECORD_STATUS = 1; 40b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang // State that describes recording in progress. 41b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang private static final int STATE_RECORDING_IN_PROGRESS = 2; 42b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 433dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang private final int mRecorderAddress; 44b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang private final byte[] mRecordSource; 453dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang 46b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang OneTouchRecordAction(HdmiCecLocalDevice source, int recorderAddress, byte[] recordSource) { 473dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang super(source); 483dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang mRecorderAddress = recorderAddress; 49b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang mRecordSource = recordSource; 503dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang } 513dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang 523dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang @Override 533dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang boolean start() { 54b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang sendRecordOn(); 55b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return true; 563dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang } 573dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang 58b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang private void sendRecordOn() { 59b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang sendCommand(HdmiCecMessageBuilder.buildRecordOn(getSourceAddress(), mRecorderAddress, 60b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang mRecordSource), 61b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang new SendMessageCallback() { 62b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 63b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void onSendCompleted(int error) { 64b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang // if failed to send <Record On>, display error message and finish action. 65b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (error != Constants.SEND_RESULT_SUCCESS) { 6612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang tv().announceOneTouchRecordResult( 67326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecorderAddress, 6812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION); 69b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang finish(); 70b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 71b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 72b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 73b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 745352081c662299b618335bf3024058fa04ef2dfdJungshik Jang mState = STATE_WAITING_FOR_RECORD_STATUS; 755352081c662299b618335bf3024058fa04ef2dfdJungshik Jang addTimer(mState, RECORD_STATUS_TIMEOUT_MS); 76a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 77a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 783dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang @Override 793dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang boolean processCommand(HdmiCecMessage cmd) { 805352081c662299b618335bf3024058fa04ef2dfdJungshik Jang if (mState != STATE_WAITING_FOR_RECORD_STATUS || mRecorderAddress != cmd.getSource()) { 81b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return false; 82b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 83b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 84b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang switch (cmd.getOpcode()) { 85b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang case Constants.MESSAGE_RECORD_STATUS: 86b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return handleRecordStatus(cmd); 87b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 883dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang return false; 893dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang } 903dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang 91b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang private boolean handleRecordStatus(HdmiCecMessage cmd) { 92b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang // Only handle message coming from original recorder. 93b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (cmd.getSource() != mRecorderAddress) { 94b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return false; 95b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 96b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 97b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang int recordStatus = cmd.getParams()[0]; 98326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang tv().announceOneTouchRecordResult(mRecorderAddress, recordStatus); 99b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.i(TAG, "Got record status:" + recordStatus + " from " + cmd.getSource()); 100b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 101b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang // If recording started successfully, change state and keep this action until <Record Off> 102b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang // received. Otherwise, finish action. 10312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang switch (recordStatus) { 10412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang case ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE: 10512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang case ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE: 10612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang case ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE: 10712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang case ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT: 108b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang mState = STATE_RECORDING_IN_PROGRESS; 109b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang mActionTimer.clearTimerMessage(); 110b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang break; 111b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang default: 112b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang finish(); 113b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang break; 114b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 115b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return true; 116b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 117b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1183dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang @Override 1193dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang void handleTimerEvent(int state) { 120b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (mState != state) { 121b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "Timeout in invalid state:[Expected:" + mState + ", Actual:" + state + "]"); 122b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 123b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 124b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 125326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang tv().announceOneTouchRecordResult(mRecorderAddress, 126326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION); 127b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang finish(); 1283dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang } 1293dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang 1303dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang int getRecorderAddress() { 1313dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang return mRecorderAddress; 1323dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang } 1333dcdd71e203f7751155ec83468e0f8092e8ea80bJungshik Jang} 134