Skip to content

Commit 7c7f88a

Browse files
committed
Use TextureView instead of SurfaceView on Android.
Compared to existing ZXingSurfaceView, ZXingTextureView fixes the following: - Ensure correct aspect ratio, no matter what the view size. - Use background handler for all camera manipulation. - Crop preview to match viewfinder, so that you only scan what you see. - Avoid byte[] marshalling between Java and .Net runtime (FastJavaByteArray). - Return buffer to java runtime with camera.AddCallbackBuffer. - Avoid traslating from YCrCb to Rgb and back to luminance data (FastJavaByteArrayYUVLuminanceSource) - Re-use buffers, to avoid memory pressure, when rotating. - Automatically request autofocus on devices that does not support continous auto focus mode. - Prefer continous mode - For Xamarin.Forms ZXingScannerView now uses ZXingTextureView in the renderer on Android.
1 parent c6967b8 commit 7c7f88a

11 files changed

Lines changed: 1479 additions & 41 deletions

File tree

Samples/Forms/Core/CustomScanPage.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ public CustomScanPage () : base ()
2121
VerticalOptions = LayoutOptions.FillAndExpand,
2222
AutomationId = "zxingScannerView",
2323
};
24+
25+
var formats = zxing.Options.PossibleFormats;
26+
formats.Clear();
27+
formats.Add(ZXing.BarcodeFormat.CODE_128);
28+
formats.Add(ZXing.BarcodeFormat.CODE_39);
29+
formats.Add(ZXing.BarcodeFormat.QR_CODE);
30+
31+
zxing.IsTorchOn = true;
32+
2433
zxing.OnScanResult += (result) =>
2534
Device.BeginInvokeOnMainThread (async () => {
2635

@@ -30,8 +39,7 @@ public CustomScanPage () : base ()
3039
// Show an alert
3140
await DisplayAlert ("Scanned Barcode", result.Text, "OK");
3241

33-
// Navigate away
34-
await Navigation.PopAsync ();
42+
zxing.IsAnalyzing = true;
3543
});
3644

3745
overlay = new ZXingDefaultOverlay
@@ -46,6 +54,10 @@ public CustomScanPage () : base ()
4654
};
4755
var grid = new Grid
4856
{
57+
RowDefinitions = {
58+
new RowDefinition { Height = new GridLength(1, GridUnitType.Star) },
59+
new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }
60+
},
4961
VerticalOptions = LayoutOptions.FillAndExpand,
5062
HorizontalOptions = LayoutOptions.FillAndExpand,
5163
};

Samples/Forms/Droid/FormsSample.Droid.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
1616
<AssemblyName>FormsSample.Droid</AssemblyName>
1717
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
18-
<TargetFrameworkVersion>v6.0</TargetFrameworkVersion>
18+
<TargetFrameworkVersion>v7.0</TargetFrameworkVersion>
1919
<NuGetPackageImportStamp>
2020
</NuGetPackageImportStamp>
2121
</PropertyGroup>
@@ -29,6 +29,7 @@
2929
<WarningLevel>4</WarningLevel>
3030
<AndroidLinkMode>None</AndroidLinkMode>
3131
<ConsolePause>false</ConsolePause>
32+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
3233
</PropertyGroup>
3334
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
3435
<DebugType>full</DebugType>
@@ -39,6 +40,7 @@
3940
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
4041
<ConsolePause>false</ConsolePause>
4142
<AndroidSupportedAbis>armeabi;armeabi-v7a;x86;arm64-v8a;x86_64</AndroidSupportedAbis>
43+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
4244
</PropertyGroup>
4345
<ItemGroup>
4446
<Reference Include="System" />
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// <copyright company="APX Labs, Inc.">
2+
// Copyright (c) APX Labs, Inc. All rights reserved.
3+
// </copyright>
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
//
17+
// Many thanks to Jonathan Pryor from Xamarin for his assistance
18+
19+
using System;
20+
using Android.Hardware;
21+
using Android.Runtime;
22+
23+
namespace ApxLabs.FastAndroidCamera
24+
{
25+
public static class CameraExtensions
26+
{
27+
static IntPtr id_addCallbackBuffer_arrayB;
28+
public static void AddCallbackBuffer(this Camera self, FastJavaByteArray callbackBuffer)
29+
{
30+
if (id_addCallbackBuffer_arrayB == IntPtr.Zero)
31+
id_addCallbackBuffer_arrayB = JNIEnv.GetMethodID(self.Class.Handle, "addCallbackBuffer", "([B)V");
32+
JNIEnv.CallVoidMethod(self.Handle, id_addCallbackBuffer_arrayB, new JValue(callbackBuffer.Handle));
33+
}
34+
35+
static IntPtr id_setPreviewCallback_Landroid_hardware_Camera_PreviewCallback_;
36+
public static void SetNonMarshalingPreviewCallback(this Camera self, INonMarshalingPreviewCallback cb)
37+
{
38+
if (id_setPreviewCallback_Landroid_hardware_Camera_PreviewCallback_ == IntPtr.Zero)
39+
id_setPreviewCallback_Landroid_hardware_Camera_PreviewCallback_ = JNIEnv.GetMethodID(self.Class.Handle, "setPreviewCallbackWithBuffer", "(Landroid/hardware/Camera$PreviewCallback;)V");
40+
JNIEnv.CallVoidMethod(self.Handle, id_setPreviewCallback_Landroid_hardware_Camera_PreviewCallback_, new JValue(cb));
41+
}
42+
43+
static IntPtr id_setOneShotPreviewCallback_Landroid_hardware_Camera_PreviewCallback_;
44+
public static void SetNonMarshalingOneShotPreviewCallback(this Camera self, INonMarshalingPreviewCallback cb)
45+
{
46+
if (id_setOneShotPreviewCallback_Landroid_hardware_Camera_PreviewCallback_ == IntPtr.Zero)
47+
id_setOneShotPreviewCallback_Landroid_hardware_Camera_PreviewCallback_ = JNIEnv.GetMethodID(self.Class.Handle, "setOneShotPreviewCallback", "(Landroid/hardware/Camera$PreviewCallback;)V");
48+
JNIEnv.CallVoidMethod(self.Handle, id_setOneShotPreviewCallback_Landroid_hardware_Camera_PreviewCallback_, new JValue(cb));
49+
}
50+
}
51+
52+
// Metadata.xml XPath interface reference: path="/api/package[@name='android.hardware']/interface[@name='Camera.PreviewCallback']"
53+
[Register("android/hardware/Camera$PreviewCallback", "", "ApxLabs.FastAndroidCamera.INonMarshalingPreviewCallbackInvoker")]
54+
public interface INonMarshalingPreviewCallback : IJavaObject {
55+
56+
// Metadata.xml XPath method reference: path="/api/package[@name='android.hardware']/interface[@name='Camera.PreviewCallback']/method[@name='onPreviewFrame' and count(parameter)=2 and parameter[1][@type='byte[]'] and parameter[2][@type='android.hardware.Camera']]"
57+
// [Register("onPreviewFrame", "([BLandroid/hardware/Camera;)V", "GetOnPreviewFrame_arrayBLandroid_hardware_Camera_Handler:ApxLabs.FastAndroidCamera.INonMarshalingPreviewCallbackInvoker, FastAndroidCamera, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")]
58+
[Register("onPreviewFrame", "([BLandroid/hardware/Camera;)V", "GetOnPreviewFrame_arrayBLandroid_hardware_Camera_Handler:ApxLabs.FastAndroidCamera.INonMarshalingPreviewCallbackInvoker, ZXingNetMobile, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")]
59+
void OnPreviewFrame(IntPtr data, Camera camera);
60+
}
61+
62+
[Register("android/hardware/Camera$PreviewCallback", DoNotGenerateAcw=true)]
63+
internal class INonMarshalingPreviewCallbackInvoker : Java.Lang.Object, INonMarshalingPreviewCallback {
64+
65+
static IntPtr java_class_ref = JNIEnv.FindClass("android/hardware/Camera$PreviewCallback");
66+
IntPtr class_ref;
67+
68+
public static INonMarshalingPreviewCallback GetObject(IntPtr handle, JniHandleOwnership transfer)
69+
{
70+
return GetObject<INonMarshalingPreviewCallback>(handle, transfer);
71+
}
72+
73+
static IntPtr Validate(IntPtr handle)
74+
{
75+
if (!JNIEnv.IsInstanceOf(handle, java_class_ref))
76+
throw new InvalidCastException(string.Format("Unable to convert instance of type '{0}' to type '{1}'.",
77+
JNIEnv.GetClassNameFromInstance(handle), "android.hardware.Camera.PreviewCallback"));
78+
return handle;
79+
}
80+
81+
protected override void Dispose(bool disposing)
82+
{
83+
if (class_ref != IntPtr.Zero)
84+
JNIEnv.DeleteGlobalRef(class_ref);
85+
class_ref = IntPtr.Zero;
86+
base.Dispose(disposing);
87+
}
88+
89+
public INonMarshalingPreviewCallbackInvoker(IntPtr handle, JniHandleOwnership transfer)
90+
: base(Validate(handle), transfer)
91+
{
92+
IntPtr local_ref = JNIEnv.GetObjectClass(Handle);
93+
class_ref = JNIEnv.NewGlobalRef(local_ref);
94+
JNIEnv.DeleteLocalRef(local_ref);
95+
}
96+
97+
protected override IntPtr ThresholdClass {
98+
get { return class_ref; }
99+
}
100+
101+
protected override Type ThresholdType {
102+
get { return typeof(INonMarshalingPreviewCallbackInvoker); }
103+
}
104+
105+
static Delegate cb_onPreviewFrame_arrayBLandroid_hardware_Camera_;
106+
#pragma warning disable 0169
107+
static Delegate GetOnPreviewFrame_arrayBLandroid_hardware_Camera_Handler()
108+
{
109+
if (cb_onPreviewFrame_arrayBLandroid_hardware_Camera_ == null)
110+
cb_onPreviewFrame_arrayBLandroid_hardware_Camera_ = JNINativeWrapper.CreateDelegate((Action<IntPtr, IntPtr, IntPtr, IntPtr>) n_OnPreviewFrame_arrayBLandroid_hardware_Camera_);
111+
return cb_onPreviewFrame_arrayBLandroid_hardware_Camera_;
112+
}
113+
114+
static void n_OnPreviewFrame_arrayBLandroid_hardware_Camera_(IntPtr jnienv, IntPtr native__this, IntPtr native_data, IntPtr native_camera)
115+
{
116+
INonMarshalingPreviewCallback __this = GetObject<INonMarshalingPreviewCallback>(native__this, JniHandleOwnership.DoNotTransfer);
117+
Camera camera = GetObject<Camera>(native_camera, JniHandleOwnership.DoNotTransfer);
118+
__this.OnPreviewFrame(native_data, camera);
119+
}
120+
#pragma warning restore 0169
121+
122+
IntPtr id_onPreviewFrame_arrayBLandroid_hardware_Camera_;
123+
public void OnPreviewFrame(IntPtr data, Camera camera)
124+
{
125+
if (id_onPreviewFrame_arrayBLandroid_hardware_Camera_ == IntPtr.Zero)
126+
id_onPreviewFrame_arrayBLandroid_hardware_Camera_ = JNIEnv.GetMethodID(class_ref, "onPreviewFrame", "([BLandroid/hardware/Camera;)V");
127+
JNIEnv.CallVoidMethod(Handle, id_onPreviewFrame_arrayBLandroid_hardware_Camera_, new JValue(data), new JValue(camera));
128+
}
129+
}
130+
}

0 commit comments

Comments
 (0)