Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/camera/camera/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.6.6+1

* Fixes picture captures causing a crash on some Huawei devices.

## 0.6.6

* Adds auto focus support for Android and iOS implementations.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -464,17 +464,20 @@ public void onCaptureFailed(
return;
}
String reason;
boolean fatalFailure = false;
switch (failure.getReason()) {
case CaptureFailure.REASON_ERROR:
reason = "An error happened in the framework";
break;
case CaptureFailure.REASON_FLUSHED:
reason = "The capture has failed due to an abortCaptures() call";
fatalFailure = true;
break;
default:
reason = "Unknown reason";
}
pictureCaptureRequest.error("captureFailure", reason, null);
Log.w("Camera", "pictureCaptureCallback.onCaptureFailed(): " + reason);
if (fatalFailure) pictureCaptureRequest.error("captureFailure", reason, null);
}

private void processCapture(CaptureResult result) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

package io.flutter.plugins.camera;

import android.os.Handler;
import android.os.Looper;
import androidx.annotation.Nullable;
import io.flutter.plugin.common.MethodChannel;

Expand All @@ -19,17 +21,36 @@ enum State {
error,
}

private final Runnable timeoutCallback =
new Runnable() {
@Override
public void run() {
error("captureTimeout", "Picture capture request timed out", state.toString());
}
};

private final MethodChannel.Result result;
private final TimeoutHandler timeoutHandler;
private State state;

public PictureCaptureRequest(MethodChannel.Result result) {
this(result, new TimeoutHandler());
}

public PictureCaptureRequest(MethodChannel.Result result, TimeoutHandler timeoutHandler) {
this.result = result;
state = State.idle;
this.state = State.idle;
this.timeoutHandler = timeoutHandler;
}

public void setState(State state) {
if (isFinished()) throw new IllegalStateException("Request has already been finished");
this.state = state;
if (state != State.idle && state != State.finished && state != State.error) {
this.timeoutHandler.resetTimeout(timeoutCallback);
} else {
this.timeoutHandler.clearTimeout(timeoutCallback);
}
}

public State getState() {
Expand All @@ -42,14 +63,34 @@ public boolean isFinished() {

public void finish(String absolutePath) {
if (isFinished()) throw new IllegalStateException("Request has already been finished");
this.timeoutHandler.clearTimeout(timeoutCallback);
result.success(absolutePath);
state = State.finished;
}

public void error(
String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails) {
if (isFinished()) throw new IllegalStateException("Request has already been finished");
this.timeoutHandler.clearTimeout(timeoutCallback);
result.error(errorCode, errorMessage, errorDetails);
state = State.error;
}

static class TimeoutHandler {
private static final int REQUEST_TIMEOUT = 5000;
private final Handler handler;

TimeoutHandler() {
this.handler = new Handler(Looper.getMainLooper());
}

public void resetTimeout(Runnable runnable) {
clearTimeout(runnable);
handler.postDelayed(runnable, REQUEST_TIMEOUT);
}

public void clearTimeout(Runnable runnable) {
handler.removeCallbacks(runnable);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import io.flutter.plugin.common.MethodChannel;
Expand Down Expand Up @@ -38,6 +41,32 @@ public void setState_sets_state() {
"State is awaitingPreCapture", req.getState(), PictureCaptureRequest.State.capturing);
}

@Test
public void setState_resets_timeout() {
PictureCaptureRequest.TimeoutHandler mockTimeoutHandler =
mock(PictureCaptureRequest.TimeoutHandler.class);
PictureCaptureRequest req = new PictureCaptureRequest(null, mockTimeoutHandler);
req.setState(PictureCaptureRequest.State.focusing);
req.setState(PictureCaptureRequest.State.preCapture);
req.setState(PictureCaptureRequest.State.waitingPreCaptureReady);
req.setState(PictureCaptureRequest.State.capturing);
verify(mockTimeoutHandler, times(4)).resetTimeout(any());
verify(mockTimeoutHandler, never()).clearTimeout(any());
}

@Test
public void setState_clears_timeout() {
PictureCaptureRequest.TimeoutHandler mockTimeoutHandler =
mock(PictureCaptureRequest.TimeoutHandler.class);
PictureCaptureRequest req = new PictureCaptureRequest(null, mockTimeoutHandler);
req.setState(PictureCaptureRequest.State.idle);
req.setState(PictureCaptureRequest.State.finished);
req = new PictureCaptureRequest(null, mockTimeoutHandler);
req.setState(PictureCaptureRequest.State.error);
verify(mockTimeoutHandler, never()).resetTimeout(any());
verify(mockTimeoutHandler, times(3)).clearTimeout(any());
}

@Test
public void finish_sets_result_and_state() {
// Setup
Expand All @@ -50,6 +79,17 @@ public void finish_sets_result_and_state() {
assertEquals("State is finished", req.getState(), PictureCaptureRequest.State.finished);
}

@Test
public void finish_clears_timeout() {
PictureCaptureRequest.TimeoutHandler mockTimeoutHandler =
mock(PictureCaptureRequest.TimeoutHandler.class);
MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
PictureCaptureRequest req = new PictureCaptureRequest(mockResult, mockTimeoutHandler);
req.finish("/test/path");
verify(mockTimeoutHandler, never()).resetTimeout(any());
verify(mockTimeoutHandler).clearTimeout(any());
}

@Test
public void isFinished_is_true_When_state_is_finished_or_error() {
// Setup
Expand Down Expand Up @@ -90,6 +130,17 @@ public void error_sets_result_and_state() {
assertEquals("State is error", req.getState(), PictureCaptureRequest.State.error);
}

@Test
public void error_clears_timeout() {
PictureCaptureRequest.TimeoutHandler mockTimeoutHandler =
mock(PictureCaptureRequest.TimeoutHandler.class);
MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
PictureCaptureRequest req = new PictureCaptureRequest(mockResult, mockTimeoutHandler);
req.error("ERROR_CODE", "Error Message", null);
verify(mockTimeoutHandler, never()).resetTimeout(any());
verify(mockTimeoutHandler).clearTimeout(any());
}

@Test(expected = IllegalStateException.class)
public void error_throws_When_already_finished() {
// Setup
Expand Down
2 changes: 1 addition & 1 deletion packages/camera/camera/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: camera
description: A Flutter plugin for getting information about and controlling the
camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video,
and streaming image buffers to dart.
version: 0.6.6
version: 0.6.6+1
homepage: https://github.com/flutter/plugins/tree/master/packages/camera/camera

dependencies:
Expand Down