scoplan.camera 1.2.5 → 1.2.9
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/.github/instructions/snyk_rules.instructions.md +14 -0
- package/.vscode/settings.json +3 -0
- package/package.json +1 -1
- package/plugin.xml +1 -1
- package/src/android/CCropActivity.java +17 -0
- package/src/android/CDrawActivity.java +18 -0
- package/src/android/CTextActivity.java +18 -0
- package/src/android/CameraFragment.java +242 -77
- package/src/android/ImageCameraAvailableListener.java +16 -6
- package/src/android/PhotoEditorActivity.java +19 -0
- package/src/android/PhotoEditorMesureCustomActivity.java +16 -0
- package/src/android/ScoplanCamera.java +5 -3
- package/src/android/res/layout/fragment_camera.xml +1 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
alwaysApply: true
|
|
3
|
+
always_on: true
|
|
4
|
+
trigger: always_on
|
|
5
|
+
applyTo: "**"
|
|
6
|
+
description: Snyk Security At Inception
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Project security best practices
|
|
10
|
+
|
|
11
|
+
- Always run snyk_code_scan tool for new first party code that is generated in a Snyk-supported language.
|
|
12
|
+
- If any security issues are found based on newly introduced or modified code or dependencies, attempt to fix the issues using the results context from Snyk.
|
|
13
|
+
- Rescan the code after fixing the issues to ensure that the issues were fixed and that there are no newly introduced issues.
|
|
14
|
+
- Repeat this process until no new issues are found.
|
package/package.json
CHANGED
package/plugin.xml
CHANGED
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
<framework custom="true" src="src/android/gradle/scoplanCamera.gradle" type="gradleReference" />
|
|
66
66
|
<framework src="com.google.android.material:material:1.5.0-alpha02" />
|
|
67
67
|
<framework src="com.squareup.picasso:picasso:2.8" />
|
|
68
|
-
<framework src="io.sentry:sentry-android:
|
|
68
|
+
<framework src="io.sentry:sentry-android:8.31.0" />
|
|
69
69
|
<framework src="androidx.constraintlayout:constraintlayout:2.1.4" />
|
|
70
70
|
<lib-file src="src/android/libs/ds-photo-editor-sdk-v9.aar" />
|
|
71
71
|
</platform>
|
|
@@ -2,6 +2,12 @@ package scoplan.camera;
|
|
|
2
2
|
|
|
3
3
|
import android.content.Context;
|
|
4
4
|
import android.os.Bundle;
|
|
5
|
+
import android.view.View;
|
|
6
|
+
|
|
7
|
+
import androidx.core.graphics.Insets;
|
|
8
|
+
import androidx.core.view.ViewCompat;
|
|
9
|
+
import androidx.core.view.WindowCompat;
|
|
10
|
+
import androidx.core.view.WindowInsetsCompat;
|
|
5
11
|
|
|
6
12
|
import com.dsphotoeditor.sdk.activity.DsPhotoEditorCropActivity;
|
|
7
13
|
|
|
@@ -13,5 +19,16 @@ public class CCropActivity extends DsPhotoEditorCropActivity {
|
|
|
13
19
|
int themeId = context.getResources().getIdentifier("AppTheme.NoActionBar", "style", context.getPackageName());
|
|
14
20
|
setTheme(themeId);
|
|
15
21
|
super.onCreate(savedInstanceState);
|
|
22
|
+
|
|
23
|
+
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
|
|
24
|
+
|
|
25
|
+
View rootView = findViewById(com.dsphotoeditor.sdk.R.id.ds_photo_editor_crop_root_layout);
|
|
26
|
+
if (rootView != null) {
|
|
27
|
+
ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, windowInsets) -> {
|
|
28
|
+
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
|
29
|
+
v.setPadding(insets.left, insets.top, insets.right, insets.bottom);
|
|
30
|
+
return WindowInsetsCompat.CONSUMED;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
16
33
|
}
|
|
17
34
|
}
|
|
@@ -2,6 +2,13 @@ package scoplan.camera;
|
|
|
2
2
|
|
|
3
3
|
import android.content.Context;
|
|
4
4
|
import android.os.Bundle;
|
|
5
|
+
import android.view.View;
|
|
6
|
+
|
|
7
|
+
import androidx.core.graphics.Insets;
|
|
8
|
+
import androidx.core.view.ViewCompat;
|
|
9
|
+
import androidx.core.view.WindowCompat;
|
|
10
|
+
import androidx.core.view.WindowInsetsCompat;
|
|
11
|
+
|
|
5
12
|
import com.dsphotoeditor.sdk.activity.DsPhotoEditorDrawActivity;
|
|
6
13
|
|
|
7
14
|
public class CDrawActivity extends DsPhotoEditorDrawActivity {
|
|
@@ -12,5 +19,16 @@ public class CDrawActivity extends DsPhotoEditorDrawActivity {
|
|
|
12
19
|
int themeId = context.getResources().getIdentifier("AppTheme.NoActionBar", "style", context.getPackageName());
|
|
13
20
|
setTheme(themeId);
|
|
14
21
|
super.onCreate(savedInstanceState);
|
|
22
|
+
|
|
23
|
+
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
|
|
24
|
+
|
|
25
|
+
View rootView = findViewById(com.dsphotoeditor.sdk.R.id.ds_photo_editor_draw_root_layout);
|
|
26
|
+
if (rootView != null) {
|
|
27
|
+
ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, windowInsets) -> {
|
|
28
|
+
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
|
29
|
+
v.setPadding(insets.left, insets.top, insets.right, insets.bottom);
|
|
30
|
+
return WindowInsetsCompat.CONSUMED;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
15
33
|
}
|
|
16
34
|
}
|
|
@@ -2,6 +2,13 @@ package scoplan.camera;
|
|
|
2
2
|
|
|
3
3
|
import android.content.Context;
|
|
4
4
|
import android.os.Bundle;
|
|
5
|
+
import android.view.View;
|
|
6
|
+
|
|
7
|
+
import androidx.core.graphics.Insets;
|
|
8
|
+
import androidx.core.view.ViewCompat;
|
|
9
|
+
import androidx.core.view.WindowCompat;
|
|
10
|
+
import androidx.core.view.WindowInsetsCompat;
|
|
11
|
+
|
|
5
12
|
import com.dsphotoeditor.sdk.activity.DsPhotoEditorTextActivity;
|
|
6
13
|
|
|
7
14
|
public class CTextActivity extends DsPhotoEditorTextActivity {
|
|
@@ -12,6 +19,17 @@ public class CTextActivity extends DsPhotoEditorTextActivity {
|
|
|
12
19
|
int themeId = context.getResources().getIdentifier("AppTheme.NoActionBar", "style", context.getPackageName());
|
|
13
20
|
setTheme(themeId);
|
|
14
21
|
super.onCreate(savedInstanceState);
|
|
22
|
+
|
|
23
|
+
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
|
|
24
|
+
|
|
25
|
+
View rootView = findViewById(com.dsphotoeditor.sdk.R.id.ds_photo_editor_text_sticker_root_layout);
|
|
26
|
+
if (rootView != null) {
|
|
27
|
+
ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, windowInsets) -> {
|
|
28
|
+
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
|
29
|
+
v.setPadding(insets.left, insets.top, insets.right, insets.bottom);
|
|
30
|
+
return WindowInsetsCompat.CONSUMED;
|
|
31
|
+
});
|
|
32
|
+
}
|
|
15
33
|
}
|
|
16
34
|
}
|
|
17
35
|
|
|
@@ -31,6 +31,7 @@ import androidx.activity.result.ActivityResult;
|
|
|
31
31
|
import androidx.activity.result.ActivityResultLauncher;
|
|
32
32
|
import androidx.activity.result.contract.ActivityResultContracts;
|
|
33
33
|
import androidx.annotation.NonNull;
|
|
34
|
+
import androidx.annotation.Nullable;
|
|
34
35
|
import androidx.core.app.ActivityCompat;
|
|
35
36
|
import androidx.core.view.WindowCompat;
|
|
36
37
|
import androidx.core.view.WindowInsetsControllerCompat;
|
|
@@ -41,6 +42,7 @@ import android.os.Handler;
|
|
|
41
42
|
import android.os.HandlerThread;
|
|
42
43
|
import android.util.Log;
|
|
43
44
|
import android.util.Size;
|
|
45
|
+
import android.view.ContextThemeWrapper;
|
|
44
46
|
import android.view.LayoutInflater;
|
|
45
47
|
import android.view.OrientationEventListener;
|
|
46
48
|
import android.view.Surface;
|
|
@@ -66,6 +68,7 @@ import java.util.Arrays;
|
|
|
66
68
|
import java.util.Date;
|
|
67
69
|
import java.util.List;
|
|
68
70
|
|
|
71
|
+
import capacitor.cordova.android.plugins.R;
|
|
69
72
|
import io.sentry.Sentry;
|
|
70
73
|
|
|
71
74
|
public class CameraFragment extends Fragment implements scoplan.camera.OnImageCaptureListener, View.OnClickListener {
|
|
@@ -87,7 +90,7 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
87
90
|
private OrientationEventListener orientationEventListener;
|
|
88
91
|
private CameraCaptureSession cameraCaptureSessions;
|
|
89
92
|
private CaptureRequest.Builder captureRequestBuilder;
|
|
90
|
-
private String cameraId;
|
|
93
|
+
private String cameraId = null;
|
|
91
94
|
private int CAMERA_REQUEST_PERMISSION = 5000;
|
|
92
95
|
private Handler mBackgroundHandler;
|
|
93
96
|
private HandlerThread mBackgroundThread;
|
|
@@ -101,17 +104,41 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
101
104
|
private int currentOrientation = -1;
|
|
102
105
|
private boolean flashOn = false;
|
|
103
106
|
private boolean cameraIsOpen = false;
|
|
104
|
-
|
|
107
|
+
private boolean previewReady = false;
|
|
105
108
|
private SurfaceHolder mSurfaceHolder;
|
|
106
109
|
|
|
107
110
|
private boolean surfaceAvailable = false;
|
|
111
|
+
private boolean surfaceSizeConfigured = false;
|
|
112
|
+
private Size optimalPreviewSize = null;
|
|
108
113
|
private LinearLayout cameraFrameLayout;
|
|
114
|
+
private boolean callbackAdded = false;
|
|
115
|
+
|
|
116
|
+
@Override
|
|
117
|
+
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
|
118
|
+
super.onViewCreated(view, savedInstanceState);
|
|
119
|
+
if (!callbackAdded) {
|
|
120
|
+
mSurfaceHolder.addCallback(surfaceHolderCallBack);
|
|
121
|
+
callbackAdded = true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Apply window insets to root view to handle system bars
|
|
125
|
+
androidx.core.view.ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
|
|
126
|
+
androidx.core.graphics.Insets insets = windowInsets.getInsets(androidx.core.view.WindowInsetsCompat.Type.systemBars());
|
|
127
|
+
|
|
128
|
+
// Apply padding to root view
|
|
129
|
+
v.setPadding(insets.left, insets.top, insets.right, insets.bottom);
|
|
130
|
+
|
|
131
|
+
return androidx.core.view.WindowInsetsCompat.CONSUMED;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
109
134
|
|
|
110
135
|
private final SurfaceHolder.Callback surfaceHolderCallBack = new SurfaceHolder.Callback() {
|
|
111
136
|
@Override
|
|
112
137
|
public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
|
|
113
138
|
surfaceAvailable = true;
|
|
114
|
-
|
|
139
|
+
if(!cameraIsOpen) {
|
|
140
|
+
openCamera();
|
|
141
|
+
}
|
|
115
142
|
}
|
|
116
143
|
|
|
117
144
|
@Override
|
|
@@ -121,8 +148,8 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
121
148
|
|
|
122
149
|
@Override
|
|
123
150
|
public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
|
|
124
|
-
//TODO close
|
|
125
151
|
surfaceAvailable = false;
|
|
152
|
+
surfaceSizeConfigured = false;
|
|
126
153
|
release();
|
|
127
154
|
}
|
|
128
155
|
};
|
|
@@ -132,19 +159,24 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
132
159
|
public void onOpened(@NonNull CameraDevice camera) {
|
|
133
160
|
cameraDevice = camera;
|
|
134
161
|
cameraIsOpen = true;
|
|
135
|
-
createCameraPreview
|
|
162
|
+
// Configure surface size first; surfaceChanged will trigger createCameraPreview
|
|
163
|
+
configureSurfaceSize();
|
|
136
164
|
}
|
|
137
165
|
|
|
138
166
|
@Override
|
|
139
|
-
public void onDisconnected(@NonNull CameraDevice
|
|
140
|
-
cameraDevice.close();
|
|
167
|
+
public void onDisconnected(@NonNull CameraDevice camera) {
|
|
141
168
|
cameraIsOpen = false;
|
|
169
|
+
previewReady = false;
|
|
170
|
+
surfaceSizeConfigured = false;
|
|
142
171
|
release();
|
|
143
172
|
}
|
|
144
173
|
|
|
145
174
|
@Override
|
|
146
|
-
public void onError(@NonNull CameraDevice
|
|
147
|
-
|
|
175
|
+
public void onError(@NonNull CameraDevice camera, int error) {
|
|
176
|
+
Log.e(SCOPLAN_TAG, "CameraDevice.StateCallback onError: " + error);
|
|
177
|
+
cameraIsOpen = false;
|
|
178
|
+
previewReady = false;
|
|
179
|
+
surfaceSizeConfigured = false;
|
|
148
180
|
release();
|
|
149
181
|
}
|
|
150
182
|
};
|
|
@@ -198,13 +230,29 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
198
230
|
}
|
|
199
231
|
};
|
|
200
232
|
|
|
201
|
-
this.fakeR = new FakeR(
|
|
233
|
+
this.fakeR = new FakeR(requireActivity());
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
private int findStyleResId(Context context, String styleName) {
|
|
237
|
+
// Convert dotted names (AppTheme.NoActionBar) to compiled names (AppTheme_NoActionBar)
|
|
238
|
+
String compiledName = styleName.replace('.', '_');
|
|
239
|
+
|
|
240
|
+
int resId = context.getResources().getIdentifier(
|
|
241
|
+
compiledName,
|
|
242
|
+
"style",
|
|
243
|
+
context.getPackageName()
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
return resId;
|
|
202
247
|
}
|
|
203
248
|
|
|
204
249
|
@Override
|
|
205
|
-
public View onCreateView(LayoutInflater
|
|
250
|
+
public View onCreateView(LayoutInflater outerInflater, ViewGroup container,
|
|
206
251
|
Bundle savedInstanceState) {
|
|
207
252
|
// Inflate the layout for this fragment
|
|
253
|
+
int themeId = getActivity().getResources().getIdentifier("AppTheme.fullscreen", "style", getActivity().getPackageName());
|
|
254
|
+
ContextThemeWrapper themeContext = new ContextThemeWrapper(requireActivity(), themeId);
|
|
255
|
+
LayoutInflater inflater = outerInflater.cloneInContext(themeContext);
|
|
208
256
|
View view = inflater.inflate(this.fakeR.getLayout("fragment_camera"), container, false);
|
|
209
257
|
camButton = view.findViewById(this.fakeR.getId("button_capture"));
|
|
210
258
|
zoomBar = view.findViewById(this.fakeR.getId("camera_zoom"));
|
|
@@ -217,7 +265,6 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
217
265
|
drawOn = view.findViewById(this.fakeR.getId("draw_on"));
|
|
218
266
|
assert surfaceView != null;
|
|
219
267
|
mSurfaceHolder = surfaceView.getHolder();
|
|
220
|
-
mSurfaceHolder.addCallback(surfaceHolderCallBack);
|
|
221
268
|
souche = view.findViewById(this.fakeR.getId("image_souche"));
|
|
222
269
|
cameraTopBar = view.findViewById(this.fakeR.getId("cameraTopBar"));
|
|
223
270
|
cancelBtn = view.findViewById(this.fakeR.getId("cancel"));
|
|
@@ -233,51 +280,107 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
233
280
|
validationButton.setOnClickListener(this);
|
|
234
281
|
flashBtn.setOnClickListener(this);
|
|
235
282
|
this.defineViewVisibility();
|
|
283
|
+
|
|
236
284
|
return view;
|
|
237
285
|
}
|
|
238
286
|
|
|
287
|
+
private void configureSurfaceSize() {
|
|
288
|
+
if (cameraId == null || getActivity() == null) {
|
|
289
|
+
// Can't configure yet, fall back to direct preview
|
|
290
|
+
surfaceSizeConfigured = true;
|
|
291
|
+
createCameraPreview();
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
try {
|
|
295
|
+
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
|
|
296
|
+
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
|
|
297
|
+
if (map != null) {
|
|
298
|
+
Size[] outputSizes = map.getOutputSizes(SurfaceTexture.class);
|
|
299
|
+
optimalPreviewSize = selectedPreviewSize(outputSizes);
|
|
300
|
+
if (optimalPreviewSize != null && cameraFrameLayout.getWidth() > 0) {
|
|
301
|
+
Size displaySize = calculateSurfaceSize(optimalPreviewSize);
|
|
302
|
+
getActivity().runOnUiThread(() -> {
|
|
303
|
+
if (!isAdded()) return;
|
|
304
|
+
ViewGroup.LayoutParams layoutParams = surfaceView.getLayoutParams();
|
|
305
|
+
layoutParams.width = displaySize.getWidth();
|
|
306
|
+
layoutParams.height = displaySize.getHeight();
|
|
307
|
+
surfaceView.setLayoutParams(layoutParams);
|
|
308
|
+
// Set buffer to camera native resolution
|
|
309
|
+
mSurfaceHolder.setFixedSize(optimalPreviewSize.getWidth(), optimalPreviewSize.getHeight());
|
|
310
|
+
// surfaceChanged will be called → createCameraPreview
|
|
311
|
+
surfaceSizeConfigured = true;
|
|
312
|
+
});
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
} catch (Exception e) {
|
|
317
|
+
Log.e(SCOPLAN_TAG, "Error configuring surface size", e);
|
|
318
|
+
}
|
|
319
|
+
// Fallback: proceed directly
|
|
320
|
+
surfaceSizeConfigured = true;
|
|
321
|
+
createCameraPreview();
|
|
322
|
+
}
|
|
323
|
+
|
|
239
324
|
private void createCameraPreview() {
|
|
240
|
-
if(cameraDevice == null || !surfaceAvailable)
|
|
325
|
+
if(cameraDevice == null || !surfaceAvailable || previewReady || !surfaceSizeConfigured)
|
|
241
326
|
return;
|
|
242
327
|
if(!cameraIsOpen) {
|
|
243
328
|
this.openCamera();
|
|
329
|
+
return;
|
|
244
330
|
}
|
|
331
|
+
previewReady = true;
|
|
245
332
|
try{
|
|
333
|
+
// Close any existing session before creating a new one
|
|
334
|
+
closeSession();
|
|
335
|
+
|
|
246
336
|
Surface surface = mSurfaceHolder.getSurface();
|
|
247
337
|
captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
|
|
248
338
|
captureRequestBuilder.addTarget(surface);
|
|
249
339
|
cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
|
|
250
340
|
@Override
|
|
251
341
|
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
|
|
252
|
-
if(cameraDevice == null)
|
|
342
|
+
if(cameraDevice == null) {
|
|
343
|
+
previewReady = false;
|
|
253
344
|
return;
|
|
345
|
+
}
|
|
254
346
|
cameraCaptureSessions = cameraCaptureSession;
|
|
255
347
|
updatePreview();
|
|
256
348
|
}
|
|
257
349
|
|
|
258
350
|
@Override
|
|
259
351
|
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
|
|
260
|
-
|
|
352
|
+
Log.e(SCOPLAN_TAG, "onConfigureFailed for preview session");
|
|
353
|
+
Sentry.captureMessage("onConfigureFailed: " + cameraCaptureSession.toString());
|
|
354
|
+
previewReady = false;
|
|
355
|
+
failedCapture();
|
|
261
356
|
}
|
|
262
|
-
},
|
|
357
|
+
}, mBackgroundHandler);
|
|
263
358
|
} catch (Exception e) {
|
|
359
|
+
Log.e(SCOPLAN_TAG, "Error creating camera preview", e);
|
|
264
360
|
Sentry.captureException(e);
|
|
361
|
+
previewReady = false;
|
|
265
362
|
this.failedCapture();
|
|
266
363
|
}
|
|
267
364
|
}
|
|
268
365
|
|
|
269
366
|
private void openCamera() {
|
|
270
367
|
try{
|
|
368
|
+
if (cameraId != null ) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
271
371
|
for (String id : manager.getCameraIdList()) {
|
|
272
372
|
CameraCharacteristics cameraCharacteristics =
|
|
273
373
|
manager.getCameraCharacteristics(id);
|
|
274
|
-
if (cameraCharacteristics.get(
|
|
374
|
+
if (cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) ==
|
|
275
375
|
CameraCharacteristics.LENS_FACING_BACK) {
|
|
276
376
|
cameraId = id;
|
|
277
377
|
break;
|
|
278
378
|
}
|
|
279
379
|
}
|
|
280
|
-
|
|
380
|
+
// Fallback to first camera only if no back camera was found
|
|
381
|
+
if (cameraId == null) {
|
|
382
|
+
cameraId = manager.getCameraIdList()[0];
|
|
383
|
+
}
|
|
281
384
|
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
|
|
282
385
|
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
|
|
283
386
|
assert map != null;
|
|
@@ -310,28 +413,9 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
310
413
|
}
|
|
311
414
|
|
|
312
415
|
private void updatePreview() {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
try{
|
|
317
|
-
CameraCharacteristics cameraCharacteristics =
|
|
318
|
-
manager.getCameraCharacteristics(cameraId);
|
|
319
|
-
StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
|
|
320
|
-
if(map != null) {
|
|
321
|
-
Size[] outputSizes = map.getOutputSizes(SurfaceTexture.class);
|
|
322
|
-
Size preferredSize = selectedPreviewSize(outputSizes);
|
|
323
|
-
if(preferredSize != null) {
|
|
324
|
-
ViewGroup.LayoutParams layoutParams = surfaceView.getLayoutParams();
|
|
325
|
-
Size surfaceSize = calculateSurfaceSize(preferredSize);
|
|
326
|
-
getActivity().runOnUiThread(() -> {
|
|
327
|
-
layoutParams.width = surfaceSize.getWidth();
|
|
328
|
-
layoutParams.height = surfaceSize.getHeight();
|
|
329
|
-
mSurfaceHolder.setFixedSize(surfaceSize.getWidth(), surfaceSize.getHeight());
|
|
330
|
-
surfaceView.setLayoutParams(layoutParams);
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(),null, mBackgroundHandler);
|
|
416
|
+
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
|
|
417
|
+
try {
|
|
418
|
+
cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
|
|
335
419
|
this.cameraSeekBarListener = new scoplan.camera.CameraSeekBarListener(cameraId, manager, zoomBar, captureRequestBuilder, cameraCaptureSessions, mBackgroundHandler);
|
|
336
420
|
} catch (Exception e) {
|
|
337
421
|
Sentry.captureException(e);
|
|
@@ -341,23 +425,54 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
341
425
|
|
|
342
426
|
private Size calculateSurfaceSize(Size selectedSize) {
|
|
343
427
|
int parentWidth = this.cameraFrameLayout.getWidth();
|
|
344
|
-
|
|
428
|
+
int parentHeight = this.cameraFrameLayout.getHeight();
|
|
429
|
+
|
|
430
|
+
// Camera sensor is landscape, but we display in portrait → swap W/H
|
|
431
|
+
float previewAspectRatio = (float) selectedSize.getHeight() / selectedSize.getWidth();
|
|
345
432
|
|
|
346
|
-
|
|
433
|
+
// Center-crop: fill the entire parent, crop overflow (no distortion)
|
|
434
|
+
int surfaceWidth, surfaceHeight;
|
|
435
|
+
int fitWidth = parentWidth;
|
|
436
|
+
int fitHeight = (int) (parentWidth / previewAspectRatio);
|
|
437
|
+
|
|
438
|
+
if (fitHeight >= parentHeight) {
|
|
439
|
+
// Fit by width already fills the height — use it
|
|
440
|
+
surfaceWidth = fitWidth;
|
|
441
|
+
surfaceHeight = fitHeight;
|
|
442
|
+
} else {
|
|
443
|
+
// Fit by height and let width overflow
|
|
444
|
+
surfaceHeight = parentHeight;
|
|
445
|
+
surfaceWidth = (int) (parentHeight * previewAspectRatio);
|
|
446
|
+
}
|
|
347
447
|
|
|
348
|
-
|
|
349
|
-
return new Size(parentWidth, height);
|
|
448
|
+
return new Size(surfaceWidth, surfaceHeight);
|
|
350
449
|
}
|
|
351
450
|
|
|
352
451
|
private Size selectedPreviewSize(Size[] outputSizes) {
|
|
353
|
-
|
|
354
|
-
|
|
452
|
+
// Target 4:3 aspect ratio (landscape sensor: width > height, so 4/3 ≈ 1.333)
|
|
453
|
+
float targetAspectRatio = 4f / 3f;
|
|
355
454
|
Size selectedSize = null;
|
|
455
|
+
int bestArea = 0;
|
|
456
|
+
|
|
356
457
|
for (Size size : outputSizes) {
|
|
357
458
|
float aspectRatio = (float) size.getWidth() / size.getHeight();
|
|
358
|
-
if (Math.abs(aspectRatio - targetAspectRatio) < 0.
|
|
359
|
-
|
|
360
|
-
|
|
459
|
+
if (Math.abs(aspectRatio - targetAspectRatio) < 0.05) {
|
|
460
|
+
// Among matching ratios, pick the largest for best quality
|
|
461
|
+
int area = size.getWidth() * size.getHeight();
|
|
462
|
+
if (area > bestArea) {
|
|
463
|
+
bestArea = area;
|
|
464
|
+
selectedSize = size;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Fallback: if no 4:3, pick the largest size available
|
|
470
|
+
if (selectedSize == null && outputSizes.length > 0) {
|
|
471
|
+
selectedSize = outputSizes[0];
|
|
472
|
+
for (Size size : outputSizes) {
|
|
473
|
+
if (size.getWidth() * size.getHeight() > selectedSize.getWidth() * selectedSize.getHeight()) {
|
|
474
|
+
selectedSize = size;
|
|
475
|
+
}
|
|
361
476
|
}
|
|
362
477
|
}
|
|
363
478
|
return selectedSize;
|
|
@@ -367,23 +482,22 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
367
482
|
public void onResume() {
|
|
368
483
|
super.onResume();
|
|
369
484
|
startBackgroundThread();
|
|
370
|
-
if(surfaceAvailable)
|
|
485
|
+
if(surfaceAvailable && !cameraIsOpen) {
|
|
371
486
|
openCamera();
|
|
372
|
-
else {
|
|
373
|
-
mSurfaceHolder.addCallback(surfaceHolderCallBack);
|
|
374
487
|
}
|
|
375
488
|
this.orientationEventListener.enable();
|
|
376
489
|
|
|
377
490
|
Window window = requireActivity().getWindow();
|
|
378
491
|
|
|
492
|
+
// Enable edge-to-edge mode but keep system bars visible
|
|
493
|
+
WindowCompat.setDecorFitsSystemWindows(window, false);
|
|
494
|
+
|
|
379
495
|
WindowInsetsControllerCompat controller =
|
|
380
496
|
WindowCompat.getInsetsController(window, window.getDecorView());
|
|
381
497
|
|
|
382
498
|
if (controller != null) {
|
|
383
|
-
|
|
384
|
-
controller.
|
|
385
|
-
WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
|
386
|
-
);
|
|
499
|
+
// Show status and navigation bars
|
|
500
|
+
controller.show(WindowInsets.Type.systemBars());
|
|
387
501
|
}
|
|
388
502
|
}
|
|
389
503
|
|
|
@@ -393,11 +507,15 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
393
507
|
super.onPause();
|
|
394
508
|
this.orientationEventListener.disable();
|
|
395
509
|
Window window = requireActivity().getWindow();
|
|
510
|
+
|
|
511
|
+
// Restore normal window mode when leaving camera
|
|
512
|
+
WindowCompat.setDecorFitsSystemWindows(window, true);
|
|
513
|
+
|
|
396
514
|
WindowInsetsControllerCompat controller =
|
|
397
515
|
WindowCompat.getInsetsController(window, window.getDecorView());
|
|
398
516
|
|
|
399
517
|
if (controller != null) {
|
|
400
|
-
controller.show(WindowInsets.Type.
|
|
518
|
+
controller.show(WindowInsets.Type.systemBars());
|
|
401
519
|
}
|
|
402
520
|
release();
|
|
403
521
|
}
|
|
@@ -408,23 +526,44 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
408
526
|
release();
|
|
409
527
|
}
|
|
410
528
|
|
|
529
|
+
private void closeSession() {
|
|
530
|
+
if(cameraCaptureSessions != null) {
|
|
531
|
+
try {
|
|
532
|
+
cameraCaptureSessions.close();
|
|
533
|
+
} catch (Exception e) {
|
|
534
|
+
Log.e(SCOPLAN_TAG, "Error closing capture session", e);
|
|
535
|
+
}
|
|
536
|
+
cameraCaptureSessions = null;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
411
540
|
private void release() {
|
|
541
|
+
closeSession();
|
|
412
542
|
if(cameraDevice != null) {
|
|
413
|
-
|
|
543
|
+
try {
|
|
544
|
+
cameraDevice.close();
|
|
545
|
+
} catch (Exception e) {
|
|
546
|
+
Log.e(SCOPLAN_TAG, "Error closing camera device", e);
|
|
547
|
+
}
|
|
414
548
|
cameraIsOpen = false;
|
|
549
|
+
previewReady = false;
|
|
415
550
|
cameraDevice = null;
|
|
551
|
+
cameraId = null;
|
|
416
552
|
}
|
|
417
553
|
}
|
|
418
554
|
|
|
419
555
|
private void stopBackgroundThread() {
|
|
556
|
+
if (mBackgroundThread == null) {
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
420
559
|
mBackgroundThread.quitSafely();
|
|
421
560
|
try{
|
|
422
561
|
mBackgroundThread.join();
|
|
423
|
-
mBackgroundThread= null;
|
|
424
|
-
mBackgroundHandler = null;
|
|
425
562
|
} catch (InterruptedException e) {
|
|
426
|
-
e
|
|
563
|
+
Log.e(SCOPLAN_TAG, "Error stopping background thread", e);
|
|
427
564
|
}
|
|
565
|
+
mBackgroundThread = null;
|
|
566
|
+
mBackgroundHandler = null;
|
|
428
567
|
}
|
|
429
568
|
|
|
430
569
|
private void startBackgroundThread() {
|
|
@@ -442,15 +581,18 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
442
581
|
}
|
|
443
582
|
|
|
444
583
|
private void takePicture() {
|
|
584
|
+
if(getContext() == null) {
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
445
587
|
if(this.pictureCount >= this.photoLimit){
|
|
446
588
|
Toast toast = Toast.makeText(this.getContext(), "La prise de photos est limitée à " + this.photoLimit + " par envoi", Toast.LENGTH_SHORT);
|
|
447
589
|
toast.show();
|
|
448
590
|
return;
|
|
449
591
|
}
|
|
450
|
-
if(this.mBackgroundThread == null || !this.mBackgroundThread.
|
|
592
|
+
if(this.mBackgroundThread == null || !this.mBackgroundThread.isAlive()) {
|
|
451
593
|
this.startBackgroundThread();
|
|
452
594
|
}
|
|
453
|
-
if(cameraDevice == null) {
|
|
595
|
+
if(cameraDevice == null || cameraId == null) {
|
|
454
596
|
return;
|
|
455
597
|
}
|
|
456
598
|
this.pictureCount++;
|
|
@@ -459,9 +601,12 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
459
601
|
try {
|
|
460
602
|
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
|
|
461
603
|
Size[] jpegSizes = null;
|
|
462
|
-
if(characteristics != null)
|
|
463
|
-
|
|
464
|
-
|
|
604
|
+
if(characteristics != null) {
|
|
605
|
+
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
|
|
606
|
+
if (map != null) {
|
|
607
|
+
jpegSizes = map.getOutputSizes(ImageFormat.JPEG);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
465
610
|
//Capture image with custom size
|
|
466
611
|
int width = 640;
|
|
467
612
|
int height = 480;
|
|
@@ -470,7 +615,7 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
470
615
|
width = jpegSizes[0].getWidth();
|
|
471
616
|
height = jpegSizes[0].getHeight();
|
|
472
617
|
}
|
|
473
|
-
final ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG,1);
|
|
618
|
+
final ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
|
|
474
619
|
List<Surface> outputSurface = new ArrayList<>(2);
|
|
475
620
|
outputSurface.add(reader.getSurface());
|
|
476
621
|
outputSurface.add(mSurfaceHolder.getSurface());
|
|
@@ -480,7 +625,7 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
480
625
|
captureBuilder.set(CaptureRequest.FLASH_MODE, flashOn ? CaptureRequest.FLASH_MODE_TORCH : CaptureRequest.FLASH_MODE_OFF);
|
|
481
626
|
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
|
482
627
|
String fileName = "IMG_"+ timeStamp + ".jpg";
|
|
483
|
-
File file = new File(
|
|
628
|
+
File file = new File(this.getContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES), fileName);
|
|
484
629
|
ImageReader.OnImageAvailableListener readerListener = new scoplan.camera.ImageCameraAvailableListener(file, reader, this, currentOrientation);
|
|
485
630
|
|
|
486
631
|
reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);
|
|
@@ -488,14 +633,18 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
488
633
|
@Override
|
|
489
634
|
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
|
|
490
635
|
super.onCaptureCompleted(session, request, result);
|
|
636
|
+
reader.close();
|
|
637
|
+
previewReady = false;
|
|
491
638
|
createCameraPreview();
|
|
492
639
|
}
|
|
493
640
|
|
|
494
641
|
@Override
|
|
495
642
|
public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
|
|
496
643
|
super.onCaptureFailed(session, request, failure);
|
|
644
|
+
reader.close();
|
|
497
645
|
Sentry.captureMessage("Failed capture _" + failure.getReason());
|
|
498
646
|
Log.e(SCOPLAN_TAG, "Error FAILED Capture " + failure.getReason());
|
|
647
|
+
pictureCount--;
|
|
499
648
|
failedCapture();
|
|
500
649
|
}
|
|
501
650
|
};
|
|
@@ -508,43 +657,59 @@ public class CameraFragment extends Fragment implements scoplan.camera.OnImageCa
|
|
|
508
657
|
} catch (Exception e) {
|
|
509
658
|
Log.e(SCOPLAN_TAG, "Error - " + e.getMessage());
|
|
510
659
|
Sentry.captureException(e);
|
|
660
|
+
reader.close();
|
|
661
|
+
pictureCount--;
|
|
511
662
|
failedCapture();
|
|
512
663
|
}
|
|
513
664
|
}
|
|
514
665
|
|
|
515
666
|
@Override
|
|
516
667
|
public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
|
|
517
|
-
Log.e(SCOPLAN_TAG, "Error FAILED Configuration ");
|
|
518
|
-
Sentry.captureMessage("Failed configure
|
|
668
|
+
Log.e(SCOPLAN_TAG, "Error FAILED Configuration for capture session");
|
|
669
|
+
Sentry.captureMessage("Failed configure capture session");
|
|
670
|
+
reader.close();
|
|
671
|
+
pictureCount--;
|
|
519
672
|
failedCapture();
|
|
520
673
|
}
|
|
521
674
|
}, mBackgroundHandler);
|
|
522
675
|
|
|
523
676
|
} catch (Exception e) {
|
|
677
|
+
Log.e(SCOPLAN_TAG, "Error in takePicture", e);
|
|
524
678
|
Sentry.captureException(e);
|
|
525
|
-
|
|
679
|
+
pictureCount--;
|
|
680
|
+
failedCapture();
|
|
526
681
|
}
|
|
527
682
|
}
|
|
528
683
|
|
|
529
684
|
@Override
|
|
530
685
|
public void onImageCapture(File file, Bitmap bitmap) {
|
|
531
686
|
pictures.add(file.getAbsolutePath());
|
|
532
|
-
getActivity()
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
687
|
+
if (getActivity() != null && isAdded()) {
|
|
688
|
+
getActivity().runOnUiThread(() -> {
|
|
689
|
+
if (isAdded()) {
|
|
690
|
+
souche.setImageBitmap(bitmap);
|
|
691
|
+
defineViewVisibility();
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
}
|
|
536
695
|
}
|
|
537
696
|
|
|
538
697
|
@Override
|
|
539
698
|
public void onImageBuildFailed(Exception e) {
|
|
540
699
|
Sentry.captureException(e);
|
|
700
|
+
pictureCount--;
|
|
541
701
|
failedCapture();
|
|
542
702
|
}
|
|
543
703
|
|
|
544
704
|
public void failedCapture() {
|
|
545
|
-
|
|
546
|
-
|
|
705
|
+
if (getActivity() == null || !isAdded()) {
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
547
708
|
getActivity().runOnUiThread(() -> {
|
|
709
|
+
if (!isAdded() || getContext() == null) {
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
Toast.makeText(getContext(), "Oups! une erreur pendant la capture. Veuillez rééssayer.", Toast.LENGTH_LONG).show();
|
|
548
713
|
defineViewVisibility();
|
|
549
714
|
});
|
|
550
715
|
}
|
|
@@ -29,33 +29,43 @@ public class ImageCameraAvailableListener implements ImageReader.OnImageAvailabl
|
|
|
29
29
|
Image image = null;
|
|
30
30
|
try{
|
|
31
31
|
image = reader.acquireLatestImage();
|
|
32
|
+
if (image == null) {
|
|
33
|
+
this.imageCaptureListener.onImageBuildFailed(new IOException("Failed to acquire image"));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
32
36
|
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
|
|
33
37
|
byte[] bytes = new byte[buffer.capacity()];
|
|
34
38
|
buffer.get(bytes);
|
|
35
39
|
this.imageCaptureListener.onImageCapture(file, save(bytes));
|
|
36
40
|
}
|
|
37
|
-
catch (
|
|
41
|
+
catch (Exception e)
|
|
38
42
|
{
|
|
39
43
|
e.printStackTrace();
|
|
40
44
|
this.imageCaptureListener.onImageBuildFailed(e);
|
|
41
45
|
}
|
|
42
46
|
finally {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
image.close();
|
|
46
|
-
}
|
|
47
|
+
if(image != null)
|
|
48
|
+
image.close();
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
private Bitmap save(byte[] bytes) throws IOException {
|
|
51
53
|
OutputStream outputStream = null;
|
|
54
|
+
Bitmap bmp = null;
|
|
52
55
|
try{
|
|
53
56
|
outputStream = new FileOutputStream(file);
|
|
54
|
-
|
|
57
|
+
bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
|
|
58
|
+
if (bmp == null) {
|
|
59
|
+
throw new IOException("Failed to decode image bytes");
|
|
60
|
+
}
|
|
55
61
|
Matrix matrix = new Matrix();
|
|
56
62
|
matrix.setRotate(this.rotation);
|
|
57
63
|
Bitmap rotatedBitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
|
|
58
64
|
rotatedBitmap.compress(Bitmap.CompressFormat.JPEG, 65, outputStream);
|
|
65
|
+
// Recycle original bitmap only if rotation created a new one
|
|
66
|
+
if (rotatedBitmap != bmp) {
|
|
67
|
+
bmp.recycle();
|
|
68
|
+
}
|
|
59
69
|
return rotatedBitmap;
|
|
60
70
|
} finally {
|
|
61
71
|
if(outputStream != null)
|
|
@@ -13,6 +13,11 @@ import android.widget.FrameLayout;
|
|
|
13
13
|
import android.widget.RelativeLayout;
|
|
14
14
|
import android.widget.Toast;
|
|
15
15
|
|
|
16
|
+
import androidx.core.graphics.Insets;
|
|
17
|
+
import androidx.core.view.ViewCompat;
|
|
18
|
+
import androidx.core.view.WindowCompat;
|
|
19
|
+
import androidx.core.view.WindowInsetsCompat;
|
|
20
|
+
|
|
16
21
|
import com.dsphotoeditor.sdk.activity.DsPhotoEditorActivity;
|
|
17
22
|
|
|
18
23
|
import java.io.File;
|
|
@@ -28,6 +33,10 @@ public class PhotoEditorActivity extends DsPhotoEditorActivity {
|
|
|
28
33
|
int themeId = context.getResources().getIdentifier("AppTheme.NoActionBar", "style", context.getPackageName());
|
|
29
34
|
setTheme(themeId);
|
|
30
35
|
super.onCreate(savedInstanceState);
|
|
36
|
+
|
|
37
|
+
// Enable edge-to-edge and handle system bars
|
|
38
|
+
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
|
|
39
|
+
|
|
31
40
|
this.fakeR = new FakeR(this);
|
|
32
41
|
this.e = this.getIntent().getData();
|
|
33
42
|
if (this.e == null) {
|
|
@@ -36,6 +45,16 @@ public class PhotoEditorActivity extends DsPhotoEditorActivity {
|
|
|
36
45
|
} else {
|
|
37
46
|
this.createBottomBar(savedInstanceState);
|
|
38
47
|
}
|
|
48
|
+
|
|
49
|
+
// Apply window insets to root layout
|
|
50
|
+
View rootView = findViewById(fakeR.getId("ds_photo_editor_root_layout"));
|
|
51
|
+
if (rootView != null) {
|
|
52
|
+
ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, windowInsets) -> {
|
|
53
|
+
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
|
54
|
+
v.setPadding(insets.left, insets.top, insets.right, insets.bottom);
|
|
55
|
+
return WindowInsetsCompat.CONSUMED;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
39
58
|
}
|
|
40
59
|
|
|
41
60
|
@SuppressLint("ResourceType")
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
package scoplan.camera;
|
|
2
2
|
|
|
3
3
|
import androidx.core.content.ContextCompat;
|
|
4
|
+
import androidx.core.graphics.Insets;
|
|
5
|
+
import androidx.core.view.ViewCompat;
|
|
6
|
+
import androidx.core.view.WindowCompat;
|
|
7
|
+
import androidx.core.view.WindowInsetsCompat;
|
|
4
8
|
|
|
5
9
|
import android.app.AlertDialog;
|
|
6
10
|
import android.content.Context;
|
|
@@ -53,6 +57,18 @@ public class PhotoEditorMesureCustomActivity extends DsPhotoEditorTextActivity i
|
|
|
53
57
|
super.onCreate(var1);
|
|
54
58
|
this.fakeR = new FakeR(this);
|
|
55
59
|
this.setContentView(com.dsphotoeditor.sdk.R.layout.activity_ds_photo_editor_sticker_text);
|
|
60
|
+
|
|
61
|
+
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
|
|
62
|
+
|
|
63
|
+
View rootView = findViewById(com.dsphotoeditor.sdk.R.id.ds_photo_editor_text_sticker_root_layout);
|
|
64
|
+
if (rootView != null) {
|
|
65
|
+
ViewCompat.setOnApplyWindowInsetsListener(rootView, (v, windowInsets) -> {
|
|
66
|
+
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
|
67
|
+
v.setPadding(insets.left, insets.top, insets.right, insets.bottom);
|
|
68
|
+
return WindowInsetsCompat.CONSUMED;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
56
72
|
if (original != null && !original.isRecycled()) {
|
|
57
73
|
this.a();
|
|
58
74
|
this.b();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package scoplan.camera;
|
|
2
2
|
|
|
3
|
+
import android.content.Context;
|
|
3
4
|
import android.content.pm.ActivityInfo;
|
|
4
5
|
import android.widget.FrameLayout;
|
|
5
6
|
|
|
@@ -38,20 +39,21 @@ public class ScoplanCamera extends CordovaPlugin implements CameraEventListener
|
|
|
38
39
|
|
|
39
40
|
private void takePictures(int limit, int currentCount) {
|
|
40
41
|
cordova.getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
|
41
|
-
CameraEventListener cameraEventListener = this;
|
|
42
|
+
scoplan.camera.CameraEventListener cameraEventListener = this;
|
|
42
43
|
cordova.getActivity().runOnUiThread(new Runnable() {
|
|
43
44
|
@Override
|
|
44
45
|
public void run() {
|
|
45
46
|
containerView = (FrameLayout)cordova.getActivity().findViewById(containerViewId);
|
|
46
47
|
if(containerView == null){
|
|
47
|
-
|
|
48
|
+
Context context = cordova.getActivity();
|
|
49
|
+
containerView = new FrameLayout(context);
|
|
48
50
|
containerView.setId(containerViewId);
|
|
49
51
|
FrameLayout.LayoutParams containerLayoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
|
|
50
52
|
cordova.getActivity().addContentView(containerView, containerLayoutParams);
|
|
51
53
|
//add the fragment to the container
|
|
52
54
|
}
|
|
53
55
|
containerView.setClickable(true);
|
|
54
|
-
cameraFragment = new CameraFragment();
|
|
56
|
+
cameraFragment = new scoplan.camera.CameraFragment();
|
|
55
57
|
if(currentCount > 0){
|
|
56
58
|
cameraFragment.setCurrentCount(currentCount);
|
|
57
59
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
3
3
|
android:layout_width="match_parent"
|
|
4
4
|
android:layout_height="match_parent"
|
|
5
|
-
android:background="
|
|
5
|
+
android:background="#000000">
|
|
6
6
|
<LinearLayout
|
|
7
7
|
android:id="@+id/camera_frame_layout"
|
|
8
8
|
android:layout_width="match_parent"
|