diff --git a/src/chrome/ScreenCaptureButtons.tsx b/src/chrome/ScreenCaptureButtons.tsx index d16cb516f..bd6495a78 100644 --- a/src/chrome/ScreenCaptureButtons.tsx +++ b/src/chrome/ScreenCaptureButtons.tsx @@ -102,11 +102,7 @@ class ScreenCaptureButtons extends Component { return; } const videoPath = path.join(CAPTURE_LOCATION, getFileName('mp4')); - await selectedDevice.startScreenCapture(videoPath); - - this.setState({ - recording: true, - }); + return selectedDevice.startScreenCapture(videoPath); }; stopRecording = async () => { @@ -114,18 +110,28 @@ class ScreenCaptureButtons extends Component { if (!selectedDevice) { return; } - const path = await selectedDevice.stopScreenCapture(); - this.setState({ - recording: false, + const path = await selectedDevice.stopScreenCapture().catch(e => { + console.error(e); }); - openFile(path); + path ? openFile(path) : 0; }; onRecordingClicked = () => { if (this.state.recording) { this.stopRecording(); + this.setState({ + recording: false, + }); } else { - this.startRecording(); + this.setState({ + recording: true, + }); + this.startRecording().catch(e => { + this.setState({ + recording: false, + }); + console.error(e); + }); } }; diff --git a/src/chrome/VideoRecordingButton.tsx b/src/chrome/VideoRecordingButton.tsx index 33d54241d..20d3efcea 100644 --- a/src/chrome/VideoRecordingButton.tsx +++ b/src/chrome/VideoRecordingButton.tsx @@ -46,10 +46,15 @@ export default class VideoRecordingButton extends Component { .toISOString() .replace(/:/g, '')}.mp4`; const videoPath = path.join(flipperDirectory, fileName); - await selectedDevice.startScreenCapture(videoPath); this.setState({ recording: true, }); + selectedDevice.startScreenCapture(videoPath).catch(e => { + console.error('Screen recording failed:', e); + this.setState({ + recording: false, + }); + }); }; stopRecording = async () => { diff --git a/src/devices/AndroidDevice.tsx b/src/devices/AndroidDevice.tsx index 693dfb8d8..8980aa10f 100644 --- a/src/devices/AndroidDevice.tsx +++ b/src/devices/AndroidDevice.tsx @@ -132,6 +132,23 @@ export default class AndroidDevice extends BaseDevice { } } + private async isValidFile(filePath: string): Promise { + const fileSize = await this.adb + .shell(this.serial, `du "${filePath}"`) + .then(adb.util.readAll) + .then((output: Buffer) => + output + .toString() + .trim() + .split('\t'), + ) + .then(x => Number(x[0])); + + // 4 is what an empty file (touch file) already takes up, so it's + // definitely not a valid video file. + return fileSize > 4; + } + async startScreenCapture(destination: string) { await this.executeShell( `mkdir -p "${DEVICE_RECORDING_DIR}" && echo -n > "${DEVICE_RECORDING_DIR}/.nomedia"`, @@ -140,17 +157,28 @@ export default class AndroidDevice extends BaseDevice { this.recordingProcess = this.adb .shell(this.serial, `screenrecord --bugreport "${recordingLocation}"`) .then(adb.util.readAll) + .then(async output => { + const isValid = await this.isValidFile(recordingLocation); + if (!isValid) { + const outputMessage = output.toString().trim(); + throw new Error( + 'Recording was not properly started: \n' + outputMessage, + ); + } + }) .then( _ => - new Promise((resolve, reject) => + new Promise((resolve, reject) => { this.adb.pull(this.serial, recordingLocation).then(stream => { stream.on('end', resolve); stream.on('error', reject); stream.pipe(createWriteStream(destination)); - }), - ), + }); + }), ) .then(_ => destination); + + return this.recordingProcess.then(_ => {}); } async stopScreenCapture(): Promise { diff --git a/src/devices/BaseDevice.tsx b/src/devices/BaseDevice.tsx index deb6cf931..e1816e13b 100644 --- a/src/devices/BaseDevice.tsx +++ b/src/devices/BaseDevice.tsx @@ -166,7 +166,7 @@ export default class BaseDevice { return false; } - async startScreenCapture(_destination: string) { + async startScreenCapture(_destination: string): Promise { throw new Error('startScreenCapture not implemented on BaseDevice '); }