Skip to content

Commit 9177d64

Browse files
committed
io.appium.settings: recording: Update to use latest Storage Access Framework
* and also clamp width/height to max 1080x1920 since avc codec crash on width/height values larger than Full HD i.e 1080x1920 * Fixup misc. handler creation issue Signed-off-by: sirmordred <[email protected]>
1 parent dc8dc27 commit 9177d64

File tree

4 files changed

+67
-22
lines changed

4 files changed

+67
-22
lines changed

app/src/main/java/io/appium/settings/RecorderConstant.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818

1919
public class RecorderConstant {
2020
public static final int REQUEST_CODE_SCREEN_CAPTURE = 123;
21-
private static final String PACKAGE_NAME = BuildConfig.APPLICATION_ID;
22-
public static final String ACTION_RECORDING_START = PACKAGE_NAME + ".recording.ACTION_START";
23-
public static final String ACTION_RECORDING_STOP = PACKAGE_NAME + ".recording.ACTION_STOP";
21+
public static final String ACTION_RECORDING_BASE = BuildConfig.APPLICATION_ID + ".recording";
22+
public static final String ACTION_RECORDING_START = ACTION_RECORDING_BASE + ".ACTION_START";
23+
public static final String ACTION_RECORDING_STOP = ACTION_RECORDING_BASE + ".ACTION_STOP";
2424
public static final String ACTION_RECORDING_RESULT_CODE = "result_code";
2525
public static final String ACTION_RECORDING_FILENAME = "recording_filename";
2626
public static final String ACTION_RECORDING_ROTATION = "recording_rotation";

app/src/main/java/io/appium/settings/RecorderService.java

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,22 @@
1717
package io.appium.settings;
1818

1919
import android.app.Service;
20+
import android.content.ContentResolver;
21+
import android.content.ContentValues;
2022
import android.content.Context;
2123
import android.content.Intent;
2224
import android.media.projection.MediaProjection;
2325
import android.media.projection.MediaProjectionManager;
26+
import android.net.Uri;
2427
import android.os.Build;
2528
import android.os.IBinder;
29+
import android.provider.MediaStore;
2630
import android.util.DisplayMetrics;
2731
import android.util.Log;
2832

33+
import java.io.FileDescriptor;
34+
import java.io.FileNotFoundException;
35+
2936
import androidx.annotation.Nullable;
3037
import androidx.annotation.RequiresApi;
3138
import io.appium.settings.helpers.NotificationHelpers;
@@ -60,7 +67,7 @@ public IBinder onBind(final Intent intent) {
6067
return null;
6168
}
6269

63-
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
70+
@RequiresApi(api = Build.VERSION_CODES.Q)
6471
@Override
6572
public int onStartCommand(final Intent intent, final int flags, final int startId) {
6673
Log.v(TAG, "onStartCommand:intent=" + intent);
@@ -95,7 +102,7 @@ public int onStartCommand(final Intent intent, final int flags, final int startI
95102
/**
96103
* start screen recording
97104
*/
98-
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
105+
@RequiresApi(api = Build.VERSION_CODES.Q)
99106
private void startScreenRecord(MediaProjectionManager mediaProjectionManager,
100107
final Intent intent) {
101108
if (recorderThread != null) {
@@ -117,9 +124,16 @@ private void startScreenRecord(MediaProjectionManager mediaProjectionManager,
117124
return;
118125
}
119126

120-
String outputFilePath = intent.getStringExtra(ACTION_RECORDING_FILENAME);
121-
if (outputFilePath == null) {
122-
Log.i(TAG, "outputFilePath is null");
127+
String outputFileName = intent.getStringExtra(ACTION_RECORDING_FILENAME);
128+
if (outputFileName == null) {
129+
Log.i(TAG, "outputFileName is null");
130+
return;
131+
}
132+
133+
FileDescriptor outputVideoFd =
134+
createOutputVideoDescriptor(getApplicationContext(), outputFileName);
135+
if (outputVideoFd == null) {
136+
Log.i(TAG, "outputVideoFd is null");
123137
return;
124138
}
125139

@@ -153,7 +167,7 @@ private void startScreenRecord(MediaProjectionManager mediaProjectionManager,
153167
metrics.widthPixels, metrics.heightPixels, rawWidth, rawHeight));
154168
}
155169

156-
recorderThread = new RecorderThread(projection, outputFilePath,
170+
recorderThread = new RecorderThread(projection, outputVideoFd,
157171
rawWidth, rawHeight, recordingRotation);
158172
recorderThread.startRecording();
159173
}
@@ -174,4 +188,21 @@ private void showNotification() {
174188
startForeground(NotificationHelpers.APPIUM_NOTIFICATION_IDENTIFIER,
175189
NotificationHelpers.getNotification(this));
176190
}
191+
192+
@RequiresApi(api = Build.VERSION_CODES.Q)
193+
public FileDescriptor createOutputVideoDescriptor(Context context, String videoFileName) {
194+
ContentValues values = new ContentValues();
195+
values.put(MediaStore.Video.Media.TITLE, videoFileName);
196+
values.put(MediaStore.Video.Media.DISPLAY_NAME, videoFileName);
197+
values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
198+
ContentResolver resolver = context.getContentResolver();
199+
Uri collection = MediaStore.Downloads.EXTERNAL_CONTENT_URI;
200+
Uri videoOutputUri = resolver.insert(collection, values);
201+
try {
202+
return resolver.openFileDescriptor(videoOutputUri, "rw").getFileDescriptor();
203+
} catch (FileNotFoundException e) {
204+
e.printStackTrace();
205+
}
206+
return null;
207+
}
177208
}

app/src/main/java/io/appium/settings/RecorderThread.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@
2929
import android.media.projection.MediaProjection;
3030
import android.os.Build;
3131
import android.os.Handler;
32+
import android.os.Looper;
3233
import android.util.DisplayMetrics;
3334
import android.util.Log;
3435
import android.view.Surface;
3536

37+
import java.io.FileDescriptor;
3638
import java.io.IOException;
3739
import java.nio.ByteBuffer;
3840

@@ -45,7 +47,7 @@ public class RecorderThread implements Runnable {
4547
private static final String TAG = "RecorderThread";
4648

4749
private final MediaProjection mediaProjection;
48-
private final String outputFilePath;
50+
private final FileDescriptor outputFileFd;
4951
private final int videoWidth;
5052
private final int videoHeight;
5153
private final int recordingRotation;
@@ -79,10 +81,10 @@ public void onStopped() {
7981
}
8082
};
8183

82-
public RecorderThread(MediaProjection mediaProjection, String outputFilePath,
84+
public RecorderThread(MediaProjection mediaProjection, FileDescriptor outputFileFd,
8385
int videoWidth, int videoHeight, int recordingRotation) {
8486
this.mediaProjection = mediaProjection;
85-
this.outputFilePath = outputFilePath;
87+
this.outputFileFd = outputFileFd;
8688
this.videoWidth = videoWidth;
8789
this.videoHeight = videoHeight;
8890
this.recordingRotation = recordingRotation;
@@ -345,6 +347,15 @@ public void run() {
345347
videoEncoderCapabilities.getSupportedWidths().clamp(this.videoWidth);
346348
int finalVideoHeight =
347349
videoEncoderCapabilities.getSupportedHeights().clamp(this.videoHeight);
350+
351+
if (finalVideoHeight > 1920) {
352+
finalVideoHeight = 1920;
353+
}
354+
355+
if (finalVideoWidth > 1080) {
356+
finalVideoWidth = 1080;
357+
}
358+
348359
int videoBitrate = calcBitRate(videoWidth, videoHeight);
349360

350361
MediaFormat videoEncoderFormat = initVideoEncoderFormat(videoMime,
@@ -355,7 +366,7 @@ public void run() {
355366
surface = videoEncoder.createInputSurface();
356367
videoEncoder.start();
357368

358-
Handler handler = new Handler();
369+
Handler handler = new Handler(Looper.getMainLooper());
359370
virtualDisplay = initVirtualDisplay(this.mediaProjection, surface, handler,
360371
finalVideoWidth, finalVideoHeight);
361372

@@ -365,7 +376,7 @@ public void run() {
365376

366377
audioRecord = initAudioRecord(this.mediaProjection, sampleRate);
367378

368-
muxer = new MediaMuxer(this.outputFilePath,
379+
muxer = new MediaMuxer(this.outputFileFd,
369380
MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
370381

371382
// set output file orientation info

app/src/main/java/io/appium/settings/Settings.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import android.view.Surface;
3333
import android.view.WindowManager;
3434

35-
import java.io.File;
3635
import java.text.SimpleDateFormat;
3736
import java.util.Arrays;
3837
import java.util.Date;
@@ -53,6 +52,7 @@
5352
import io.appium.settings.receivers.UnpairBluetoothDevicesReceiver;
5453
import io.appium.settings.receivers.WiFiConnectionSettingReceiver;
5554

55+
import static io.appium.settings.RecorderConstant.ACTION_RECORDING_BASE;
5656
import static io.appium.settings.RecorderConstant.ACTION_RECORDING_FILENAME;
5757
import static io.appium.settings.RecorderConstant.ACTION_RECORDING_RESULT_CODE;
5858
import static io.appium.settings.RecorderConstant.ACTION_RECORDING_ROTATION;
@@ -63,7 +63,7 @@
6363
public class Settings extends Activity {
6464
private static final String TAG = "APPIUM SETTINGS";
6565

66-
private String recordingOutputPath = "";
66+
private String recordingFilename = RecorderConstant.DEFAULT_RECORDING_FILENAME;
6767
private int recordingRotation = -1;
6868

6969
@Override
@@ -110,6 +110,12 @@ private void handleRecording(Intent intent) {
110110
return;
111111
}
112112

113+
if (!recordingAction.startsWith(ACTION_RECORDING_BASE)) {
114+
Log.i(TAG, "handleRecording: Different intent");
115+
finishActivity();
116+
return;
117+
}
118+
113119
if (isLowerThanQ()) {
114120
Log.e(TAG, "handleRecording: Current Android OS Version is lower than Q");
115121
finishActivity();
@@ -122,7 +128,7 @@ private void handleRecording(Intent intent) {
122128
return;
123129
}
124130

125-
String recordingFilename = intent.getStringExtra(ACTION_RECORDING_FILENAME);
131+
recordingFilename = intent.getStringExtra(ACTION_RECORDING_FILENAME);
126132

127133
if (isValidFileName(recordingFilename)) {
128134
String timeStamp = new SimpleDateFormat(
@@ -133,9 +139,6 @@ private void handleRecording(Intent intent) {
133139
" using default one: " + recordingFilename);
134140
}
135141

136-
recordingOutputPath = getExternalFilesDir(null).getAbsolutePath()
137-
+ File.separator + recordingFilename;
138-
139142
Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
140143

141144
if (display != null) {
@@ -184,7 +187,7 @@ private void handleRecording(Intent intent) {
184187

185188
finishActivity();
186189
} else {
187-
Log.e(TAG, "handleRecording: Unknown recording intent.action");
190+
Log.e(TAG, "handleRecording: Unknown recording intent.action:" + recordingAction);
188191
finishActivity();
189192
}
190193
}
@@ -265,7 +268,7 @@ protected void onActivityResult(final int requestCode, final int resultCode, fin
265268
final Intent intent = new Intent(this, RecorderService.class);
266269
intent.setAction(ACTION_RECORDING_START);
267270
intent.putExtra(ACTION_RECORDING_RESULT_CODE, resultCode);
268-
intent.putExtra(ACTION_RECORDING_FILENAME, recordingOutputPath);
271+
intent.putExtra(ACTION_RECORDING_FILENAME, recordingFilename);
269272
intent.putExtra(ACTION_RECORDING_ROTATION, recordingRotation);
270273
intent.putExtras(data);
271274

0 commit comments

Comments
 (0)