Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[camera_android_camerax] PreviewView experiment #8470

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,5 @@ dependencies {
testImplementation 'org.mockito:mockito-inline:5.0.0'
testImplementation 'androidx.test:core:1.4.0'
testImplementation 'org.robolectric:robolectric:4.10.3'
implementation "androidx.camera:camera-view:${camerax_version}"
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.view.TextureRegistry;
import androidx.camera.view.PreviewView;

import android.util.Log;

/** Platform implementation of the camera_plugin implemented with the CameraX library. */
public final class CameraAndroidCameraxPlugin implements FlutterPlugin, ActivityAware {
Expand All @@ -40,6 +43,8 @@ public final class CameraAndroidCameraxPlugin implements FlutterPlugin, Activity

@VisibleForTesting public @Nullable LiveDataHostApiImpl liveDataHostApiImpl;

public NativeViewFactory nativeViewFactory;

/**
* Initialize this within the {@code #configureFlutterEngine} of a Flutter activity or fragment.
*
Expand Down Expand Up @@ -83,7 +88,7 @@ public void setUp(
GeneratedCameraXLibrary.DeviceOrientationManagerHostApi.setup(
binaryMessenger, deviceOrientationManagerHostApiImpl);
GeneratedCameraXLibrary.PreviewHostApi.setup(
binaryMessenger, new PreviewHostApiImpl(binaryMessenger, instanceManager, textureRegistry));
binaryMessenger, new PreviewHostApiImpl(binaryMessenger, instanceManager, textureRegistry, nativeViewFactory));
imageCaptureHostApiImpl =
new ImageCaptureHostApiImpl(binaryMessenger, instanceManager, context);
GeneratedCameraXLibrary.ImageCaptureHostApi.setup(binaryMessenger, imageCaptureHostApiImpl);
Expand Down Expand Up @@ -143,6 +148,11 @@ public void setUp(
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
pluginBinding = flutterPluginBinding;
Log.e("CAMILLE", "hey");
nativeViewFactory = new NativeViewFactory();
flutterPluginBinding
.getPlatformViewRegistry()
.registerViewFactory("<camille-platform-view>", nativeViewFactory);
}

@Override
Expand All @@ -168,7 +178,7 @@ public void onAttachedToActivity(@NonNull ActivityPluginBinding activityPluginBi
// Set permissions registry reference.
systemServicesHostApiImpl.setPermissionsRegistry(
activityPluginBinding::addRequestPermissionsResultListener);
}
}

@Override
public void onDetachedFromActivityForConfigChanges() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.flutter.plugins.camerax;

import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.plugin.platform.PlatformView;
import java.util.Map;
import androidx.camera.view.PreviewView;
import androidx.annotation.Nullable;


class NativeView implements PlatformView {
@NonNull private final TextView textView;
@NonNull private final PreviewView previewView;

NativeView(@NonNull Context context, int id, @Nullable Map<String, Object> creationParams) {
textView = new TextView(context);
textView.setTextSize(72);
textView.setBackgroundColor(Color.rgb(255, 255, 255));
textView.setText("Rendered on a native Android view (id: " + id + ")");

previewView = new PreviewView(context);
}

@NonNull
@Override
public View getView() {
return previewView;
}

@Override
public void dispose() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.flutter.plugins.camerax;

import android.content.Context;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import io.flutter.plugin.common.StandardMessageCodec;
import io.flutter.plugin.platform.PlatformView;
import io.flutter.plugin.platform.PlatformViewFactory;
import java.util.Map;
import android.view.View;

class NativeViewFactory extends PlatformViewFactory {

NativeViewFactory() {
super(StandardMessageCodec.INSTANCE);
}

NativeView view2;

@NonNull
@Override
@SuppressWarnings("unchecked")
public PlatformView create(@NonNull Context context, int id, @Nullable Object args) {
final Map<String, Object> creationParams = (Map<String, Object>) args;
view2 = new NativeView(context, id, creationParams);
return view2;
}

public View getView2() {
return view2.getView();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import io.flutter.view.TextureRegistry;
import java.util.Objects;
import java.util.concurrent.Executors;
import androidx.camera.view.PreviewView;

public class PreviewHostApiImpl implements PreviewHostApi {
final BinaryMessenger binaryMessenger;
Expand All @@ -25,14 +26,17 @@ public class PreviewHostApiImpl implements PreviewHostApi {

@VisibleForTesting public @NonNull CameraXProxy cameraXProxy = new CameraXProxy();
@VisibleForTesting public @Nullable TextureRegistry.SurfaceProducer flutterSurfaceProducer;
public NativeViewFactory nativeViewFactory;

public PreviewHostApiImpl(
@NonNull BinaryMessenger binaryMessenger,
@NonNull InstanceManager instanceManager,
@NonNull TextureRegistry textureRegistry) {
@NonNull TextureRegistry textureRegistry,
NativeViewFactory nativeViewFactory) {
this.binaryMessenger = binaryMessenger;
this.instanceManager = instanceManager;
this.textureRegistry = textureRegistry;
this.nativeViewFactory = nativeViewFactory;
}

/** Creates a {@link Preview} with the target rotation and resolution if specified. */
Expand Down Expand Up @@ -61,11 +65,14 @@ public void create(
@Override
public @NonNull Long setSurfaceProvider(@NonNull Long identifier) {
Preview preview = getPreviewInstance(identifier);
flutterSurfaceProducer = textureRegistry.createSurfaceProducer();
Preview.SurfaceProvider surfaceProvider = createSurfaceProvider(flutterSurfaceProducer);
preview.setSurfaceProvider(surfaceProvider);

return flutterSurfaceProducer.id();
// flutterSurfaceProducer = textureRegistry.createSurfaceProducer();
// Preview.SurfaceProvider surfaceProvider = createSurfaceProvider(flutterSurfaceProducer);
// preview.setSurfaceProvider(surfaceProvider);
PreviewView previewView = (PreviewView) nativeViewFactory.getView2();
preview.setSurfaceProvider(previewView.getSurfaceProvider());

return 3L;
// return flutterSurfaceProducer.id();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,15 @@ flutter {
}

dependencies {
def camerax_version = "1.4.1"
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
api 'androidx.test:core:1.4.0'
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
implementation "androidx.camera:camera-video:${camerax_version}"
implementation "androidx.camera:camera-view:${camerax_version}"

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,63 @@

package io.flutter.plugins.cameraxexample;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import androidx.camera.lifecycle.ProcessCameraProvider;
import com.google.common.util.concurrent.ListenableFuture;
import android.os.Bundle;
import androidx.lifecycle.LifecycleOwner;
import androidx.camera.core.CameraSelector;
import androidx.core.content.ContextCompat;
import java.util.concurrent.ExecutionException;
import androidx.camera.core.Preview;
import androidx.camera.view.PreviewView;
import android.util.Log;

public class MainActivity extends FlutterActivity {}
public class MainActivity extends FlutterActivity {
// private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
// NativeViewFactory nativeViewFactory;

@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
// nativeViewFactory = new NativeViewFactory();
// flutterEngine
// .getPlatformViewsController()
// .getRegistry()
// .registerViewFactory("<platform-view-type>", nativeViewFactory);
}

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Log.e("CAMILLE", "oncreate!");
// cameraProviderFuture = ProcessCameraProvider.getInstance(this);
// cameraProviderFuture.addListener(() -> {
// try {
// ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
// bindPreview(cameraProvider);
// } catch (ExecutionException | InterruptedException e) {
// // No errors need to be handled for this Future.
// // This should never be reached.
// }
// }, ContextCompat.getMainExecutor(this));

}

// void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
// Preview preview = new Preview.Builder()
// .build();

// CameraSelector cameraSelector = new CameraSelector.Builder()
// .requireLensFacing(CameraSelector.LENS_FACING_BACK)
// .build();

// PreviewView previewView = (PreviewView) nativeViewFactory.getView2();
// preview.setSurfaceProvider(previewView.getSurfaceProvider());

// cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview);
// }
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ class CameraPreview extends StatelessWidget {
if (kIsWeb || defaultTargetPlatform != TargetPlatform.android) {
return child;
}

return RotatedBox(
quarterTurns: _getQuarterTurns(),
child: child,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import 'dart:math' show Point;

import 'package:async/async.dart';
import 'package:camera_platform_interface/camera_platform_interface.dart';
import 'package:flutter/services.dart'
show DeviceOrientation, PlatformException;
import 'package:flutter/services.dart';
// show DeviceOrientation, PlatformException;
import 'package:flutter/widgets.dart'
show Size, Texture, Widget, visibleForTesting;
import 'package:stream_transform/stream_transform.dart';
import 'package:flutter/foundation.dart';
// import 'package:flutter/services.dart';
import 'package:flutter/material.dart' show AndroidView;

import 'analyzer.dart';
import 'aspect_ratio_strategy.dart';
Expand Down Expand Up @@ -836,8 +839,18 @@ class AndroidCameraCameraX extends CameraPlatform {
);
}

return Texture(textureId: cameraId);
}
// This is used in the platform side to register the view.
const String viewType = '<camille-platform-view>';
// Pass parameters to the platform side.
final Map<String, dynamic> creationParams = <String, dynamic>{};

return AndroidView(
viewType: viewType,
layoutDirection: TextDirection.ltr,
creationParams: creationParams,
creationParamsCodec: const StandardMessageCodec(),
);
}

/// Captures an image and returns the file where it was saved.
///
Expand Down
Loading