Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
475f4ab
Replicated existing code and migrated references to new embedding, ad…
matthew-carroll Sep 24, 2019
8cde03b
Introduced CameraPreviewDisplay and CameraImageStream to remove Flutt…
matthew-carroll Sep 24, 2019
2081f42
Introduced a CameraEventListener to completely decouple Camera from E…
matthew-carroll Sep 24, 2019
b78bfcb
Removed all references of Result from Camera by introducing a combina…
matthew-carroll Sep 24, 2019
b45ae68
Refactored Camera such that getFlutterTexture() no longer needs to ex…
matthew-carroll Sep 24, 2019
6780abf
Moved ResolutionPreset to standalone class and made Camera package pr…
matthew-carroll Sep 24, 2019
8b93f68
Re-organized Camera code order to clearly separate preview images, fr…
matthew-carroll Sep 24, 2019
c85fcc2
Removed Activity reference from Camera.
matthew-carroll Sep 24, 2019
e04653b
Refactored CameraPermissions to eliminate Activity, ActivityCompat, C…
matthew-carroll Sep 24, 2019
60c1d20
Refactored CameraPermissions into an Interface and AndroidCameraPermi…
matthew-carroll Sep 25, 2019
13e4303
Separated the CameraPlugin class from the concept of the comms Camera…
matthew-carroll Sep 25, 2019
d5da9ce
Introduced CameraDetails data structure & wrote unit tests for Camera…
matthew-carroll Sep 25, 2019
436d9ca
Added unit tests for CameraPluginProtocol and reached 100% coverage f…
matthew-carroll Sep 25, 2019
3dcc0ab
Moved CameraPreviewDisplay and CameraImageStream implementations into…
matthew-carroll Sep 26, 2019
02ab397
Extracted per-camera channel construction out into CameraPlugin for t…
matthew-carroll Sep 26, 2019
e5408d9
Refactored so that CameraSystem and AndroidCameraSystem could be redu…
matthew-carroll Sep 26, 2019
6ea1b4f
Deleted CameraUtils, and continued to cleanup relationships.
matthew-carroll Sep 26, 2019
4669cb4
Added tests for CameraSystem - at 93% line coverage.
matthew-carroll Sep 26, 2019
410d0ac
Added tests to ensure that CameraPlugin does nothing without an Activ…
matthew-carroll Sep 26, 2019
0bd6522
Added tests for ChannelCameraEventHandler - now at CameraSystem (93%)…
matthew-carroll Sep 26, 2019
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/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,9 @@ android {
dependencies {
implementation 'androidx.annotation:annotation:1.0.0'
implementation 'androidx.core:core:1.0.0'

testImplementation 'junit:junit:4.12'
testImplementation 'androidx.test:core:1.2.0' // for robolectric
testImplementation 'org.mockito:mockito-core:1.10.19'
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package dev.flutter.plugins.camera;

import android.content.Context;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraManager;

import androidx.annotation.NonNull;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.view.TextureRegistry;

/* package */ class AndroidCameraFactory implements CameraFactory {
@NonNull
private final FlutterPlugin.FlutterPluginBinding pluginBinding;
@NonNull
private final ActivityPluginBinding activityBinding;

/* package */ AndroidCameraFactory(
@NonNull FlutterPlugin.FlutterPluginBinding pluginBinding,
@NonNull ActivityPluginBinding activityBinding
) {
this.pluginBinding = pluginBinding;
this.activityBinding = activityBinding;
}

@NonNull
@Override
public Camera createCamera(
@NonNull String cameraName,
@NonNull String resolutionPreset,
boolean enableAudio
) throws CameraAccessException {
TextureRegistry.SurfaceTextureEntry textureEntry = pluginBinding
.getFlutterEngine()
.getRenderer()
.createSurfaceTexture();

return new Camera(
activityBinding.getActivity(),
(CameraManager) activityBinding.getActivity().getSystemService(Context.CAMERA_SERVICE),
textureEntry,
cameraName,
resolutionPreset,
enableAudio
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package dev.flutter.plugins.camera;

import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;

import androidx.annotation.NonNull;

import java.util.ArrayList;
import java.util.List;

/* package */ class AndroidCameraHardware implements CameraHardware {
@NonNull
private final CameraManager cameraManager;

/* package */ AndroidCameraHardware(@NonNull CameraManager cameraManager) {
this.cameraManager = cameraManager;
}

@NonNull
@Override
public List<CameraDetails> getAvailableCameras() throws CameraAccessException {
String[] cameraNames = cameraManager.getCameraIdList();
List<CameraDetails> cameras = new ArrayList<>();

for (String cameraName : cameraNames) {
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraName);

int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);

int lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING);
String lensFacingName = null;
switch (lensFacing) {
case CameraMetadata.LENS_FACING_FRONT:
lensFacingName = "front";
break;
case CameraMetadata.LENS_FACING_BACK:
lensFacingName = "back";
break;
case CameraMetadata.LENS_FACING_EXTERNAL:
lensFacingName = "external";
break;
}

cameras.add(new CameraDetails(
cameraName,
sensorOrientation,
lensFacingName
));
}
return cameras;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package dev.flutter.plugins.camera;

import android.Manifest;
import android.content.pm.PackageManager;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.PluginRegistry;

/* package */ class AndroidCameraPermissions implements CameraPermissions {
private static final int CAMERA_REQUEST_ID = 9796;

@NonNull
private final ActivityPluginBinding activityBinding;
private boolean ongoing = false;

/* package */ AndroidCameraPermissions(@NonNull ActivityPluginBinding activityBinding) {
this.activityBinding = activityBinding;
}

@Override
public boolean hasCameraPermission() {
return ContextCompat.checkSelfPermission(activityBinding.getActivity(), Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED;
}

@Override
public boolean hasAudioPermission() {
return ContextCompat.checkSelfPermission(activityBinding.getActivity(), Manifest.permission.RECORD_AUDIO)
== PackageManager.PERMISSION_GRANTED;
}

public void requestPermissions(boolean enableAudio, CameraPermissions.ResultCallback callback) {
if (ongoing) {
callback.onResult("cameraPermission", "Camera permission request ongoing");
}
if (!hasCameraPermission() || (enableAudio && !hasAudioPermission())) {
ongoing = true;

activityBinding.addRequestPermissionsResultListener(
new CameraRequestPermissionsListener(callback)
);

ActivityCompat.requestPermissions(
activityBinding.getActivity(),
enableAudio
? new String[] {Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO}
: new String[] {Manifest.permission.CAMERA},
CAMERA_REQUEST_ID);
} else {
// Permissions already exist. Call the callback with success.
callback.onSuccess();
}
}

@Override
public void addRequestPermissionsResultListener(@NonNull PluginRegistry.RequestPermissionsResultListener listener) {
activityBinding.addRequestPermissionsResultListener(listener);
}

private static class CameraRequestPermissionsListener implements PluginRegistry.RequestPermissionsResultListener {
final CameraPermissions.ResultCallback callback;

private CameraRequestPermissionsListener(CameraPermissions.ResultCallback callback) {
this.callback = callback;
}

@Override
public boolean onRequestPermissionsResult(int id, String[] permissions, int[] grantResults) {
if (id == CAMERA_REQUEST_ID) {
// TODO(mattcarroll): fix bug where granting 1st permission and denying 2nd crashes
// due to submitting a reply twice.
if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
callback.onResult("cameraPermission", "MediaRecorderCamera permission not granted");
} else if (grantResults.length > 1
&& grantResults[1] != PackageManager.PERMISSION_GRANTED) {
callback.onResult("cameraPermission", "MediaRecorderAudio permission not granted");
} else {
callback.onSuccess();
}
return true;
}
return false;
}
}
}
Loading