-
Notifications
You must be signed in to change notification settings - Fork 5
/
MainActivity.cs
188 lines (155 loc) · 7.56 KB
/
MainActivity.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
using Android;
using Android.App;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Widget;
using AndroidX.AppCompat.App;
using AndroidX.Camera.Core;
using AndroidX.Camera.Lifecycle;
using AndroidX.Camera.View;
using AndroidX.Core.App;
using AndroidX.Core.Content;
using Java.IO;
using Java.Lang;
using Java.Util;
using Java.Util.Concurrent;
using System.Linq;
namespace CameraX
{
/// <summary>
/// https://codelabs.developers.google.com/codelabs/camerax-getting-started#0
/// </summary>
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
private const string TAG = "CameraXBasic";
private const int REQUEST_CODE_PERMISSIONS = 10;
private const string FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS";
ImageCapture imageCapture;
File outputDirectory;
IExecutorService cameraExecutor;
PreviewView viewFinder;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
this.viewFinder = this.FindViewById<PreviewView>(Resource.Id.viewFinder);
var camera_capture_button = this.FindViewById<Button>(Resource.Id.camera_capture_button);
// Request camera permissions
string[] permissions = new string[] { Manifest.Permission.Camera, Manifest.Permission.WriteExternalStorage };
if (permissions.FirstOrDefault(x => ContextCompat.CheckSelfPermission(this, x) != Android.Content.PM.Permission.Granted) != null) // ContextCompat.CheckSelfPermission(this, Manifest.Permission.Camera) == Android.Content.PM.Permission.Granted)
ActivityCompat.RequestPermissions(this, permissions, REQUEST_CODE_PERMISSIONS);
else
StartCamera();
// Set up the listener for take photo button
camera_capture_button.SetOnClickListener(new OnClickListener(() => TakePhoto()));
outputDirectory = GetOutputDirectory();
cameraExecutor = Executors.NewSingleThreadExecutor();
}
protected override void OnDestroy()
{
base.OnDestroy();
cameraExecutor.Shutdown();
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
if (requestCode == REQUEST_CODE_PERMISSIONS)
{
//if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.Camera) == Android.Content.PM.Permission.Granted)
if (permissions.FirstOrDefault(x => ContextCompat.CheckSelfPermission(this, x) != Android.Content.PM.Permission.Granted) == null)
{
StartCamera();
}
else
{
Toast.MakeText(this, "Permissions not granted by the user.", ToastLength.Short).Show();
this.Finish();
return;
}
}
//base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
/// <summary>
/// https://codelabs.developers.google.com/codelabs/camerax-getting-started#3
/// </summary>
private void StartCamera()
{
var cameraProviderFuture = ProcessCameraProvider.GetInstance(this);
cameraProviderFuture.AddListener(new Runnable(() =>
{
// Used to bind the lifecycle of cameras to the lifecycle owner
var cameraProvider = (ProcessCameraProvider)cameraProviderFuture.Get();
// Preview
var preview = new Preview.Builder().Build();
preview.SetSurfaceProvider(viewFinder.CreateSurfaceProvider());
// Take Photo
this.imageCapture = new ImageCapture.Builder().Build();
// Frame by frame analyze
var imageAnalyzer = new ImageAnalysis.Builder().Build();
imageAnalyzer.SetAnalyzer(cameraExecutor, new LuminosityAnalyzer(luma =>
Log.Debug(TAG, $"Average luminosity: {luma}")
));
// Select back camera as a default, or front camera otherwise
CameraSelector cameraSelector = null;
if (cameraProvider.HasCamera(CameraSelector.DefaultBackCamera) == true)
cameraSelector = CameraSelector.DefaultBackCamera;
else if (cameraProvider.HasCamera(CameraSelector.DefaultFrontCamera) == true)
cameraSelector = CameraSelector.DefaultFrontCamera;
else
throw new System.Exception("Camera not found");
try
{
// Unbind use cases before rebinding
cameraProvider.UnbindAll();
// Bind use cases to camera
cameraProvider.BindToLifecycle(this, cameraSelector, preview, imageCapture, imageAnalyzer);
}
catch (Exception exc)
{
Log.Debug(TAG, "Use case binding failed", exc);
Toast.MakeText(this, $"Use case binding failed: {exc.Message}", ToastLength.Short).Show();
}
}), ContextCompat.GetMainExecutor(this)); //GetMainExecutor: returns an Executor that runs on the main thread.
}
private void TakePhoto()
{
// Get a stable reference of the modifiable image capture use case
var imageCapture = this.imageCapture;
if (imageCapture == null)
return;
// Create time-stamped output file to hold the image
var photoFile = new File(outputDirectory, new Java.Text.SimpleDateFormat(FILENAME_FORMAT, Locale.Us).Format(JavaSystem.CurrentTimeMillis()) + ".jpg");
// Create output options object which contains file + metadata
var outputOptions = new ImageCapture.OutputFileOptions.Builder(photoFile).Build();
// Set up image capture listener, which is triggered after photo has been taken
imageCapture.TakePicture(outputOptions, ContextCompat.GetMainExecutor(this), new ImageSaveCallback(
onErrorCallback: (exc) =>
{
var msg = $"Photo capture failed: {exc.Message}";
Log.Error(TAG, msg, exc);
Toast.MakeText(this.BaseContext, msg, ToastLength.Short).Show();
},
onImageSaveCallback: (output) =>
{
var savedUri = output.SavedUri;
var msg = $"Photo capture succeeded: {savedUri}";
Log.Debug(TAG, msg);
Toast.MakeText(this.BaseContext, msg, ToastLength.Short).Show();
}
));
}
// Save photos to => /Pictures/CameraX/
private File GetOutputDirectory()
{
//var mediaDir = GetExternalMediaDirs().FirstOrDefault();
var mediaDir = Environment.GetExternalStoragePublicDirectory(System.IO.Path.Combine(Environment.DirectoryPictures, Resources.GetString(Resource.String.app_name)));
if (mediaDir != null && mediaDir.Exists())
return mediaDir;
var file = new File(mediaDir, string.Empty);
file.Mkdirs();
return file;
}
}
}