cordova-plugin-mserviceinterface-2.0 1.0.85 → 1.0.87
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/plugin.xml +19 -1
- package/src/android/CameraActivity.java +334 -0
- package/src/android/res/drawable/circle_button.xml +14 -0
- package/src/android/res/drawable/focus_box.xml +11 -0
- package/src/android/res/drawable/ic_flashlight_off.xml +17 -0
- package/src/android/res/drawable/ic_flashlight_on.xml +12 -0
- package/src/android/res/drawable/ic_flip_camera.xml +14 -0
- package/src/android/res/layout/activity_camera.xml +64 -0
- package/src/android/res/values/styles.xml +8 -0
package/package.json
CHANGED
package/plugin.xml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
2
|
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
|
|
3
|
-
xmlns:android="http://schemas.android.com/apk/res/android" id="cordova-plugin-mserviceinterface-2.0" version="1.0.
|
|
3
|
+
xmlns:android="http://schemas.android.com/apk/res/android" id="cordova-plugin-mserviceinterface-2.0" version="1.0.87">
|
|
4
4
|
<name>mserviceinterface-2.0</name>
|
|
5
5
|
<description>This plugin establishes the connection to the native interface and performs the requested task.</description>
|
|
6
6
|
<author>selfservit@gmail.com</author>
|
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
</js-module>
|
|
18
18
|
<platform name="android">
|
|
19
19
|
<framework src="src/android/doubleogradle.gradle" custom="true" type="gradleReference"/>
|
|
20
|
+
<framework src="androidx.camera:camera-core:1.2.0" />
|
|
21
|
+
<framework src="androidx.camera:camera-camera2:1.2.0" />
|
|
22
|
+
<framework src="androidx.camera:camera-lifecycle:1.2.0" />
|
|
23
|
+
<framework src="androidx.camera:camera-view:1.2.0" />
|
|
24
|
+
<framework src="androidx.constraintlayout:constraintlayout:2.1.4" />
|
|
20
25
|
<framework src="com.google.android.gms:play-services-location:21.0.1" />
|
|
21
26
|
<framework src="androidx.exifinterface:exifinterface:1.3.5" />
|
|
22
27
|
<framework src="com.android.support:support-v4:28.0.0" />
|
|
@@ -50,8 +55,14 @@
|
|
|
50
55
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
|
51
56
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
52
57
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
|
58
|
+
<queries>
|
|
59
|
+
<intent>
|
|
60
|
+
<action android:name="android.media.action.IMAGE_CAPTURE" />
|
|
61
|
+
</intent>
|
|
62
|
+
</queries>
|
|
53
63
|
</config-file>
|
|
54
64
|
<config-file target="AndroidManifest.xml" parent="/manifest/application">
|
|
65
|
+
<activity android:name="com.selfservit.util.CameraActivity" android:configChanges="orientation|screenSize" android:screenOrientation="portrait" android:exported="true" android:theme="@style/CameraTheme" />
|
|
55
66
|
<service android:name="com.selfservit.util.mInterfaceService" android:foregroundServiceType="location" android:enabled="true" android:exported="true"/>
|
|
56
67
|
<receiver android:name="com.selfservit.util.mInterfaceReceiver" android:enabled="true" android:exported="true">
|
|
57
68
|
<intent-filter>
|
|
@@ -78,6 +89,13 @@
|
|
|
78
89
|
<source-file src="src/android/res/xml/opener_paths.xml" target-dir="res/xml" />
|
|
79
90
|
<source-file src="src/android/res/xml/network_security_config.xml" target-dir="res/xml" />
|
|
80
91
|
<source-file src="src/android/res/xml/my_backup_rules.xml" target-dir="res/xml" />
|
|
92
|
+
<resource-file src="src/android/res/layout/activity_camera.xml" target="app/src/main/res/layout/activity_camera.xml" />
|
|
93
|
+
<resource-file src="src/android/res/drawable/focus_box.xml" target="app/src/main/res/drawable/focus_box.xml" />
|
|
94
|
+
<resource-file src="src/android/res/drawable/ic_flip_camera.xml" target="app/src/main/res/drawable/ic_flip_camera.xml" />
|
|
95
|
+
<resource-file src="src/android/res/drawable/circle_button.xml" target="app/src/main/res/drawable/circle_button.xml" />
|
|
96
|
+
<resource-file src="src/android/res/drawable/ic_flashlight_on.xml" target="app/src/main/res/drawable/ic_flashlight_on.xml" />
|
|
97
|
+
<resource-file src="src/android/res/drawable/ic_flashlight_off.xml" target="app/src/main/res/drawable/ic_flashlight_off.xml" />
|
|
98
|
+
<resource-file src="src/android/res/values/styles.xml" target="app/src/main/res/values/styles.xml" />
|
|
81
99
|
</platform>
|
|
82
100
|
<platform name="ios">
|
|
83
101
|
<config-file target="*-Info.plist" parent="NSCameraUsageDescription">
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
package com.selfservit.util;
|
|
2
|
+
|
|
3
|
+
import android.Manifest;
|
|
4
|
+
import android.annotation.SuppressLint;
|
|
5
|
+
import android.app.Activity;
|
|
6
|
+
import android.content.Intent;
|
|
7
|
+
import android.content.pm.PackageManager;
|
|
8
|
+
import android.os.Bundle;
|
|
9
|
+
import android.util.Log;
|
|
10
|
+
import android.view.MotionEvent;
|
|
11
|
+
import android.view.ScaleGestureDetector;
|
|
12
|
+
import android.view.View;
|
|
13
|
+
import android.view.ViewGroup;
|
|
14
|
+
import android.widget.ImageButton;
|
|
15
|
+
import android.widget.Toast;
|
|
16
|
+
|
|
17
|
+
import androidx.annotation.NonNull;
|
|
18
|
+
import androidx.appcompat.app.AppCompatActivity;
|
|
19
|
+
import androidx.camera.core.Camera;
|
|
20
|
+
import androidx.camera.core.CameraSelector;
|
|
21
|
+
import androidx.camera.core.FocusMeteringAction;
|
|
22
|
+
import androidx.camera.core.ImageCapture;
|
|
23
|
+
import androidx.camera.core.ImageCaptureException;
|
|
24
|
+
import androidx.camera.core.MeteringPoint;
|
|
25
|
+
import androidx.camera.core.Preview;
|
|
26
|
+
import androidx.camera.lifecycle.ProcessCameraProvider;
|
|
27
|
+
import androidx.camera.view.PreviewView;
|
|
28
|
+
import androidx.core.app.ActivityCompat;
|
|
29
|
+
import androidx.core.content.ContextCompat;
|
|
30
|
+
|
|
31
|
+
import com.google.common.util.concurrent.ListenableFuture;
|
|
32
|
+
|
|
33
|
+
import java.io.File;
|
|
34
|
+
import java.text.SimpleDateFormat;
|
|
35
|
+
import java.util.Locale;
|
|
36
|
+
import java.util.Objects;
|
|
37
|
+
import java.util.concurrent.ExecutionException;
|
|
38
|
+
import java.util.concurrent.TimeUnit;
|
|
39
|
+
|
|
40
|
+
public class CameraActivity extends AppCompatActivity {
|
|
41
|
+
private static final int REQUEST_CODE_PERMISSIONS = 10;
|
|
42
|
+
private final String[] REQUIRED_PERMISSIONS = new String[]{ Manifest.permission.CAMERA };
|
|
43
|
+
|
|
44
|
+
private PreviewView previewView;
|
|
45
|
+
private ImageCapture imageCapture;
|
|
46
|
+
private ImageButton torchButton;
|
|
47
|
+
private ProcessCameraProvider cameraProvider;
|
|
48
|
+
private Camera camera;
|
|
49
|
+
|
|
50
|
+
private int lensFacing = CameraSelector.LENS_FACING_BACK;
|
|
51
|
+
private boolean isTorchOn = false;
|
|
52
|
+
private ScaleGestureDetector scaleGestureDetector;
|
|
53
|
+
private View focusView;
|
|
54
|
+
private ScaleGestureDetector scaleDetector;
|
|
55
|
+
@SuppressLint("ClickableViewAccessibility")
|
|
56
|
+
@Override
|
|
57
|
+
protected void onCreate(Bundle savedInstanceState) {
|
|
58
|
+
super.onCreate(savedInstanceState);
|
|
59
|
+
|
|
60
|
+
// Dynamically inflate layout
|
|
61
|
+
String pkg = getPackageName();
|
|
62
|
+
int layoutId = getResources().getIdentifier("activity_camera", "layout", pkg);
|
|
63
|
+
setContentView(layoutId);
|
|
64
|
+
|
|
65
|
+
// Resolve view IDs
|
|
66
|
+
int previewId = getResources().getIdentifier("previewView", "id", pkg);
|
|
67
|
+
int captureId = getResources().getIdentifier("captureButton", "id", pkg);
|
|
68
|
+
int switchId = getResources().getIdentifier("switchCamera", "id", pkg);
|
|
69
|
+
int torchId = getResources().getIdentifier("torchButton", "id", pkg);
|
|
70
|
+
int focusViewId = getResources().getIdentifier("focusView", "id", pkg);
|
|
71
|
+
|
|
72
|
+
// Resolve drawable IDs
|
|
73
|
+
final int torchOnDrawable = getResources().getIdentifier("ic_flashlight_on", "drawable", pkg);
|
|
74
|
+
final int torchOffDrawable = getResources().getIdentifier("ic_flashlight_off", "drawable", pkg);
|
|
75
|
+
|
|
76
|
+
// Bind views to fields
|
|
77
|
+
previewView = findViewById(previewId);
|
|
78
|
+
ImageButton captureButton = findViewById(captureId);
|
|
79
|
+
ImageButton switchButton = findViewById(switchId);
|
|
80
|
+
torchButton = findViewById(torchId);
|
|
81
|
+
focusView = findViewById(focusViewId);
|
|
82
|
+
|
|
83
|
+
// Utility to add press animation to any view
|
|
84
|
+
View.OnTouchListener pressAnim = (v, e) -> {
|
|
85
|
+
switch (e.getAction()) {
|
|
86
|
+
case MotionEvent.ACTION_DOWN:
|
|
87
|
+
v.animate()
|
|
88
|
+
.scaleX(0.9f)
|
|
89
|
+
.scaleY(0.9f)
|
|
90
|
+
.setDuration(100)
|
|
91
|
+
.start();
|
|
92
|
+
break;
|
|
93
|
+
case MotionEvent.ACTION_UP:
|
|
94
|
+
case MotionEvent.ACTION_CANCEL:
|
|
95
|
+
v.animate()
|
|
96
|
+
.scaleX(1f)
|
|
97
|
+
.scaleY(1f)
|
|
98
|
+
.setDuration(100)
|
|
99
|
+
.start();
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
// return false so the click event still fires
|
|
103
|
+
return false;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// Apply it to your buttons
|
|
107
|
+
captureButton.setOnTouchListener(pressAnim);
|
|
108
|
+
switchButton .setOnTouchListener(pressAnim);
|
|
109
|
+
torchButton .setOnTouchListener(pressAnim);
|
|
110
|
+
// Pinch-to-zoom & tap-to-focus
|
|
111
|
+
scaleGestureDetector = new ScaleGestureDetector(this,
|
|
112
|
+
new ScaleGestureDetector.SimpleOnScaleGestureListener() {
|
|
113
|
+
@Override
|
|
114
|
+
public boolean onScale(@NonNull ScaleGestureDetector detector) {
|
|
115
|
+
if (camera != null) {
|
|
116
|
+
float current = Objects.requireNonNull(camera.getCameraInfo()
|
|
117
|
+
.getZoomState().getValue()).getZoomRatio();
|
|
118
|
+
camera.getCameraControl()
|
|
119
|
+
.setZoomRatio(current * detector.getScaleFactor());
|
|
120
|
+
}
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
previewView.setOnTouchListener((v, e) -> {
|
|
125
|
+
scaleGestureDetector.onTouchEvent(e);
|
|
126
|
+
if (e.getAction() == MotionEvent.ACTION_UP && camera != null) {
|
|
127
|
+
MeteringPoint point = previewView.getMeteringPointFactory()
|
|
128
|
+
.createPoint(e.getX(), e.getY());
|
|
129
|
+
camera.getCameraControl()
|
|
130
|
+
.startFocusAndMetering(new FocusMeteringAction.Builder(point).build());
|
|
131
|
+
}
|
|
132
|
+
return true;
|
|
133
|
+
});
|
|
134
|
+
scaleDetector = new ScaleGestureDetector(this,
|
|
135
|
+
new ScaleGestureDetector.SimpleOnScaleGestureListener() {
|
|
136
|
+
@Override
|
|
137
|
+
public boolean onScale(ScaleGestureDetector detector) {
|
|
138
|
+
if (camera != null) {
|
|
139
|
+
float current = camera.getCameraInfo()
|
|
140
|
+
.getZoomState().getValue().getZoomRatio();
|
|
141
|
+
camera.getCameraControl().setZoomRatio(current * detector.getScaleFactor());
|
|
142
|
+
}
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
// Touch listener: zoom + focus box + CameraX focus
|
|
147
|
+
previewView.setOnTouchListener((v, e) -> {
|
|
148
|
+
scaleDetector.onTouchEvent(e);
|
|
149
|
+
if (e.getAction() == MotionEvent.ACTION_UP && camera != null) {
|
|
150
|
+
float x = e.getX(), y = e.getY();
|
|
151
|
+
|
|
152
|
+
// 1) Show & animate focus box
|
|
153
|
+
focusView.setX(x - (float) focusView.getWidth() /2);
|
|
154
|
+
focusView.setY(y - (float) focusView.getHeight() /2);
|
|
155
|
+
focusView.setAlpha(1f);
|
|
156
|
+
focusView.setVisibility(View.VISIBLE);
|
|
157
|
+
focusView.animate()
|
|
158
|
+
.alpha(0f)
|
|
159
|
+
.setDuration(800)
|
|
160
|
+
.withEndAction(() -> focusView.setVisibility(View.GONE));
|
|
161
|
+
|
|
162
|
+
// 2) Tell CameraX to focus there
|
|
163
|
+
MeteringPoint point = previewView.getMeteringPointFactory()
|
|
164
|
+
.createPoint(x, y);
|
|
165
|
+
FocusMeteringAction action = new FocusMeteringAction.Builder(point)
|
|
166
|
+
.setAutoCancelDuration(3, TimeUnit.SECONDS)
|
|
167
|
+
.build();
|
|
168
|
+
camera.getCameraControl().startFocusAndMetering(action);
|
|
169
|
+
}
|
|
170
|
+
return true;
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Permissions and start
|
|
174
|
+
if (allPermissionsGranted()) {
|
|
175
|
+
startCamera();
|
|
176
|
+
} else {
|
|
177
|
+
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Capture
|
|
181
|
+
captureButton.setOnClickListener(v -> takePhoto());
|
|
182
|
+
|
|
183
|
+
// Switch front/back
|
|
184
|
+
switchButton.setOnClickListener(v -> {
|
|
185
|
+
lensFacing = (lensFacing == CameraSelector.LENS_FACING_BACK)
|
|
186
|
+
? CameraSelector.LENS_FACING_FRONT
|
|
187
|
+
: CameraSelector.LENS_FACING_BACK;
|
|
188
|
+
bindUseCases();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Torch toggle
|
|
192
|
+
torchButton.setOnClickListener(v -> {
|
|
193
|
+
if (camera != null) {
|
|
194
|
+
isTorchOn = !isTorchOn;
|
|
195
|
+
camera.getCameraControl().enableTorch(isTorchOn);
|
|
196
|
+
torchButton.setImageResource(isTorchOn ? torchOnDrawable : torchOffDrawable);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private void startCamera() {
|
|
202
|
+
ListenableFuture<ProcessCameraProvider> future =
|
|
203
|
+
ProcessCameraProvider.getInstance(this);
|
|
204
|
+
future.addListener(() -> {
|
|
205
|
+
try {
|
|
206
|
+
cameraProvider = future.get();
|
|
207
|
+
bindUseCases();
|
|
208
|
+
} catch (ExecutionException | InterruptedException e) {
|
|
209
|
+
Log.e("CameraActivity", "CameraProvider init failed", e);
|
|
210
|
+
}
|
|
211
|
+
}, ContextCompat.getMainExecutor(this));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private void bindUseCases() {
|
|
215
|
+
if (cameraProvider == null || previewView == null) return;
|
|
216
|
+
|
|
217
|
+
// Unbind old before rebinding
|
|
218
|
+
cameraProvider.unbindAll();
|
|
219
|
+
|
|
220
|
+
// Preview use-case
|
|
221
|
+
Preview preview = new Preview.Builder().build();
|
|
222
|
+
preview.setSurfaceProvider(previewView.getSurfaceProvider());
|
|
223
|
+
|
|
224
|
+
// Image capture use-case
|
|
225
|
+
imageCapture = new ImageCapture.Builder()
|
|
226
|
+
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
|
|
227
|
+
.build();
|
|
228
|
+
|
|
229
|
+
// Select camera
|
|
230
|
+
CameraSelector selector = new CameraSelector.Builder()
|
|
231
|
+
.requireLensFacing(lensFacing)
|
|
232
|
+
.build();
|
|
233
|
+
|
|
234
|
+
// Bind lifecycle
|
|
235
|
+
camera = cameraProvider.bindToLifecycle(
|
|
236
|
+
this, selector, preview, imageCapture
|
|
237
|
+
);
|
|
238
|
+
boolean hasFlash = camera.getCameraInfo().hasFlashUnit();
|
|
239
|
+
if (hasFlash) {
|
|
240
|
+
torchButton.setVisibility(View.VISIBLE);
|
|
241
|
+
} else {
|
|
242
|
+
torchButton.setVisibility(View.GONE);
|
|
243
|
+
// reset state in case you were mid-toggle
|
|
244
|
+
isTorchOn = false;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
private void takePhoto() {
|
|
248
|
+
if (imageCapture == null) return;
|
|
249
|
+
|
|
250
|
+
// Prepare output file
|
|
251
|
+
File photoFile = new File(getCacheDir(),
|
|
252
|
+
new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.US)
|
|
253
|
+
.format(System.currentTimeMillis()) + ".jpg"
|
|
254
|
+
);
|
|
255
|
+
ImageCapture.OutputFileOptions options =
|
|
256
|
+
new ImageCapture.OutputFileOptions.Builder(photoFile).build();
|
|
257
|
+
|
|
258
|
+
// Take picture
|
|
259
|
+
imageCapture.takePicture(options,
|
|
260
|
+
ContextCompat.getMainExecutor(this),
|
|
261
|
+
new ImageCapture.OnImageSavedCallback() {
|
|
262
|
+
@Override
|
|
263
|
+
public void onImageSaved(@NonNull ImageCapture.OutputFileResults result) {
|
|
264
|
+
// Return path to Cordova plugin
|
|
265
|
+
Intent out = new Intent();
|
|
266
|
+
out.putExtra("imagePath", photoFile.getAbsolutePath());
|
|
267
|
+
setResult(Activity.RESULT_OK, out);
|
|
268
|
+
finish();
|
|
269
|
+
}
|
|
270
|
+
@Override
|
|
271
|
+
public void onError(@NonNull ImageCaptureException exc) {
|
|
272
|
+
Intent out = new Intent();
|
|
273
|
+
out.putExtra("error", exc.getMessage());
|
|
274
|
+
setResult(Activity.RESULT_CANCELED, out);
|
|
275
|
+
finish();
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
private void takePhoto1() {
|
|
281
|
+
if (imageCapture == null) return;
|
|
282
|
+
|
|
283
|
+
File file = new File(getCacheDir(),
|
|
284
|
+
new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS", Locale.US)
|
|
285
|
+
.format(System.currentTimeMillis()) + ".jpg"
|
|
286
|
+
);
|
|
287
|
+
ImageCapture.OutputFileOptions opts =
|
|
288
|
+
new ImageCapture.OutputFileOptions.Builder(file).build();
|
|
289
|
+
|
|
290
|
+
imageCapture.takePicture(
|
|
291
|
+
opts,
|
|
292
|
+
ContextCompat.getMainExecutor(this),
|
|
293
|
+
new ImageCapture.OnImageSavedCallback() {
|
|
294
|
+
@Override
|
|
295
|
+
public void onImageSaved(@NonNull ImageCapture.OutputFileResults result) {
|
|
296
|
+
Toast.makeText(CameraActivity.this,
|
|
297
|
+
"Saved: " + file.getAbsolutePath(),
|
|
298
|
+
Toast.LENGTH_SHORT).show();
|
|
299
|
+
// TODO: return path via Intent to Cordova side
|
|
300
|
+
}
|
|
301
|
+
@Override
|
|
302
|
+
public void onError(@NonNull ImageCaptureException exc) {
|
|
303
|
+
Toast.makeText(CameraActivity.this,
|
|
304
|
+
"Error: " + exc.getMessage(),
|
|
305
|
+
Toast.LENGTH_SHORT).show();
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
private boolean allPermissionsGranted() {
|
|
312
|
+
for (String p : REQUIRED_PERMISSIONS) {
|
|
313
|
+
if (ContextCompat.checkSelfPermission(this, p)
|
|
314
|
+
!= PackageManager.PERMISSION_GRANTED) return false;
|
|
315
|
+
}
|
|
316
|
+
return true;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
@Override
|
|
320
|
+
public void onRequestPermissionsResult(int rc, @NonNull String[] perms,
|
|
321
|
+
@NonNull int[] results) {
|
|
322
|
+
super.onRequestPermissionsResult(rc, perms, results);
|
|
323
|
+
if (rc == REQUEST_CODE_PERMISSIONS) {
|
|
324
|
+
if (allPermissionsGranted()) {
|
|
325
|
+
startCamera();
|
|
326
|
+
} else {
|
|
327
|
+
Toast.makeText(this,
|
|
328
|
+
"Camera permission required", Toast.LENGTH_SHORT).show();
|
|
329
|
+
setResult(Activity.RESULT_CANCELED);
|
|
330
|
+
finish();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
android:width="60dp"
|
|
3
|
+
android:height="60dp"
|
|
4
|
+
android:viewportWidth="60"
|
|
5
|
+
android:viewportHeight="60">
|
|
6
|
+
<path
|
|
7
|
+
android:fillColor="#FFFFFFFF"
|
|
8
|
+
android:pathData="M0 30c0-16.57 13.43-30 30-30h0c16.57 0 30 13.43 30 30v0c0 16.57-13.43 30-30 30h0c-16.57 0-30-13.43-30-30z"/>
|
|
9
|
+
<path
|
|
10
|
+
android:fillColor="#FFFFFFFF"
|
|
11
|
+
android:strokeColor="#FF000000"
|
|
12
|
+
android:strokeWidth="1.3"
|
|
13
|
+
android:pathData="M29.5 4.65c13.71 0 24.85 11.34 24.85 25.35 0 14.01-11.14 25.35-24.85 25.35S4.65 44.01 4.65 30c0-14.01 11.14-25.35 24.85-25.35Z"/>
|
|
14
|
+
</vector>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
android:width="80dp"
|
|
3
|
+
android:height="80dp"
|
|
4
|
+
android:viewportWidth="80"
|
|
5
|
+
android:viewportHeight="80">
|
|
6
|
+
<group>
|
|
7
|
+
<path
|
|
8
|
+
android:fillColor="#FFFFFFFF"
|
|
9
|
+
android:pathData="M14.33 65.67V50.1h2v13.56H29.9v2H14.33Zm35.78 0v-2h13.56V50.1h2v15.56H50.1ZM14.33 29.89V14.33H29.9v2H16.33V29.9h-2Zm49.34 0V16.33H50.1v-2h15.56V29.9h-2Z"/>
|
|
10
|
+
</group>
|
|
11
|
+
</vector>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
android:width="45dp"
|
|
3
|
+
android:height="45dp"
|
|
4
|
+
android:viewportWidth="45"
|
|
5
|
+
android:viewportHeight="45">
|
|
6
|
+
<path
|
|
7
|
+
android:fillColor="#54151515"
|
|
8
|
+
android:pathData="M0 22.5c0-12.43 10.07-22.5 22.5-22.5h0c12.43 0 22.5 10.07 22.5 22.5v0c0 12.43-10.07 22.5-22.5 22.5h0c-12.43 0-22.5-10.07-22.5-22.5z"/>
|
|
9
|
+
<path
|
|
10
|
+
android:fillColor="#FFFFFFFF"
|
|
11
|
+
android:pathData="M20.7 36.9h-1.8l1.8-11.2h-6.3c-1.05 0-1.03-0.51-0.7-1.06 0.35-0.54 0.1-0.12 0.14-0.19 2.32-3.65 5.8-9.09 10.45-16.35h1.8l-1.8 11.2h6.3c0.89 0 1.01 0.53 0.85 0.82l-0.13 0.24C24.22 31.38 20.7 36.9 20.7 36.9Z"/>
|
|
12
|
+
<path
|
|
13
|
+
android:fillColor="#FFFFFFFF"
|
|
14
|
+
android:strokeColor="#FF000000"
|
|
15
|
+
android:strokeWidth="0.1"
|
|
16
|
+
android:pathData="M14.33 13.24l0.85-0.71 15.82 19-0.85 0.72z"/>
|
|
17
|
+
</vector>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
android:width="45dp"
|
|
3
|
+
android:height="45dp"
|
|
4
|
+
android:viewportWidth="45"
|
|
5
|
+
android:viewportHeight="45">
|
|
6
|
+
<path
|
|
7
|
+
android:fillColor="#54151515"
|
|
8
|
+
android:pathData="M0 22.5c0-12.43 10.07-22.5 22.5-22.5h0c12.43 0 22.5 10.07 22.5 22.5v0c0 12.43-10.07 22.5-22.5 22.5h0c-12.43 0-22.5-10.07-22.5-22.5z"/>
|
|
9
|
+
<path
|
|
10
|
+
android:fillColor="#FFFFFFFF"
|
|
11
|
+
android:pathData="M20.7 36.9h-1.8l1.8-11.2h-6.3c-1.05 0-1.03-0.51-0.7-1.06 0.35-0.54 0.1-0.12 0.14-0.19 2.32-3.65 5.8-9.09 10.45-16.35h1.8l-1.8 11.2h6.3c0.89 0 1.01 0.53 0.85 0.82l-0.13 0.24C24.22 31.38 20.7 36.9 20.7 36.9Z"/>
|
|
12
|
+
</vector>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
android:width="45dp"
|
|
3
|
+
android:height="45dp"
|
|
4
|
+
android:viewportWidth="45"
|
|
5
|
+
android:viewportHeight="45">
|
|
6
|
+
<path
|
|
7
|
+
android:fillColor="#54151515"
|
|
8
|
+
android:pathData="M0 22.5c0-12.43 10.07-22.5 22.5-22.5h0c12.43 0 22.5 10.07 22.5 22.5v0c0 12.43-10.07 22.5-22.5 22.5h0c-12.43 0-22.5-10.07-22.5-22.5z"/>
|
|
9
|
+
<group>
|
|
10
|
+
<path
|
|
11
|
+
android:fillColor="#FFFFFFFF"
|
|
12
|
+
android:pathData="M12.07 19.63l6.45 3.72-3.81 1.02c1.12 4.2 5.46 6.7 9.66 5.58 1.28-0.34 2.42-0.99 3.32-1.84l2.35 1.35c-1.3 1.41-3 2.5-4.99 3.03-5.61 1.5-11.38-1.83-12.88-7.44l-3.82 1.02 3.72-6.44Zm17.88 0.66c-1.13-4.2-5.46-6.71-9.66-5.58-1.29 0.34-2.42 0.98-3.32 1.84l-2.35-1.36c1.3-1.4 2.99-2.49 4.98-3.02 5.62-1.5 11.39 1.82 12.89 7.43l3.81-1.02-3.72 6.45-6.44-3.72 3.8-1.02Z"/>
|
|
13
|
+
</group>
|
|
14
|
+
</vector>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<androidx.constraintlayout.widget.ConstraintLayout
|
|
3
|
+
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
4
|
+
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
5
|
+
android:layout_width="match_parent"
|
|
6
|
+
android:layout_height="match_parent">
|
|
7
|
+
|
|
8
|
+
<androidx.camera.view.PreviewView
|
|
9
|
+
android:id="@+id/previewView"
|
|
10
|
+
android:layout_width="0dp"
|
|
11
|
+
android:layout_height="0dp"
|
|
12
|
+
app:layout_constraintTop_toTopOf="parent"
|
|
13
|
+
app:layout_constraintBottom_toBottomOf="parent"
|
|
14
|
+
app:layout_constraintStart_toStartOf="parent"
|
|
15
|
+
app:layout_constraintEnd_toEndOf="parent"/>
|
|
16
|
+
<View
|
|
17
|
+
android:id="@+id/focusView"
|
|
18
|
+
android:layout_width="80dp"
|
|
19
|
+
android:layout_height="80dp"
|
|
20
|
+
android:background="@drawable/focus_box"
|
|
21
|
+
android:visibility="gone"
|
|
22
|
+
app:layout_constraintTop_toTopOf="parent"
|
|
23
|
+
app:layout_constraintStart_toStartOf="parent"/>
|
|
24
|
+
|
|
25
|
+
<ImageButton
|
|
26
|
+
android:id="@+id/torchButton"
|
|
27
|
+
android:layout_width="56dp"
|
|
28
|
+
android:layout_height="56dp"
|
|
29
|
+
android:layout_marginStart="8dp"
|
|
30
|
+
android:layout_marginEnd="24dp"
|
|
31
|
+
android:layout_marginBottom="32dp"
|
|
32
|
+
android:background="?attr/selectableItemBackgroundBorderless"
|
|
33
|
+
android:contentDescription="Toggle flash"
|
|
34
|
+
android:src="@drawable/ic_flashlight_off"
|
|
35
|
+
app:layout_constraintBottom_toBottomOf="parent"
|
|
36
|
+
app:layout_constraintEnd_toStartOf="@id/captureButton"
|
|
37
|
+
app:layout_constraintStart_toStartOf="parent" />
|
|
38
|
+
|
|
39
|
+
<ImageButton
|
|
40
|
+
android:id="@+id/captureButton"
|
|
41
|
+
android:layout_width="72dp"
|
|
42
|
+
android:layout_height="72dp"
|
|
43
|
+
android:layout_marginBottom="32dp"
|
|
44
|
+
android:background="@drawable/circle_button"
|
|
45
|
+
android:contentDescription="Capture"
|
|
46
|
+
app:layout_constraintBottom_toBottomOf="parent"
|
|
47
|
+
app:layout_constraintEnd_toEndOf="parent"
|
|
48
|
+
app:layout_constraintStart_toStartOf="parent" />
|
|
49
|
+
|
|
50
|
+
<ImageButton
|
|
51
|
+
android:id="@+id/switchCamera"
|
|
52
|
+
android:layout_width="56dp"
|
|
53
|
+
android:layout_height="56dp"
|
|
54
|
+
android:layout_marginStart="24dp"
|
|
55
|
+
android:layout_marginEnd="8dp"
|
|
56
|
+
android:layout_marginBottom="32dp"
|
|
57
|
+
android:background="?attr/selectableItemBackgroundBorderless"
|
|
58
|
+
android:contentDescription="Switch camera"
|
|
59
|
+
android:src="@drawable/ic_flip_camera"
|
|
60
|
+
app:layout_constraintBottom_toBottomOf="parent"
|
|
61
|
+
app:layout_constraintEnd_toEndOf="parent"
|
|
62
|
+
app:layout_constraintStart_toEndOf="@+id/captureButton" />
|
|
63
|
+
|
|
64
|
+
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<!-- src/main/res/values/styles.xml -->
|
|
2
|
+
<resources>
|
|
3
|
+
<!-- A no-action-bar theme for your camera -->
|
|
4
|
+
<style name="CameraTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
|
5
|
+
<!-- if you want full-screen preview, you can add -->
|
|
6
|
+
<item name="android:windowFullscreen">true</item>
|
|
7
|
+
</style>
|
|
8
|
+
</resources>
|