Skip to content

Commit

Permalink
Synchronize thread-unsafe code
Browse files Browse the repository at this point in the history
  • Loading branch information
JeroenWeener committed Apr 12, 2023
1 parent 4ce0b49 commit b0113ba
Showing 1 changed file with 90 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ interface OnPathReadyListener {

private Uri pendingCameraMediaUri;
private @Nullable PendingCallState pendingCallState;
private final Object pendingCallStateLock = new Object();

public ImagePickerDelegate(
final Activity activity,
Expand Down Expand Up @@ -230,19 +231,25 @@ void setCameraDevice(CameraDevice device) {

// Save the state of the image picker so it can be retrieved with `retrieveLostImage`.
void saveStateBeforeResult() {
if (pendingCallState == null) {
return;
ImageSelectionOptions localImageOptions;
synchronized (pendingCallStateLock) {
if (pendingCallState == null) {
return;
}
localImageOptions = pendingCallState.imageOptions;
}

cache.saveType(
pendingCallState.imageOptions != null
localImageOptions != null
? ImagePickerCache.CacheType.IMAGE
: ImagePickerCache.CacheType.VIDEO);
if (pendingCallState.imageOptions != null) {
cache.saveDimensionWithOutputOptions(pendingCallState.imageOptions);
if (localImageOptions != null) {
cache.saveDimensionWithOutputOptions(localImageOptions);
}
if (pendingCameraMediaUri != null) {
cache.savePendingCameraMediaUriPath(pendingCameraMediaUri);

final Uri localPendingCameraMediaUri = pendingCameraMediaUri;
if (localPendingCameraMediaUri != null) {
cache.savePendingCameraMediaUriPath(localPendingCameraMediaUri);
}
}

Expand Down Expand Up @@ -329,10 +336,17 @@ public void takeVideoWithCamera(

private void launchTakeVideoWithCameraIntent() {
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
if (pendingCallState != null
&& pendingCallState.videoOptions != null
&& pendingCallState.videoOptions.getMaxDurationSeconds() != null) {
int maxSeconds = pendingCallState.videoOptions.getMaxDurationSeconds().intValue();

VideoSelectionOptions localVideoOptions = null;
synchronized (pendingCallStateLock) {
if (pendingCallState != null) {
localVideoOptions = pendingCallState.videoOptions;
}
}

if (localVideoOptions != null
&& localVideoOptions.getMaxDurationSeconds() != null) {
int maxSeconds = localVideoOptions.getMaxDurationSeconds().intValue();
intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, maxSeconds);
}
if (cameraDevice == CameraDevice.FRONT) {
Expand Down Expand Up @@ -614,9 +628,11 @@ private void handleChooseVideoResult(int resultCode, Intent data) {

private void handleCaptureImageResult(int resultCode) {
if (resultCode == Activity.RESULT_OK) {
final Uri localPendingCameraMediaUri = pendingCameraMediaUri;

fileUriResolver.getFullImagePath(
pendingCameraMediaUri != null
? pendingCameraMediaUri
localPendingCameraMediaUri != null
? localPendingCameraMediaUri
: Uri.parse(cache.retrievePendingCameraMediaUriPath()),
new OnPathReadyListener() {
@Override
Expand All @@ -633,9 +649,10 @@ public void onPathReady(String path) {

private void handleCaptureVideoResult(int resultCode) {
if (resultCode == Activity.RESULT_OK) {
final Uri localPendingCameraMediaUrl = pendingCameraMediaUri;
fileUriResolver.getFullImagePath(
pendingCameraMediaUri != null
? pendingCameraMediaUri
localPendingCameraMediaUrl != null
? localPendingCameraMediaUrl
: Uri.parse(cache.retrievePendingCameraMediaUriPath()),
new OnPathReadyListener() {
@Override
Expand All @@ -652,10 +669,17 @@ public void onPathReady(String path) {

private void handleMultiImageResult(
ArrayList<String> paths, boolean shouldDeleteOriginalIfScaled) {
if (pendingCallState != null && pendingCallState.imageOptions != null) {
ImageSelectionOptions localImageOptions = null;
synchronized (pendingCallStateLock) {
if (pendingCallState != null) {
localImageOptions = pendingCallState.imageOptions;
}
}

if (localImageOptions != null) {
ArrayList<String> finalPath = new ArrayList<>();
for (int i = 0; i < paths.size(); i++) {
String finalImagePath = getResizedImagePath(paths.get(i), pendingCallState.imageOptions);
String finalImagePath = getResizedImagePath(paths.get(i), localImageOptions);

//delete original file if scaled
if (finalImagePath != null
Expand All @@ -672,8 +696,15 @@ private void handleMultiImageResult(
}

private void handleImageResult(String path, boolean shouldDeleteOriginalIfScaled) {
if (pendingCallState != null && pendingCallState.imageOptions != null) {
String finalImagePath = getResizedImagePath(path, pendingCallState.imageOptions);
ImageSelectionOptions localImageOptions = null;
synchronized (pendingCallStateLock) {
if (pendingCallState != null) {
localImageOptions = pendingCallState.imageOptions;
}
}

if (localImageOptions != null) {
String finalImagePath = getResizedImagePath(path, localImageOptions);
//delete original file if scaled
if (finalImagePath != null && !finalImagePath.equals(path) && shouldDeleteOriginalIfScaled) {
new File(path).delete();
Expand All @@ -696,16 +727,17 @@ private void handleVideoResult(String path) {
finishWithSuccess(path);
}

private synchronized boolean setPendingOptionsAndResult(
private boolean setPendingOptionsAndResult(
@Nullable ImageSelectionOptions imageOptions,
@Nullable VideoSelectionOptions videoOptions,
@NonNull Messages.Result<List<String>> result) {
if (pendingCallState != null) {
return false;
synchronized (pendingCallStateLock) {
if (pendingCallState != null) {
return false;
}
pendingCallState = new PendingCallState(imageOptions, videoOptions, result);
}

pendingCallState = new PendingCallState(imageOptions, videoOptions, result);

// Clean up cache if a new image picker is launched.
cache.clear();

Expand All @@ -721,37 +753,59 @@ private void finishWithSuccess(@Nullable String imagePath) {
if (imagePath != null) {
pathList.add(imagePath);
}
if (pendingCallState == null) {

Messages.Result<List<String>> localResult = null;
synchronized (pendingCallStateLock) {
if (pendingCallState != null) {
localResult = pendingCallState.result;
}
pendingCallState = null;
}

if (localResult == null) {
// Only save data for later retrieval if something was actually selected.
if (!pathList.isEmpty()) {
cache.saveResult(pathList, null, null);
}
return;
} else {
localResult.success(pathList);
}
pendingCallState.result.success(pathList);
pendingCallState = null;
}

private void finishWithListSuccess(ArrayList<String> imagePaths) {
if (pendingCallState == null) {
Messages.Result<List<String>> localResult = null;
synchronized (pendingCallStateLock) {
if (pendingCallState != null) {
localResult = pendingCallState.result;
}
pendingCallState = null;
}

if (localResult == null) {
cache.saveResult(imagePaths, null, null);
return;
} else {
localResult.success(imagePaths);
}
pendingCallState.result.success(imagePaths);
pendingCallState = null;
}

private void finishWithAlreadyActiveError(Messages.Result<List<String>> result) {
result.error(new FlutterError("already_active", "Image picker is already active", null));
}

private void finishWithError(String errorCode, String errorMessage) {
if (pendingCallState == null) {
Messages.Result<List<String>> localResult = null;
synchronized (pendingCallStateLock) {
if (pendingCallState != null) {
localResult = pendingCallState.result;
}
pendingCallState = null;
}

if (localResult == null) {
cache.saveResult(null, errorCode, errorMessage);
return;
} else {
localResult.error(new FlutterError(errorCode, errorMessage, null));
}
pendingCallState.result.error(new FlutterError(errorCode, errorMessage, null));
pendingCallState = null;
}

private void useFrontCamera(Intent intent) {
Expand Down

0 comments on commit b0113ba

Please sign in to comment.