@capgo/camera-preview 3.6.23 → 5.0.0
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/README.md +67 -405
- package/android/build.gradle +8 -7
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +1 -1
- package/android/gradle.properties +1 -1
- package/android/gradlew +2 -2
- package/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java +6 -6
- package/android/src/main/AndroidManifest.xml +1 -1
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java +1105 -854
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +543 -428
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomSurfaceView.java +15 -10
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomTextureView.java +31 -21
- package/android/src/main/java/com/ahm/capacitor/camera/preview/Preview.java +386 -332
- package/android/src/main/java/com/ahm/capacitor/camera/preview/TapGestureDetector.java +13 -13
- package/android/src/test/java/com/getcapacitor/ExampleUnitTest.java +4 -4
- package/dist/docs.json +208 -37
- package/dist/esm/definitions.d.ts +76 -3
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +4 -4
- package/dist/esm/web.d.ts +2 -2
- package/dist/esm/web.js +39 -36
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +39 -36
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +39 -36
- package/dist/plugin.js.map +1 -1
- package/ios/Plugin/CameraController.swift +1 -1
- package/ios/Plugin/Plugin.swift +1 -1
- package/ios/Podfile.lock +3 -3
- package/package.json +22 -22
- package/android/.gradle/7.6/checksums/checksums.lock +0 -0
- package/android/.gradle/7.6/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/7.6/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/7.6/dependencies-accessors/dependencies-accessors.lock +0 -0
- package/android/.gradle/7.6/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/7.6/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/7.6/fileChanges/last-build.bin +0 -0
- package/android/.gradle/7.6/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/7.6/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
- package/android/.gradle/vcs-1/gc.properties +0 -0
|
@@ -48,953 +48,1204 @@ import java.util.UUID;
|
|
|
48
48
|
|
|
49
49
|
public class CameraActivity extends Fragment {
|
|
50
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
|
-
|
|
51
|
+
public interface CameraPreviewListener {
|
|
52
|
+
void onPictureTaken(String originalPicture);
|
|
53
|
+
void onPictureTakenError(String message);
|
|
54
|
+
void onSnapshotTaken(String originalPicture);
|
|
55
|
+
void onSnapshotTakenError(String message);
|
|
56
|
+
void onFocusSet(int pointX, int pointY);
|
|
57
|
+
void onFocusSetError(String message);
|
|
58
|
+
void onBackButton();
|
|
59
|
+
void onCameraStarted();
|
|
60
|
+
void onStartRecordVideo();
|
|
61
|
+
void onStartRecordVideoError(String message);
|
|
62
|
+
void onStopRecordVideo(String file);
|
|
63
|
+
void onStopRecordVideoError(String error);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private CameraPreviewListener eventListener;
|
|
67
|
+
private static final String TAG = "CameraActivity";
|
|
68
|
+
public FrameLayout mainLayout;
|
|
69
|
+
public FrameLayout frameContainerLayout;
|
|
70
|
+
|
|
71
|
+
private Preview mPreview;
|
|
72
|
+
private boolean canTakePicture = true;
|
|
73
|
+
|
|
74
|
+
private View view;
|
|
75
|
+
private Camera.Parameters cameraParameters;
|
|
76
|
+
private Camera mCamera;
|
|
77
|
+
private int numberOfCameras;
|
|
78
|
+
private int cameraCurrentlyLocked;
|
|
79
|
+
private int currentQuality;
|
|
80
|
+
|
|
81
|
+
private enum RecordingState {
|
|
82
|
+
INITIALIZING,
|
|
83
|
+
STARTED,
|
|
84
|
+
STOPPED,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private RecordingState mRecordingState = RecordingState.INITIALIZING;
|
|
88
|
+
private MediaRecorder mRecorder = null;
|
|
89
|
+
private String recordFilePath;
|
|
90
|
+
private float opacity;
|
|
91
|
+
|
|
92
|
+
// The first rear facing camera
|
|
93
|
+
private int defaultCameraId;
|
|
94
|
+
public String defaultCamera;
|
|
95
|
+
public boolean tapToTakePicture;
|
|
96
|
+
public boolean dragEnabled;
|
|
97
|
+
public boolean tapToFocus;
|
|
98
|
+
public boolean disableExifHeaderStripping;
|
|
99
|
+
public boolean storeToFile;
|
|
100
|
+
public boolean toBack;
|
|
101
|
+
public boolean enableOpacity = false;
|
|
102
|
+
public boolean enableZoom = false;
|
|
103
|
+
|
|
104
|
+
public int width;
|
|
105
|
+
public int height;
|
|
106
|
+
public int x;
|
|
107
|
+
public int y;
|
|
108
|
+
|
|
109
|
+
public void setEventListener(CameraPreviewListener listener) {
|
|
110
|
+
eventListener = listener;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private String appResourcesPackage;
|
|
114
|
+
|
|
115
|
+
@Override
|
|
116
|
+
public View onCreateView(
|
|
117
|
+
LayoutInflater inflater,
|
|
118
|
+
ViewGroup container,
|
|
119
|
+
Bundle savedInstanceState
|
|
120
|
+
) {
|
|
121
|
+
appResourcesPackage = getActivity().getPackageName();
|
|
122
|
+
|
|
123
|
+
// Inflate the layout for this fragment
|
|
124
|
+
view =
|
|
125
|
+
inflater.inflate(
|
|
126
|
+
getResources()
|
|
127
|
+
.getIdentifier("camera_activity", "layout", appResourcesPackage),
|
|
128
|
+
container,
|
|
129
|
+
false
|
|
130
|
+
);
|
|
131
|
+
createCameraPreview();
|
|
132
|
+
return view;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public void setRect(int x, int y, int width, int height) {
|
|
136
|
+
this.x = x;
|
|
137
|
+
this.y = y;
|
|
138
|
+
this.width = width;
|
|
139
|
+
this.height = height;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private void createCameraPreview() {
|
|
143
|
+
if (mPreview == null) {
|
|
144
|
+
setDefaultCameraId();
|
|
145
|
+
|
|
146
|
+
//set box position and size
|
|
147
|
+
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
|
|
148
|
+
width,
|
|
149
|
+
height
|
|
150
|
+
);
|
|
151
|
+
layoutParams.setMargins(x, y, 0, 0);
|
|
152
|
+
frameContainerLayout =
|
|
153
|
+
(FrameLayout) view.findViewById(
|
|
154
|
+
getResources()
|
|
155
|
+
.getIdentifier("frame_container", "id", appResourcesPackage)
|
|
156
|
+
);
|
|
157
|
+
frameContainerLayout.setLayoutParams(layoutParams);
|
|
151
158
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
159
|
+
//video view
|
|
160
|
+
mPreview = new Preview(getActivity(), enableOpacity);
|
|
161
|
+
mainLayout =
|
|
162
|
+
(FrameLayout) view.findViewById(
|
|
163
|
+
getResources().getIdentifier("video_view", "id", appResourcesPackage)
|
|
164
|
+
);
|
|
165
|
+
mainLayout.setLayoutParams(
|
|
166
|
+
new RelativeLayout.LayoutParams(
|
|
167
|
+
RelativeLayout.LayoutParams.MATCH_PARENT,
|
|
168
|
+
RelativeLayout.LayoutParams.MATCH_PARENT
|
|
169
|
+
)
|
|
170
|
+
);
|
|
171
|
+
mainLayout.addView(mPreview);
|
|
172
|
+
mainLayout.setEnabled(false);
|
|
173
|
+
|
|
174
|
+
if (enableZoom) {
|
|
175
|
+
this.setupTouchAndBackButton();
|
|
176
|
+
}
|
|
156
177
|
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private void setupTouchAndBackButton() {
|
|
181
|
+
final GestureDetector gestureDetector = new GestureDetector(
|
|
182
|
+
getActivity().getApplicationContext(),
|
|
183
|
+
new TapGestureDetector()
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
getActivity()
|
|
187
|
+
.runOnUiThread(
|
|
188
|
+
new Runnable() {
|
|
189
|
+
@Override
|
|
190
|
+
public void run() {
|
|
191
|
+
frameContainerLayout.setClickable(true);
|
|
192
|
+
frameContainerLayout.setOnTouchListener(
|
|
193
|
+
new View.OnTouchListener() {
|
|
194
|
+
private int mLastTouchX;
|
|
195
|
+
private int mLastTouchY;
|
|
196
|
+
private int mPosX = 0;
|
|
197
|
+
private int mPosY = 0;
|
|
157
198
|
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
takePicture(0, 0, 85);
|
|
208
|
-
} else if (tapToFocus) {
|
|
209
|
-
setFocusArea(
|
|
210
|
-
(int) event.getX(0),
|
|
211
|
-
(int) event.getY(0),
|
|
212
|
-
new Camera.AutoFocusCallback() {
|
|
213
|
-
public void onAutoFocus(boolean success, Camera camera) {
|
|
214
|
-
if (success) {
|
|
215
|
-
// A callback to JS might make sense here.
|
|
216
|
-
} else {
|
|
217
|
-
Log.d(TAG, "onTouch:" + " setFocusArea() did not suceed");
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
return true;
|
|
224
|
-
} else {
|
|
225
|
-
if (dragEnabled) {
|
|
226
|
-
int x;
|
|
227
|
-
int y;
|
|
228
|
-
|
|
229
|
-
switch (event.getAction()) {
|
|
230
|
-
case MotionEvent.ACTION_DOWN:
|
|
231
|
-
if (mLastTouchX == 0 || mLastTouchY == 0) {
|
|
232
|
-
mLastTouchX = (int) event.getRawX() - layoutParams.leftMargin;
|
|
233
|
-
mLastTouchY = (int) event.getRawY() - layoutParams.topMargin;
|
|
234
|
-
} else {
|
|
235
|
-
mLastTouchX = (int) event.getRawX();
|
|
236
|
-
mLastTouchY = (int) event.getRawY();
|
|
237
|
-
}
|
|
238
|
-
break;
|
|
239
|
-
case MotionEvent.ACTION_MOVE:
|
|
240
|
-
x = (int) event.getRawX();
|
|
241
|
-
y = (int) event.getRawY();
|
|
242
|
-
|
|
243
|
-
final float dx = x - mLastTouchX;
|
|
244
|
-
final float dy = y - mLastTouchY;
|
|
245
|
-
|
|
246
|
-
mPosX += dx;
|
|
247
|
-
mPosY += dy;
|
|
248
|
-
|
|
249
|
-
layoutParams.leftMargin = mPosX;
|
|
250
|
-
layoutParams.topMargin = mPosY;
|
|
251
|
-
|
|
252
|
-
frameContainerLayout.setLayoutParams(layoutParams);
|
|
253
|
-
|
|
254
|
-
// Remember this touch position for the next move event
|
|
255
|
-
mLastTouchX = x;
|
|
256
|
-
mLastTouchY = y;
|
|
257
|
-
|
|
258
|
-
break;
|
|
259
|
-
default:
|
|
260
|
-
break;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
return true;
|
|
266
|
-
}
|
|
199
|
+
@Override
|
|
200
|
+
public boolean onTouch(View v, MotionEvent event) {
|
|
201
|
+
FrameLayout.LayoutParams layoutParams =
|
|
202
|
+
(FrameLayout.LayoutParams) frameContainerLayout.getLayoutParams();
|
|
203
|
+
|
|
204
|
+
boolean isSingleTapTouch = gestureDetector.onTouchEvent(
|
|
205
|
+
event
|
|
206
|
+
);
|
|
207
|
+
int action = event.getAction();
|
|
208
|
+
int eventCount = event.getPointerCount();
|
|
209
|
+
Log.d(
|
|
210
|
+
TAG,
|
|
211
|
+
"onTouch event, action, count: " +
|
|
212
|
+
event +
|
|
213
|
+
", " +
|
|
214
|
+
action +
|
|
215
|
+
", " +
|
|
216
|
+
eventCount
|
|
217
|
+
);
|
|
218
|
+
if (eventCount > 1) {
|
|
219
|
+
// handle multi-touch events
|
|
220
|
+
Camera.Parameters params = mCamera.getParameters();
|
|
221
|
+
if (action == MotionEvent.ACTION_POINTER_DOWN) {
|
|
222
|
+
mDist = getFingerSpacing(event);
|
|
223
|
+
} else if (
|
|
224
|
+
action == MotionEvent.ACTION_MOVE &&
|
|
225
|
+
params.isZoomSupported()
|
|
226
|
+
) {
|
|
227
|
+
handleZoom(event, params);
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
if (action != MotionEvent.ACTION_MOVE && isSingleTapTouch) {
|
|
231
|
+
if (tapToTakePicture && tapToFocus) {
|
|
232
|
+
setFocusArea(
|
|
233
|
+
(int) event.getX(0),
|
|
234
|
+
(int) event.getY(0),
|
|
235
|
+
new Camera.AutoFocusCallback() {
|
|
236
|
+
public void onAutoFocus(
|
|
237
|
+
boolean success,
|
|
238
|
+
Camera camera
|
|
239
|
+
) {
|
|
240
|
+
if (success) {
|
|
241
|
+
takePicture(0, 0, 85);
|
|
242
|
+
} else {
|
|
243
|
+
Log.d(
|
|
244
|
+
TAG,
|
|
245
|
+
"onTouch:" + " setFocusArea() did not suceed"
|
|
246
|
+
);
|
|
247
|
+
}
|
|
267
248
|
}
|
|
249
|
+
}
|
|
268
250
|
);
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
251
|
+
} else if (tapToTakePicture) {
|
|
252
|
+
takePicture(0, 0, 85);
|
|
253
|
+
} else if (tapToFocus) {
|
|
254
|
+
setFocusArea(
|
|
255
|
+
(int) event.getX(0),
|
|
256
|
+
(int) event.getY(0),
|
|
257
|
+
new Camera.AutoFocusCallback() {
|
|
258
|
+
public void onAutoFocus(
|
|
259
|
+
boolean success,
|
|
260
|
+
Camera camera
|
|
261
|
+
) {
|
|
262
|
+
if (success) {
|
|
263
|
+
// A callback to JS might make sense here.
|
|
264
|
+
} else {
|
|
265
|
+
Log.d(
|
|
266
|
+
TAG,
|
|
267
|
+
"onTouch:" + " setFocusArea() did not suceed"
|
|
268
|
+
);
|
|
269
|
+
}
|
|
281
270
|
}
|
|
271
|
+
}
|
|
282
272
|
);
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
273
|
+
}
|
|
274
|
+
return true;
|
|
275
|
+
} else {
|
|
276
|
+
if (dragEnabled) {
|
|
277
|
+
int x;
|
|
278
|
+
int y;
|
|
279
|
+
|
|
280
|
+
switch (event.getAction()) {
|
|
281
|
+
case MotionEvent.ACTION_DOWN:
|
|
282
|
+
if (mLastTouchX == 0 || mLastTouchY == 0) {
|
|
283
|
+
mLastTouchX =
|
|
284
|
+
(int) event.getRawX() - layoutParams.leftMargin;
|
|
285
|
+
mLastTouchY =
|
|
286
|
+
(int) event.getRawY() - layoutParams.topMargin;
|
|
287
|
+
} else {
|
|
288
|
+
mLastTouchX = (int) event.getRawX();
|
|
289
|
+
mLastTouchY = (int) event.getRawY();
|
|
299
290
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
);
|
|
307
|
-
}
|
|
291
|
+
break;
|
|
292
|
+
case MotionEvent.ACTION_MOVE:
|
|
293
|
+
x = (int) event.getRawX();
|
|
294
|
+
y = (int) event.getRawY();
|
|
308
295
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
numberOfCameras = Camera.getNumberOfCameras();
|
|
296
|
+
final float dx = x - mLastTouchX;
|
|
297
|
+
final float dy = y - mLastTouchY;
|
|
312
298
|
|
|
313
|
-
|
|
299
|
+
mPosX += dx;
|
|
300
|
+
mPosY += dy;
|
|
314
301
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
for (int i = 0; i < numberOfCameras; i++) {
|
|
318
|
-
Camera.getCameraInfo(i, cameraInfo);
|
|
319
|
-
if (cameraInfo.facing == facing) {
|
|
320
|
-
defaultCameraId = i;
|
|
321
|
-
break;
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
@Override
|
|
327
|
-
public void onResume() {
|
|
328
|
-
super.onResume();
|
|
329
|
-
|
|
330
|
-
mCamera = Camera.open(defaultCameraId);
|
|
302
|
+
layoutParams.leftMargin = mPosX;
|
|
303
|
+
layoutParams.topMargin = mPosY;
|
|
331
304
|
|
|
332
|
-
|
|
333
|
-
mCamera.setParameters(cameraParameters);
|
|
334
|
-
}
|
|
305
|
+
frameContainerLayout.setLayoutParams(layoutParams);
|
|
335
306
|
|
|
336
|
-
|
|
307
|
+
// Remember this touch position for the next move event
|
|
308
|
+
mLastTouchX = x;
|
|
309
|
+
mLastTouchY = y;
|
|
337
310
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
} else {
|
|
342
|
-
mPreview.switchCamera(mCamera, cameraCurrentlyLocked);
|
|
343
|
-
mCamera.startPreview();
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
Log.d(TAG, "cameraCurrentlyLocked:" + cameraCurrentlyLocked);
|
|
347
|
-
|
|
348
|
-
final FrameLayout frameContainerLayout = (FrameLayout) view.findViewById(
|
|
349
|
-
getResources().getIdentifier("frame_container", "id", appResourcesPackage)
|
|
350
|
-
);
|
|
351
|
-
|
|
352
|
-
ViewTreeObserver viewTreeObserver = frameContainerLayout.getViewTreeObserver();
|
|
353
|
-
|
|
354
|
-
if (viewTreeObserver.isAlive()) {
|
|
355
|
-
viewTreeObserver.addOnGlobalLayoutListener(
|
|
356
|
-
new ViewTreeObserver.OnGlobalLayoutListener() {
|
|
357
|
-
@Override
|
|
358
|
-
public void onGlobalLayout() {
|
|
359
|
-
frameContainerLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
|
|
360
|
-
frameContainerLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
|
|
361
|
-
Activity activity = getActivity();
|
|
362
|
-
if (isAdded() && activity != null) {
|
|
363
|
-
final RelativeLayout frameCamContainerLayout = (RelativeLayout) view.findViewById(
|
|
364
|
-
getResources().getIdentifier("frame_camera_cont", "id", appResourcesPackage)
|
|
365
|
-
);
|
|
366
|
-
|
|
367
|
-
FrameLayout.LayoutParams camViewLayout = new FrameLayout.LayoutParams(
|
|
368
|
-
frameContainerLayout.getWidth(),
|
|
369
|
-
frameContainerLayout.getHeight()
|
|
370
|
-
);
|
|
371
|
-
camViewLayout.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
|
|
372
|
-
frameCamContainerLayout.setLayoutParams(camViewLayout);
|
|
311
|
+
break;
|
|
312
|
+
default:
|
|
313
|
+
break;
|
|
373
314
|
}
|
|
315
|
+
}
|
|
374
316
|
}
|
|
317
|
+
}
|
|
318
|
+
return true;
|
|
375
319
|
}
|
|
320
|
+
}
|
|
376
321
|
);
|
|
377
|
-
|
|
378
|
-
|
|
322
|
+
frameContainerLayout.setFocusableInTouchMode(true);
|
|
323
|
+
frameContainerLayout.requestFocus();
|
|
324
|
+
frameContainerLayout.setOnKeyListener(
|
|
325
|
+
new View.OnKeyListener() {
|
|
326
|
+
@Override
|
|
327
|
+
public boolean onKey(
|
|
328
|
+
View v,
|
|
329
|
+
int keyCode,
|
|
330
|
+
android.view.KeyEvent event
|
|
331
|
+
) {
|
|
332
|
+
if (keyCode == android.view.KeyEvent.KEYCODE_BACK) {
|
|
333
|
+
eventListener.onBackButton();
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
);
|
|
340
|
+
}
|
|
379
341
|
|
|
380
|
-
|
|
381
|
-
public void onPause() {
|
|
382
|
-
super.onPause();
|
|
342
|
+
private float mDist = 0F;
|
|
383
343
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
344
|
+
private void handleZoom(MotionEvent event, Camera.Parameters params) {
|
|
345
|
+
if (mCamera != null) {
|
|
346
|
+
mCamera.cancelAutoFocus();
|
|
347
|
+
int maxZoom = params.getMaxZoom();
|
|
348
|
+
int zoom = params.getZoom();
|
|
349
|
+
float newDist = getFingerSpacing(event);
|
|
350
|
+
if (newDist > mDist) {
|
|
351
|
+
//zoom in
|
|
352
|
+
if (zoom < maxZoom) zoom++;
|
|
353
|
+
} else if (newDist < mDist) {
|
|
354
|
+
//zoom out
|
|
355
|
+
if (zoom > 0) zoom--;
|
|
356
|
+
}
|
|
357
|
+
mDist = newDist;
|
|
358
|
+
params.setZoom(zoom);
|
|
359
|
+
mCamera.setParameters(params);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
391
362
|
}
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
private void setDefaultCameraId() {
|
|
367
|
+
// Find the total number of cameras available
|
|
368
|
+
numberOfCameras = Camera.getNumberOfCameras();
|
|
369
|
+
|
|
370
|
+
int facing = "front".equals(defaultCamera)
|
|
371
|
+
? Camera.CameraInfo.CAMERA_FACING_FRONT
|
|
372
|
+
: Camera.CameraInfo.CAMERA_FACING_BACK;
|
|
373
|
+
|
|
374
|
+
// Find the ID of the default camera
|
|
375
|
+
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
|
|
376
|
+
for (int i = 0; i < numberOfCameras; i++) {
|
|
377
|
+
Camera.getCameraInfo(i, cameraInfo);
|
|
378
|
+
if (cameraInfo.facing == facing) {
|
|
379
|
+
defaultCameraId = i;
|
|
380
|
+
break;
|
|
381
|
+
}
|
|
392
382
|
}
|
|
383
|
+
}
|
|
393
384
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
385
|
+
@Override
|
|
386
|
+
public void onResume() {
|
|
387
|
+
super.onResume();
|
|
397
388
|
|
|
398
|
-
|
|
399
|
-
getResources().getIdentifier("frame_container", "id", appResourcesPackage)
|
|
400
|
-
);
|
|
401
|
-
|
|
402
|
-
final int previousOrientation = frameContainerLayout.getHeight() > frameContainerLayout.getWidth()
|
|
403
|
-
? Configuration.ORIENTATION_PORTRAIT
|
|
404
|
-
: Configuration.ORIENTATION_LANDSCAPE;
|
|
405
|
-
// Checks if the orientation of the screen has changed
|
|
406
|
-
if (newConfig.orientation != previousOrientation) {
|
|
407
|
-
final RelativeLayout frameCamContainerLayout = (RelativeLayout) view.findViewById(
|
|
408
|
-
getResources().getIdentifier("frame_camera_cont", "id", appResourcesPackage)
|
|
409
|
-
);
|
|
410
|
-
|
|
411
|
-
frameContainerLayout.getLayoutParams().width = frameCamContainerLayout.getHeight();
|
|
412
|
-
frameContainerLayout.getLayoutParams().height = frameCamContainerLayout.getWidth();
|
|
389
|
+
mCamera = Camera.open(defaultCameraId);
|
|
413
390
|
|
|
414
|
-
|
|
415
|
-
|
|
391
|
+
if (cameraParameters != null) {
|
|
392
|
+
mCamera.setParameters(cameraParameters);
|
|
393
|
+
}
|
|
416
394
|
|
|
417
|
-
|
|
418
|
-
frameContainerLayout.requestLayout();
|
|
395
|
+
cameraCurrentlyLocked = defaultCameraId;
|
|
419
396
|
|
|
420
|
-
|
|
397
|
+
if (mPreview.mPreviewSize == null) {
|
|
398
|
+
mPreview.setCamera(mCamera, cameraCurrentlyLocked);
|
|
399
|
+
eventListener.onCameraStarted();
|
|
400
|
+
} else {
|
|
401
|
+
mPreview.switchCamera(mCamera, cameraCurrentlyLocked);
|
|
402
|
+
mCamera.startPreview();
|
|
403
|
+
}
|
|
421
404
|
|
|
422
|
-
|
|
405
|
+
Log.d(TAG, "cameraCurrentlyLocked:" + cameraCurrentlyLocked);
|
|
406
|
+
|
|
407
|
+
final FrameLayout frameContainerLayout = (FrameLayout) view.findViewById(
|
|
408
|
+
getResources().getIdentifier("frame_container", "id", appResourcesPackage)
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
ViewTreeObserver viewTreeObserver =
|
|
412
|
+
frameContainerLayout.getViewTreeObserver();
|
|
413
|
+
|
|
414
|
+
if (viewTreeObserver.isAlive()) {
|
|
415
|
+
viewTreeObserver.addOnGlobalLayoutListener(
|
|
416
|
+
new ViewTreeObserver.OnGlobalLayoutListener() {
|
|
417
|
+
@Override
|
|
418
|
+
public void onGlobalLayout() {
|
|
419
|
+
frameContainerLayout
|
|
420
|
+
.getViewTreeObserver()
|
|
421
|
+
.removeGlobalOnLayoutListener(this);
|
|
422
|
+
frameContainerLayout.measure(
|
|
423
|
+
View.MeasureSpec.UNSPECIFIED,
|
|
424
|
+
View.MeasureSpec.UNSPECIFIED
|
|
425
|
+
);
|
|
426
|
+
Activity activity = getActivity();
|
|
427
|
+
if (isAdded() && activity != null) {
|
|
428
|
+
final RelativeLayout frameCamContainerLayout =
|
|
429
|
+
(RelativeLayout) view.findViewById(
|
|
430
|
+
getResources()
|
|
431
|
+
.getIdentifier(
|
|
432
|
+
"frame_camera_cont",
|
|
433
|
+
"id",
|
|
434
|
+
appResourcesPackage
|
|
435
|
+
)
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
FrameLayout.LayoutParams camViewLayout =
|
|
439
|
+
new FrameLayout.LayoutParams(
|
|
440
|
+
frameContainerLayout.getWidth(),
|
|
441
|
+
frameContainerLayout.getHeight()
|
|
442
|
+
);
|
|
443
|
+
camViewLayout.gravity =
|
|
444
|
+
Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
|
|
445
|
+
frameCamContainerLayout.setLayoutParams(camViewLayout);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
423
448
|
}
|
|
449
|
+
);
|
|
424
450
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
@Override
|
|
454
|
+
public void onPause() {
|
|
455
|
+
super.onPause();
|
|
456
|
+
|
|
457
|
+
// Because the Camera object is a shared resource, it's very important to release it when the activity is paused.
|
|
458
|
+
if (mCamera != null) {
|
|
459
|
+
setDefaultCameraId();
|
|
460
|
+
mPreview.setCamera(null, -1);
|
|
461
|
+
mCamera.setPreviewCallback(null);
|
|
462
|
+
mCamera.release();
|
|
463
|
+
mCamera = null;
|
|
428
464
|
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
@Override
|
|
468
|
+
public void onConfigurationChanged(Configuration newConfig) {
|
|
469
|
+
super.onConfigurationChanged(newConfig);
|
|
470
|
+
|
|
471
|
+
final FrameLayout frameContainerLayout = (FrameLayout) view.findViewById(
|
|
472
|
+
getResources().getIdentifier("frame_container", "id", appResourcesPackage)
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
final int previousOrientation = frameContainerLayout.getHeight() >
|
|
476
|
+
frameContainerLayout.getWidth()
|
|
477
|
+
? Configuration.ORIENTATION_PORTRAIT
|
|
478
|
+
: Configuration.ORIENTATION_LANDSCAPE;
|
|
479
|
+
// Checks if the orientation of the screen has changed
|
|
480
|
+
if (newConfig.orientation != previousOrientation) {
|
|
481
|
+
final RelativeLayout frameCamContainerLayout =
|
|
482
|
+
(RelativeLayout) view.findViewById(
|
|
483
|
+
getResources()
|
|
484
|
+
.getIdentifier("frame_camera_cont", "id", appResourcesPackage)
|
|
485
|
+
);
|
|
429
486
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
} else {
|
|
435
|
-
Log.d(TAG, "numberOfCameras: " + numberOfCameras);
|
|
487
|
+
frameContainerLayout.getLayoutParams().width =
|
|
488
|
+
frameCamContainerLayout.getHeight();
|
|
489
|
+
frameContainerLayout.getLayoutParams().height =
|
|
490
|
+
frameCamContainerLayout.getWidth();
|
|
436
491
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
mCamera.release();
|
|
442
|
-
mCamera = null;
|
|
443
|
-
}
|
|
492
|
+
frameCamContainerLayout.getLayoutParams().width =
|
|
493
|
+
frameCamContainerLayout.getHeight();
|
|
494
|
+
frameCamContainerLayout.getLayoutParams().height =
|
|
495
|
+
frameCamContainerLayout.getWidth();
|
|
444
496
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
cameraCurrentlyLocked = (cameraCurrentlyLocked + 1) % numberOfCameras;
|
|
448
|
-
Log.d(TAG, "cameraCurrentlyLocked new: " + cameraCurrentlyLocked);
|
|
449
|
-
} catch (Exception exception) {
|
|
450
|
-
Log.d(TAG, exception.getMessage());
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
// Acquire the next camera and request Preview to reconfigure parameters.
|
|
454
|
-
mCamera = Camera.open(cameraCurrentlyLocked);
|
|
497
|
+
frameContainerLayout.invalidate();
|
|
498
|
+
frameContainerLayout.requestLayout();
|
|
455
499
|
|
|
456
|
-
|
|
457
|
-
Log.d(TAG, "camera parameter not null");
|
|
500
|
+
frameCamContainerLayout.forceLayout();
|
|
458
501
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
502
|
+
mPreview.setCameraDisplayOrientation();
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
public Camera getCamera() {
|
|
507
|
+
return mCamera;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
public void switchCamera() {
|
|
511
|
+
// check for availability of multiple cameras
|
|
512
|
+
if (numberOfCameras == 1) {
|
|
513
|
+
//There is only one camera available
|
|
514
|
+
} else {
|
|
515
|
+
Log.d(TAG, "numberOfCameras: " + numberOfCameras);
|
|
516
|
+
|
|
517
|
+
// OK, we have multiple cameras. Release this camera -> cameraCurrentlyLocked
|
|
518
|
+
if (mCamera != null) {
|
|
519
|
+
mCamera.stopPreview();
|
|
520
|
+
mPreview.setCamera(null, -1);
|
|
521
|
+
mCamera.release();
|
|
522
|
+
mCamera = null;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
Log.d(
|
|
526
|
+
TAG,
|
|
527
|
+
"cameraCurrentlyLocked := " + Integer.toString(cameraCurrentlyLocked)
|
|
528
|
+
);
|
|
529
|
+
try {
|
|
530
|
+
cameraCurrentlyLocked = (cameraCurrentlyLocked + 1) % numberOfCameras;
|
|
531
|
+
Log.d(TAG, "cameraCurrentlyLocked new: " + cameraCurrentlyLocked);
|
|
532
|
+
} catch (Exception exception) {
|
|
533
|
+
Log.d(TAG, exception.getMessage());
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Acquire the next camera and request Preview to reconfigure parameters.
|
|
537
|
+
mCamera = Camera.open(cameraCurrentlyLocked);
|
|
538
|
+
|
|
539
|
+
if (cameraParameters != null) {
|
|
540
|
+
Log.d(TAG, "camera parameter not null");
|
|
541
|
+
|
|
542
|
+
// Check for flashMode as well to prevent error on frontward facing camera.
|
|
543
|
+
List<String> supportedFlashModesNewCamera = mCamera
|
|
544
|
+
.getParameters()
|
|
545
|
+
.getSupportedFlashModes();
|
|
546
|
+
String currentFlashModePreviousCamera = cameraParameters.getFlashMode();
|
|
547
|
+
if (
|
|
548
|
+
supportedFlashModesNewCamera != null &&
|
|
549
|
+
supportedFlashModesNewCamera.contains(currentFlashModePreviousCamera)
|
|
550
|
+
) {
|
|
551
|
+
Log.d(
|
|
552
|
+
TAG,
|
|
553
|
+
"current flash mode supported on new camera. setting params"
|
|
554
|
+
);
|
|
555
|
+
/* mCamera.setParameters(cameraParameters);
|
|
465
556
|
The line above is disabled because parameters that can actually be changed are different from one device to another. Makes less sense trying to reconfigure them when changing camera device while those settings gan be changed using plugin methods.
|
|
466
557
|
*/
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
}
|
|
470
|
-
} else {
|
|
471
|
-
Log.d(TAG, "camera parameter NULL");
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
mPreview.switchCamera(mCamera, cameraCurrentlyLocked);
|
|
475
|
-
|
|
476
|
-
mCamera.startPreview();
|
|
558
|
+
} else {
|
|
559
|
+
Log.d(TAG, "current flash mode NOT supported on new camera");
|
|
477
560
|
}
|
|
478
|
-
|
|
561
|
+
} else {
|
|
562
|
+
Log.d(TAG, "camera parameter NULL");
|
|
563
|
+
}
|
|
479
564
|
|
|
480
|
-
|
|
481
|
-
cameraParameters = params;
|
|
565
|
+
mPreview.switchCamera(mCamera, cameraCurrentlyLocked);
|
|
482
566
|
|
|
483
|
-
|
|
484
|
-
mCamera.setParameters(cameraParameters);
|
|
485
|
-
}
|
|
567
|
+
mCamera.startPreview();
|
|
486
568
|
}
|
|
569
|
+
}
|
|
487
570
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
}
|
|
571
|
+
public void setCameraParameters(Camera.Parameters params) {
|
|
572
|
+
cameraParameters = params;
|
|
491
573
|
|
|
492
|
-
|
|
493
|
-
|
|
574
|
+
if (mCamera != null && cameraParameters != null) {
|
|
575
|
+
mCamera.setParameters(cameraParameters);
|
|
494
576
|
}
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
// Create the cache directory if it doesn't exist
|
|
520
|
-
cache.mkdirs();
|
|
521
|
-
return cache.getAbsolutePath();
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
public boolean hasFrontCamera() {
|
|
580
|
+
return getActivity()
|
|
581
|
+
.getApplicationContext()
|
|
582
|
+
.getPackageManager()
|
|
583
|
+
.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
public static Bitmap applyMatrix(Bitmap source, Matrix matrix) {
|
|
587
|
+
return Bitmap.createBitmap(
|
|
588
|
+
source,
|
|
589
|
+
0,
|
|
590
|
+
0,
|
|
591
|
+
source.getWidth(),
|
|
592
|
+
source.getHeight(),
|
|
593
|
+
matrix,
|
|
594
|
+
true
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
ShutterCallback shutterCallback = new ShutterCallback() {
|
|
599
|
+
public void onShutter() {
|
|
600
|
+
// do nothing, availabilty of this callback causes default system shutter sound to work
|
|
522
601
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
private static int exifToDegrees(int exifOrientation) {
|
|
605
|
+
if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
|
|
606
|
+
return 90;
|
|
607
|
+
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
|
|
608
|
+
return 180;
|
|
609
|
+
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
|
|
610
|
+
return 270;
|
|
526
611
|
}
|
|
612
|
+
return 0;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
private String getTempDirectoryPath() {
|
|
616
|
+
File cache = null;
|
|
617
|
+
|
|
618
|
+
// Use internal storage
|
|
619
|
+
cache = getActivity().getCacheDir();
|
|
620
|
+
|
|
621
|
+
// Create the cache directory if it doesn't exist
|
|
622
|
+
cache.mkdirs();
|
|
623
|
+
return cache.getAbsolutePath();
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
private String getTempFilePath() {
|
|
627
|
+
return (
|
|
628
|
+
getTempDirectoryPath() +
|
|
629
|
+
"/cpcp_capture_" +
|
|
630
|
+
UUID.randomUUID().toString().replace("-", "").substring(0, 8) +
|
|
631
|
+
".jpg"
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
PictureCallback jpegPictureCallback = new PictureCallback() {
|
|
636
|
+
public void onPictureTaken(byte[] data, Camera arg1) {
|
|
637
|
+
Log.d(TAG, "CameraPreview jpegPictureCallback");
|
|
638
|
+
|
|
639
|
+
try {
|
|
640
|
+
if (!disableExifHeaderStripping) {
|
|
641
|
+
Matrix matrix = new Matrix();
|
|
642
|
+
if (cameraCurrentlyLocked == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
|
643
|
+
matrix.preScale(1.0f, -1.0f);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
ExifInterface exifInterface = new ExifInterface(
|
|
647
|
+
new ByteArrayInputStream(data)
|
|
648
|
+
);
|
|
649
|
+
int rotation = exifInterface.getAttributeInt(
|
|
650
|
+
ExifInterface.TAG_ORIENTATION,
|
|
651
|
+
ExifInterface.ORIENTATION_NORMAL
|
|
652
|
+
);
|
|
653
|
+
int rotationInDegrees = exifToDegrees(rotation);
|
|
654
|
+
|
|
655
|
+
if (rotation != 0f) {
|
|
656
|
+
matrix.preRotate(rotationInDegrees);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Check if matrix has changed. In that case, apply matrix and override data
|
|
660
|
+
if (!matrix.isIdentity()) {
|
|
661
|
+
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
|
|
662
|
+
bitmap = applyMatrix(bitmap, matrix);
|
|
663
|
+
|
|
664
|
+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
|
665
|
+
bitmap.compress(CompressFormat.JPEG, currentQuality, outputStream);
|
|
666
|
+
data = outputStream.toByteArray();
|
|
667
|
+
}
|
|
668
|
+
}
|
|
527
669
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
Log.d(TAG, "CameraPreview jpegPictureCallback");
|
|
531
|
-
|
|
532
|
-
try {
|
|
533
|
-
if (!disableExifHeaderStripping) {
|
|
534
|
-
Matrix matrix = new Matrix();
|
|
535
|
-
if (cameraCurrentlyLocked == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
|
536
|
-
matrix.preScale(1.0f, -1.0f);
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
ExifInterface exifInterface = new ExifInterface(new ByteArrayInputStream(data));
|
|
540
|
-
int rotation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
|
|
541
|
-
int rotationInDegrees = exifToDegrees(rotation);
|
|
542
|
-
|
|
543
|
-
if (rotation != 0f) {
|
|
544
|
-
matrix.preRotate(rotationInDegrees);
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
// Check if matrix has changed. In that case, apply matrix and override data
|
|
548
|
-
if (!matrix.isIdentity()) {
|
|
549
|
-
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
|
|
550
|
-
bitmap = applyMatrix(bitmap, matrix);
|
|
551
|
-
|
|
552
|
-
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
|
553
|
-
bitmap.compress(CompressFormat.JPEG, currentQuality, outputStream);
|
|
554
|
-
data = outputStream.toByteArray();
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
if (!storeToFile) {
|
|
559
|
-
String encodedImage = Base64.encodeToString(data, Base64.NO_WRAP);
|
|
670
|
+
if (!storeToFile) {
|
|
671
|
+
String encodedImage = Base64.encodeToString(data, Base64.NO_WRAP);
|
|
560
672
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
}
|
|
569
|
-
Log.d(TAG, "CameraPreview pictureTakenHandler called back");
|
|
570
|
-
} catch (OutOfMemoryError e) {
|
|
571
|
-
// most likely failed to allocate memory for rotateBitmap
|
|
572
|
-
Log.d(TAG, "CameraPreview OutOfMemoryError");
|
|
573
|
-
// failed to allocate memory
|
|
574
|
-
eventListener.onPictureTakenError("Picture too large (memory)");
|
|
575
|
-
} catch (IOException e) {
|
|
576
|
-
Log.d(TAG, "CameraPreview IOException");
|
|
577
|
-
eventListener.onPictureTakenError("IO Error when extracting exif");
|
|
578
|
-
} catch (Exception e) {
|
|
579
|
-
Log.d(TAG, "CameraPreview onPictureTaken general exception");
|
|
580
|
-
} finally {
|
|
581
|
-
canTakePicture = true;
|
|
582
|
-
mCamera.startPreview();
|
|
583
|
-
}
|
|
673
|
+
eventListener.onPictureTaken(encodedImage);
|
|
674
|
+
} else {
|
|
675
|
+
String path = getTempFilePath();
|
|
676
|
+
FileOutputStream out = new FileOutputStream(path);
|
|
677
|
+
out.write(data);
|
|
678
|
+
out.close();
|
|
679
|
+
eventListener.onPictureTaken(path);
|
|
584
680
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
681
|
+
Log.d(TAG, "CameraPreview pictureTakenHandler called back");
|
|
682
|
+
} catch (OutOfMemoryError e) {
|
|
683
|
+
// most likely failed to allocate memory for rotateBitmap
|
|
684
|
+
Log.d(TAG, "CameraPreview OutOfMemoryError");
|
|
685
|
+
// failed to allocate memory
|
|
686
|
+
eventListener.onPictureTakenError("Picture too large (memory)");
|
|
687
|
+
} catch (IOException e) {
|
|
688
|
+
Log.d(TAG, "CameraPreview IOException");
|
|
689
|
+
eventListener.onPictureTakenError("IO Error when extracting exif");
|
|
690
|
+
} catch (Exception e) {
|
|
691
|
+
Log.d(TAG, "CameraPreview onPictureTaken general exception");
|
|
692
|
+
} finally {
|
|
693
|
+
canTakePicture = true;
|
|
694
|
+
mCamera.startPreview();
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
|
|
699
|
+
private Camera.Size getOptimalPictureSize(
|
|
700
|
+
final int width,
|
|
701
|
+
final int height,
|
|
702
|
+
final Camera.Size previewSize,
|
|
703
|
+
final List<Camera.Size> supportedSizes
|
|
704
|
+
) {
|
|
705
|
+
/*
|
|
594
706
|
get the supportedPictureSize that:
|
|
595
707
|
- matches exactly width and height
|
|
596
708
|
- has the closest aspect ratio to the preview aspect ratio
|
|
597
709
|
- has picture.width and picture.height closest to width and height
|
|
598
710
|
- has the highest supported picture width and height up to 2 Megapixel if width == 0 || height == 0
|
|
599
711
|
*/
|
|
600
|
-
|
|
712
|
+
Camera.Size size = mCamera.new Size(width, height);
|
|
601
713
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
Camera.Size requestedSize = mCamera.new Size(size.width, size.height);
|
|
610
|
-
|
|
611
|
-
double previewAspectRatio = (double) previewSize.width / (double) previewSize.height;
|
|
612
|
-
|
|
613
|
-
if (previewAspectRatio < 1.0) {
|
|
614
|
-
// reset ratio to landscape
|
|
615
|
-
previewAspectRatio = 1.0 / previewAspectRatio;
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
Log.d(TAG, "CameraPreview previewAspectRatio " + previewAspectRatio);
|
|
619
|
-
|
|
620
|
-
double aspectTolerance = 0.1;
|
|
621
|
-
double bestDifference = Double.MAX_VALUE;
|
|
622
|
-
|
|
623
|
-
for (int i = 0; i < supportedSizes.size(); i++) {
|
|
624
|
-
Camera.Size supportedSize = supportedSizes.get(i);
|
|
625
|
-
|
|
626
|
-
// Perfect match
|
|
627
|
-
if (supportedSize.equals(requestedSize)) {
|
|
628
|
-
Log.d(TAG, "CameraPreview optimalPictureSize " + supportedSize.width + 'x' + supportedSize.height);
|
|
629
|
-
return supportedSize;
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
double difference = Math.abs(previewAspectRatio - ((double) supportedSize.width / (double) supportedSize.height));
|
|
633
|
-
|
|
634
|
-
if (difference < bestDifference - aspectTolerance) {
|
|
635
|
-
// better aspectRatio found
|
|
636
|
-
if ((width != 0 && height != 0) || (supportedSize.width * supportedSize.height < 2048 * 1024)) {
|
|
637
|
-
size.width = supportedSize.width;
|
|
638
|
-
size.height = supportedSize.height;
|
|
639
|
-
bestDifference = difference;
|
|
640
|
-
}
|
|
641
|
-
} else if (difference < bestDifference + aspectTolerance) {
|
|
642
|
-
// same aspectRatio found (within tolerance)
|
|
643
|
-
if (width == 0 || height == 0) {
|
|
644
|
-
// set highest supported resolution below 2 Megapixel
|
|
645
|
-
if ((size.width < supportedSize.width) && (supportedSize.width * supportedSize.height < 2048 * 1024)) {
|
|
646
|
-
size.width = supportedSize.width;
|
|
647
|
-
size.height = supportedSize.height;
|
|
648
|
-
}
|
|
649
|
-
} else {
|
|
650
|
-
// check if this pictureSize closer to requested width and height
|
|
651
|
-
if (
|
|
652
|
-
Math.abs(width * height - supportedSize.width * supportedSize.height) <
|
|
653
|
-
Math.abs(width * height - size.width * size.height)
|
|
654
|
-
) {
|
|
655
|
-
size.width = supportedSize.width;
|
|
656
|
-
size.height = supportedSize.height;
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
Log.d(TAG, "CameraPreview optimalPictureSize " + size.width + 'x' + size.height);
|
|
662
|
-
return size;
|
|
714
|
+
// convert to landscape if necessary
|
|
715
|
+
if (size.width < size.height) {
|
|
716
|
+
int temp = size.width;
|
|
717
|
+
size.width = size.height;
|
|
718
|
+
size.height = temp;
|
|
663
719
|
}
|
|
664
720
|
|
|
665
|
-
|
|
666
|
-
if (rotation == 0) return yuv;
|
|
667
|
-
if (rotation % 90 != 0 || rotation < 0 || rotation > 270) {
|
|
668
|
-
throw new IllegalArgumentException("0 <= rotation < 360, rotation % 90 == 0");
|
|
669
|
-
}
|
|
721
|
+
Camera.Size requestedSize = mCamera.new Size(size.width, size.height);
|
|
670
722
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
final boolean swap = rotation % 180 != 0;
|
|
674
|
-
final boolean xflip = rotation % 270 != 0;
|
|
675
|
-
final boolean yflip = rotation >= 180;
|
|
676
|
-
|
|
677
|
-
for (int j = 0; j < height; j++) {
|
|
678
|
-
for (int i = 0; i < width; i++) {
|
|
679
|
-
final int yIn = j * width + i;
|
|
680
|
-
final int uIn = frameSize + (j >> 1) * width + (i & ~1);
|
|
681
|
-
final int vIn = uIn + 1;
|
|
682
|
-
|
|
683
|
-
final int wOut = swap ? height : width;
|
|
684
|
-
final int hOut = swap ? width : height;
|
|
685
|
-
final int iSwapped = swap ? j : i;
|
|
686
|
-
final int jSwapped = swap ? i : j;
|
|
687
|
-
final int iOut = xflip ? wOut - iSwapped - 1 : iSwapped;
|
|
688
|
-
final int jOut = yflip ? hOut - jSwapped - 1 : jSwapped;
|
|
689
|
-
|
|
690
|
-
final int yOut = jOut * wOut + iOut;
|
|
691
|
-
final int uOut = frameSize + (jOut >> 1) * wOut + (iOut & ~1);
|
|
692
|
-
final int vOut = uOut + 1;
|
|
693
|
-
|
|
694
|
-
output[yOut] = (byte) (0xff & yuv[yIn]);
|
|
695
|
-
output[uOut] = (byte) (0xff & yuv[uIn]);
|
|
696
|
-
output[vOut] = (byte) (0xff & yuv[vIn]);
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
return output;
|
|
700
|
-
}
|
|
723
|
+
double previewAspectRatio = (double) previewSize.width /
|
|
724
|
+
(double) previewSize.height;
|
|
701
725
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
mPreview.setOpacity(opacity);
|
|
726
|
+
if (previewAspectRatio < 1.0) {
|
|
727
|
+
// reset ratio to landscape
|
|
728
|
+
previewAspectRatio = 1.0 / previewAspectRatio;
|
|
706
729
|
}
|
|
707
730
|
|
|
708
|
-
|
|
709
|
-
mCamera.setPreviewCallback(
|
|
710
|
-
new Camera.PreviewCallback() {
|
|
711
|
-
@Override
|
|
712
|
-
public void onPreviewFrame(byte[] bytes, Camera camera) {
|
|
713
|
-
try {
|
|
714
|
-
Camera.Parameters parameters = camera.getParameters();
|
|
715
|
-
Camera.Size size = parameters.getPreviewSize();
|
|
716
|
-
int orientation = mPreview.getDisplayOrientation();
|
|
717
|
-
if (mPreview.getCameraFacing() == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
|
718
|
-
bytes = rotateNV21(bytes, size.width, size.height, (360 - orientation) % 360);
|
|
719
|
-
} else {
|
|
720
|
-
bytes = rotateNV21(bytes, size.width, size.height, orientation);
|
|
721
|
-
}
|
|
722
|
-
// switch width/height when rotating 90/270 deg
|
|
723
|
-
Rect rect = orientation == 90 || orientation == 270
|
|
724
|
-
? new Rect(0, 0, size.height, size.width)
|
|
725
|
-
: new Rect(0, 0, size.width, size.height);
|
|
726
|
-
YuvImage yuvImage = new YuvImage(bytes, parameters.getPreviewFormat(), rect.width(), rect.height(), null);
|
|
727
|
-
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
|
728
|
-
yuvImage.compressToJpeg(rect, quality, byteArrayOutputStream);
|
|
729
|
-
byte[] data = byteArrayOutputStream.toByteArray();
|
|
730
|
-
byteArrayOutputStream.close();
|
|
731
|
-
eventListener.onSnapshotTaken(Base64.encodeToString(data, Base64.NO_WRAP));
|
|
732
|
-
} catch (IOException e) {
|
|
733
|
-
Log.d(TAG, "CameraPreview IOException");
|
|
734
|
-
eventListener.onSnapshotTakenError("IO Error");
|
|
735
|
-
} finally {
|
|
736
|
-
mCamera.setPreviewCallback(null);
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
);
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
public void takePicture(final int width, final int height, final int quality) {
|
|
744
|
-
Log.d(TAG, "CameraPreview takePicture width: " + width + ", height: " + height + ", quality: " + quality);
|
|
745
|
-
|
|
746
|
-
if (mPreview != null) {
|
|
747
|
-
if (!canTakePicture) {
|
|
748
|
-
return;
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
canTakePicture = false;
|
|
752
|
-
|
|
753
|
-
new Thread() {
|
|
754
|
-
public void run() {
|
|
755
|
-
Camera.Parameters params = mCamera.getParameters();
|
|
756
|
-
|
|
757
|
-
Camera.Size size = getOptimalPictureSize(width, height, params.getPreviewSize(), params.getSupportedPictureSizes());
|
|
758
|
-
params.setPictureSize(size.width, size.height);
|
|
759
|
-
currentQuality = quality;
|
|
731
|
+
Log.d(TAG, "CameraPreview previewAspectRatio " + previewAspectRatio);
|
|
760
732
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
params.setJpegQuality(99);
|
|
764
|
-
} else {
|
|
765
|
-
params.setJpegQuality(quality);
|
|
766
|
-
}
|
|
733
|
+
double aspectTolerance = 0.1;
|
|
734
|
+
double bestDifference = Double.MAX_VALUE;
|
|
767
735
|
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
|
|
771
|
-
int degrees = 0;
|
|
772
|
-
switch (rotation) {
|
|
773
|
-
case Surface.ROTATION_0:
|
|
774
|
-
degrees = 0;
|
|
775
|
-
break;
|
|
776
|
-
case Surface.ROTATION_90:
|
|
777
|
-
degrees = 180;
|
|
778
|
-
break;
|
|
779
|
-
case Surface.ROTATION_180:
|
|
780
|
-
degrees = 270;
|
|
781
|
-
break;
|
|
782
|
-
case Surface.ROTATION_270:
|
|
783
|
-
degrees = 0;
|
|
784
|
-
break;
|
|
785
|
-
}
|
|
786
|
-
int orientation;
|
|
787
|
-
Camera.CameraInfo info = new Camera.CameraInfo();
|
|
788
|
-
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
|
789
|
-
orientation = (info.orientation + degrees) % 360;
|
|
790
|
-
if (degrees != 0) {
|
|
791
|
-
orientation = (360 - orientation) % 360;
|
|
792
|
-
}
|
|
793
|
-
} else {
|
|
794
|
-
orientation = (info.orientation - degrees + 360) % 360;
|
|
795
|
-
}
|
|
796
|
-
params.setRotation(orientation);
|
|
797
|
-
} else {
|
|
798
|
-
params.setRotation(mPreview.getDisplayOrientation());
|
|
799
|
-
}
|
|
736
|
+
for (int i = 0; i < supportedSizes.size(); i++) {
|
|
737
|
+
Camera.Size supportedSize = supportedSizes.get(i);
|
|
800
738
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
739
|
+
// Perfect match
|
|
740
|
+
if (supportedSize.equals(requestedSize)) {
|
|
741
|
+
Log.d(
|
|
742
|
+
TAG,
|
|
743
|
+
"CameraPreview optimalPictureSize " +
|
|
744
|
+
supportedSize.width +
|
|
745
|
+
'x' +
|
|
746
|
+
supportedSize.height
|
|
747
|
+
);
|
|
748
|
+
return supportedSize;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
double difference = Math.abs(
|
|
752
|
+
previewAspectRatio -
|
|
753
|
+
((double) supportedSize.width / (double) supportedSize.height)
|
|
754
|
+
);
|
|
755
|
+
|
|
756
|
+
if (difference < bestDifference - aspectTolerance) {
|
|
757
|
+
// better aspectRatio found
|
|
758
|
+
if (
|
|
759
|
+
(width != 0 && height != 0) ||
|
|
760
|
+
(supportedSize.width * supportedSize.height < 2048 * 1024)
|
|
761
|
+
) {
|
|
762
|
+
size.width = supportedSize.width;
|
|
763
|
+
size.height = supportedSize.height;
|
|
764
|
+
bestDifference = difference;
|
|
765
|
+
}
|
|
766
|
+
} else if (difference < bestDifference + aspectTolerance) {
|
|
767
|
+
// same aspectRatio found (within tolerance)
|
|
768
|
+
if (width == 0 || height == 0) {
|
|
769
|
+
// set highest supported resolution below 2 Megapixel
|
|
770
|
+
if (
|
|
771
|
+
(size.width < supportedSize.width) &&
|
|
772
|
+
(supportedSize.width * supportedSize.height < 2048 * 1024)
|
|
773
|
+
) {
|
|
774
|
+
size.width = supportedSize.width;
|
|
775
|
+
size.height = supportedSize.height;
|
|
776
|
+
}
|
|
806
777
|
} else {
|
|
807
|
-
|
|
778
|
+
// check if this pictureSize closer to requested width and height
|
|
779
|
+
if (
|
|
780
|
+
Math.abs(
|
|
781
|
+
width * height - supportedSize.width * supportedSize.height
|
|
782
|
+
) <
|
|
783
|
+
Math.abs(width * height - size.width * size.height)
|
|
784
|
+
) {
|
|
785
|
+
size.width = supportedSize.width;
|
|
786
|
+
size.height = supportedSize.height;
|
|
787
|
+
}
|
|
808
788
|
}
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
Log.d(
|
|
792
|
+
TAG,
|
|
793
|
+
"CameraPreview optimalPictureSize " + size.width + 'x' + size.height
|
|
794
|
+
);
|
|
795
|
+
return size;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
static byte[] rotateNV21(
|
|
799
|
+
final byte[] yuv,
|
|
800
|
+
final int width,
|
|
801
|
+
final int height,
|
|
802
|
+
final int rotation
|
|
803
|
+
) {
|
|
804
|
+
if (rotation == 0) return yuv;
|
|
805
|
+
if (rotation % 90 != 0 || rotation < 0 || rotation > 270) {
|
|
806
|
+
throw new IllegalArgumentException(
|
|
807
|
+
"0 <= rotation < 360, rotation % 90 == 0"
|
|
808
|
+
);
|
|
809
809
|
}
|
|
810
810
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
int
|
|
831
|
-
int
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
811
|
+
final byte[] output = new byte[yuv.length];
|
|
812
|
+
final int frameSize = width * height;
|
|
813
|
+
final boolean swap = rotation % 180 != 0;
|
|
814
|
+
final boolean xflip = rotation % 270 != 0;
|
|
815
|
+
final boolean yflip = rotation >= 180;
|
|
816
|
+
|
|
817
|
+
for (int j = 0; j < height; j++) {
|
|
818
|
+
for (int i = 0; i < width; i++) {
|
|
819
|
+
final int yIn = j * width + i;
|
|
820
|
+
final int uIn = frameSize + (j >> 1) * width + (i & ~1);
|
|
821
|
+
final int vIn = uIn + 1;
|
|
822
|
+
|
|
823
|
+
final int wOut = swap ? height : width;
|
|
824
|
+
final int hOut = swap ? width : height;
|
|
825
|
+
final int iSwapped = swap ? j : i;
|
|
826
|
+
final int jSwapped = swap ? i : j;
|
|
827
|
+
final int iOut = xflip ? wOut - iSwapped - 1 : iSwapped;
|
|
828
|
+
final int jOut = yflip ? hOut - jSwapped - 1 : jSwapped;
|
|
829
|
+
|
|
830
|
+
final int yOut = jOut * wOut + iOut;
|
|
831
|
+
final int uOut = frameSize + (jOut >> 1) * wOut + (iOut & ~1);
|
|
832
|
+
final int vOut = uOut + 1;
|
|
833
|
+
|
|
834
|
+
output[yOut] = (byte) (0xff & yuv[yIn]);
|
|
835
|
+
output[uOut] = (byte) (0xff & yuv[uIn]);
|
|
836
|
+
output[vOut] = (byte) (0xff & yuv[vIn]);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
return output;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
public void setOpacity(final float opacity) {
|
|
843
|
+
Log.d(TAG, "set opacity:" + opacity);
|
|
844
|
+
this.opacity = opacity;
|
|
845
|
+
mPreview.setOpacity(opacity);
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
public void takeSnapshot(final int quality) {
|
|
849
|
+
mCamera.setPreviewCallback(
|
|
850
|
+
new Camera.PreviewCallback() {
|
|
851
|
+
@Override
|
|
852
|
+
public void onPreviewFrame(byte[] bytes, Camera camera) {
|
|
853
|
+
try {
|
|
854
|
+
Camera.Parameters parameters = camera.getParameters();
|
|
855
|
+
Camera.Size size = parameters.getPreviewSize();
|
|
856
|
+
int orientation = mPreview.getDisplayOrientation();
|
|
857
|
+
if (
|
|
858
|
+
mPreview.getCameraFacing() ==
|
|
859
|
+
Camera.CameraInfo.CAMERA_FACING_FRONT
|
|
860
|
+
) {
|
|
861
|
+
bytes =
|
|
862
|
+
rotateNV21(
|
|
863
|
+
bytes,
|
|
864
|
+
size.width,
|
|
865
|
+
size.height,
|
|
866
|
+
(360 - orientation) % 360
|
|
867
|
+
);
|
|
849
868
|
} else {
|
|
850
|
-
|
|
851
|
-
profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_480P);
|
|
852
|
-
} else {
|
|
853
|
-
if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_720P)) {
|
|
854
|
-
profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_720P);
|
|
855
|
-
} else {
|
|
856
|
-
if (CamcorderProfile.hasProfile(defaultCameraId, CamcorderProfile.QUALITY_1080P)) {
|
|
857
|
-
profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_1080P);
|
|
858
|
-
} else {
|
|
859
|
-
profile = CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_LOW);
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
}
|
|
869
|
+
bytes = rotateNV21(bytes, size.width, size.height, orientation);
|
|
863
870
|
}
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
871
|
+
// switch width/height when rotating 90/270 deg
|
|
872
|
+
Rect rect = orientation == 90 || orientation == 270
|
|
873
|
+
? new Rect(0, 0, size.height, size.width)
|
|
874
|
+
: new Rect(0, 0, size.width, size.height);
|
|
875
|
+
YuvImage yuvImage = new YuvImage(
|
|
876
|
+
bytes,
|
|
877
|
+
parameters.getPreviewFormat(),
|
|
878
|
+
rect.width(),
|
|
879
|
+
rect.height(),
|
|
880
|
+
null
|
|
881
|
+
);
|
|
882
|
+
ByteArrayOutputStream byteArrayOutputStream =
|
|
883
|
+
new ByteArrayOutputStream();
|
|
884
|
+
yuvImage.compressToJpeg(rect, quality, byteArrayOutputStream);
|
|
885
|
+
byte[] data = byteArrayOutputStream.toByteArray();
|
|
886
|
+
byteArrayOutputStream.close();
|
|
887
|
+
eventListener.onSnapshotTaken(
|
|
888
|
+
Base64.encodeToString(data, Base64.NO_WRAP)
|
|
889
|
+
);
|
|
890
|
+
} catch (IOException e) {
|
|
891
|
+
Log.d(TAG, "CameraPreview IOException");
|
|
892
|
+
eventListener.onSnapshotTakenError("IO Error");
|
|
893
|
+
} finally {
|
|
894
|
+
mCamera.setPreviewCallback(null);
|
|
895
|
+
}
|
|
878
896
|
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
897
|
+
}
|
|
898
|
+
);
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
public void takePicture(
|
|
902
|
+
final int width,
|
|
903
|
+
final int height,
|
|
904
|
+
final int quality
|
|
905
|
+
) {
|
|
906
|
+
Log.d(
|
|
907
|
+
TAG,
|
|
908
|
+
"CameraPreview takePicture width: " +
|
|
909
|
+
width +
|
|
910
|
+
", height: " +
|
|
911
|
+
height +
|
|
912
|
+
", quality: " +
|
|
913
|
+
quality
|
|
914
|
+
);
|
|
915
|
+
|
|
916
|
+
if (mPreview != null) {
|
|
917
|
+
if (!canTakePicture) {
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
canTakePicture = false;
|
|
922
|
+
|
|
923
|
+
new Thread() {
|
|
924
|
+
public void run() {
|
|
925
|
+
Camera.Parameters params = mCamera.getParameters();
|
|
926
|
+
|
|
927
|
+
Camera.Size size = getOptimalPictureSize(
|
|
928
|
+
width,
|
|
929
|
+
height,
|
|
930
|
+
params.getPreviewSize(),
|
|
931
|
+
params.getSupportedPictureSizes()
|
|
932
|
+
);
|
|
933
|
+
params.setPictureSize(size.width, size.height);
|
|
934
|
+
currentQuality = quality;
|
|
935
|
+
|
|
936
|
+
if (
|
|
937
|
+
cameraCurrentlyLocked == Camera.CameraInfo.CAMERA_FACING_FRONT &&
|
|
938
|
+
!storeToFile
|
|
939
|
+
) {
|
|
940
|
+
// The image will be recompressed in the callback
|
|
941
|
+
params.setJpegQuality(99);
|
|
942
|
+
} else {
|
|
943
|
+
params.setJpegQuality(quality);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
if (
|
|
947
|
+
cameraCurrentlyLocked == Camera.CameraInfo.CAMERA_FACING_FRONT &&
|
|
948
|
+
disableExifHeaderStripping
|
|
949
|
+
) {
|
|
950
|
+
Activity activity = getActivity();
|
|
951
|
+
int rotation = activity
|
|
952
|
+
.getWindowManager()
|
|
953
|
+
.getDefaultDisplay()
|
|
954
|
+
.getRotation();
|
|
955
|
+
int degrees = 0;
|
|
956
|
+
switch (rotation) {
|
|
957
|
+
case Surface.ROTATION_0:
|
|
894
958
|
degrees = 0;
|
|
895
959
|
break;
|
|
896
|
-
|
|
897
|
-
degrees = 90;
|
|
898
|
-
break;
|
|
899
|
-
case Surface.ROTATION_180:
|
|
960
|
+
case Surface.ROTATION_90:
|
|
900
961
|
degrees = 180;
|
|
901
962
|
break;
|
|
902
|
-
|
|
963
|
+
case Surface.ROTATION_180:
|
|
903
964
|
degrees = 270;
|
|
904
965
|
break;
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
orientation
|
|
910
|
-
|
|
966
|
+
case Surface.ROTATION_270:
|
|
967
|
+
degrees = 0;
|
|
968
|
+
break;
|
|
969
|
+
}
|
|
970
|
+
int orientation;
|
|
971
|
+
Camera.CameraInfo info = new Camera.CameraInfo();
|
|
972
|
+
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
|
973
|
+
orientation = (info.orientation + degrees) % 360;
|
|
974
|
+
if (degrees != 0) {
|
|
911
975
|
orientation = (360 - orientation) % 360;
|
|
976
|
+
}
|
|
977
|
+
} else {
|
|
978
|
+
orientation = (info.orientation - degrees + 360) % 360;
|
|
912
979
|
}
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
980
|
+
params.setRotation(orientation);
|
|
981
|
+
} else {
|
|
982
|
+
params.setRotation(mPreview.getDisplayOrientation());
|
|
983
|
+
}
|
|
917
984
|
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
public void stopRecord() {
|
|
922
|
-
Log.d(TAG, "stopRecord");
|
|
923
|
-
|
|
924
|
-
try {
|
|
925
|
-
mRecorder.stop();
|
|
926
|
-
mRecorder.reset(); // clear recorder configuration
|
|
927
|
-
mRecorder.release(); // release the recorder object
|
|
928
|
-
mRecorder = null;
|
|
929
|
-
mCamera.lock();
|
|
930
|
-
Camera.Parameters cameraParams = mCamera.getParameters();
|
|
931
|
-
cameraParams.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
|
|
932
|
-
mCamera.setParameters(cameraParams);
|
|
933
|
-
mCamera.startPreview();
|
|
934
|
-
eventListener.onStopRecordVideo(this.recordFilePath);
|
|
935
|
-
} catch (Exception e) {
|
|
936
|
-
eventListener.onStopRecordVideoError(e.getMessage());
|
|
985
|
+
mCamera.setParameters(params);
|
|
986
|
+
mCamera.takePicture(shutterCallback, null, jpegPictureCallback);
|
|
937
987
|
}
|
|
988
|
+
}
|
|
989
|
+
.start();
|
|
990
|
+
} else {
|
|
991
|
+
canTakePicture = true;
|
|
938
992
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
public void startRecord(
|
|
996
|
+
final String filePath,
|
|
997
|
+
final String camera,
|
|
998
|
+
final int width,
|
|
999
|
+
final int height,
|
|
1000
|
+
final int quality,
|
|
1001
|
+
final boolean withFlash,
|
|
1002
|
+
final int maxDuration
|
|
1003
|
+
) {
|
|
1004
|
+
Log.d(
|
|
1005
|
+
TAG,
|
|
1006
|
+
"CameraPreview startRecord camera: " +
|
|
1007
|
+
camera +
|
|
1008
|
+
" width: " +
|
|
1009
|
+
width +
|
|
1010
|
+
", height: " +
|
|
1011
|
+
height +
|
|
1012
|
+
", quality: " +
|
|
1013
|
+
quality
|
|
1014
|
+
);
|
|
1015
|
+
Activity activity = getActivity();
|
|
1016
|
+
muteStream(true, activity);
|
|
1017
|
+
if (this.mRecordingState == RecordingState.STARTED) {
|
|
1018
|
+
Log.d(TAG, "Already Recording");
|
|
1019
|
+
return;
|
|
943
1020
|
}
|
|
944
1021
|
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
1022
|
+
this.recordFilePath = filePath;
|
|
1023
|
+
int mOrientationHint = calculateOrientationHint();
|
|
1024
|
+
int videoWidth = 0; //set whatever
|
|
1025
|
+
int videoHeight = 0; //set whatever
|
|
1026
|
+
|
|
1027
|
+
Camera.Parameters cameraParams = mCamera.getParameters();
|
|
1028
|
+
if (withFlash) {
|
|
1029
|
+
cameraParams.setFlashMode(
|
|
1030
|
+
withFlash
|
|
1031
|
+
? Camera.Parameters.FLASH_MODE_TORCH
|
|
1032
|
+
: Camera.Parameters.FLASH_MODE_OFF
|
|
1033
|
+
);
|
|
1034
|
+
mCamera.setParameters(cameraParams);
|
|
1035
|
+
mCamera.startPreview();
|
|
1036
|
+
}
|
|
959
1037
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1038
|
+
mCamera.unlock();
|
|
1039
|
+
mRecorder = new MediaRecorder();
|
|
1040
|
+
|
|
1041
|
+
try {
|
|
1042
|
+
mRecorder.setCamera(mCamera);
|
|
1043
|
+
|
|
1044
|
+
CamcorderProfile profile;
|
|
1045
|
+
if (
|
|
1046
|
+
CamcorderProfile.hasProfile(
|
|
1047
|
+
defaultCameraId,
|
|
1048
|
+
CamcorderProfile.QUALITY_HIGH
|
|
1049
|
+
)
|
|
1050
|
+
) {
|
|
1051
|
+
profile =
|
|
1052
|
+
CamcorderProfile.get(defaultCameraId, CamcorderProfile.QUALITY_HIGH);
|
|
1053
|
+
} else {
|
|
1054
|
+
if (
|
|
1055
|
+
CamcorderProfile.hasProfile(
|
|
1056
|
+
defaultCameraId,
|
|
1057
|
+
CamcorderProfile.QUALITY_480P
|
|
1058
|
+
)
|
|
1059
|
+
) {
|
|
1060
|
+
profile =
|
|
1061
|
+
CamcorderProfile.get(
|
|
1062
|
+
defaultCameraId,
|
|
1063
|
+
CamcorderProfile.QUALITY_480P
|
|
1064
|
+
);
|
|
1065
|
+
} else {
|
|
1066
|
+
if (
|
|
1067
|
+
CamcorderProfile.hasProfile(
|
|
1068
|
+
defaultCameraId,
|
|
1069
|
+
CamcorderProfile.QUALITY_720P
|
|
1070
|
+
)
|
|
1071
|
+
) {
|
|
1072
|
+
profile =
|
|
1073
|
+
CamcorderProfile.get(
|
|
1074
|
+
defaultCameraId,
|
|
1075
|
+
CamcorderProfile.QUALITY_720P
|
|
1076
|
+
);
|
|
1077
|
+
} else {
|
|
1078
|
+
if (
|
|
1079
|
+
CamcorderProfile.hasProfile(
|
|
1080
|
+
defaultCameraId,
|
|
1081
|
+
CamcorderProfile.QUALITY_1080P
|
|
1082
|
+
)
|
|
1083
|
+
) {
|
|
1084
|
+
profile =
|
|
1085
|
+
CamcorderProfile.get(
|
|
1086
|
+
defaultCameraId,
|
|
1087
|
+
CamcorderProfile.QUALITY_1080P
|
|
1088
|
+
);
|
|
1089
|
+
} else {
|
|
1090
|
+
profile =
|
|
1091
|
+
CamcorderProfile.get(
|
|
1092
|
+
defaultCameraId,
|
|
1093
|
+
CamcorderProfile.QUALITY_LOW
|
|
1094
|
+
);
|
|
966
1095
|
}
|
|
1096
|
+
}
|
|
967
1097
|
}
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
mRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_RECOGNITION);
|
|
1101
|
+
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
|
|
1102
|
+
mRecorder.setProfile(profile);
|
|
1103
|
+
mRecorder.setOutputFile(filePath);
|
|
1104
|
+
mRecorder.setOrientationHint(mOrientationHint);
|
|
1105
|
+
mRecorder.setMaxDuration(maxDuration);
|
|
1106
|
+
|
|
1107
|
+
mRecorder.prepare();
|
|
1108
|
+
Log.d(TAG, "Starting recording");
|
|
1109
|
+
mRecorder.start();
|
|
1110
|
+
eventListener.onStartRecordVideo();
|
|
1111
|
+
} catch (IOException e) {
|
|
1112
|
+
eventListener.onStartRecordVideoError(e.getMessage());
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
public int calculateOrientationHint() {
|
|
1117
|
+
DisplayMetrics dm = new DisplayMetrics();
|
|
1118
|
+
Camera.CameraInfo info = new Camera.CameraInfo();
|
|
1119
|
+
Camera.getCameraInfo(defaultCameraId, info);
|
|
1120
|
+
int cameraRotationOffset = info.orientation;
|
|
1121
|
+
Activity activity = getActivity();
|
|
1122
|
+
|
|
1123
|
+
activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
|
|
1124
|
+
int currentScreenRotation = activity
|
|
1125
|
+
.getWindowManager()
|
|
1126
|
+
.getDefaultDisplay()
|
|
1127
|
+
.getRotation();
|
|
1128
|
+
|
|
1129
|
+
int degrees = 0;
|
|
1130
|
+
switch (currentScreenRotation) {
|
|
1131
|
+
case Surface.ROTATION_0:
|
|
1132
|
+
degrees = 0;
|
|
1133
|
+
break;
|
|
1134
|
+
case Surface.ROTATION_90:
|
|
1135
|
+
degrees = 90;
|
|
1136
|
+
break;
|
|
1137
|
+
case Surface.ROTATION_180:
|
|
1138
|
+
degrees = 180;
|
|
1139
|
+
break;
|
|
1140
|
+
case Surface.ROTATION_270:
|
|
1141
|
+
degrees = 270;
|
|
1142
|
+
break;
|
|
968
1143
|
}
|
|
969
1144
|
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1145
|
+
int orientation;
|
|
1146
|
+
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
|
1147
|
+
orientation = (cameraRotationOffset + degrees) % 360;
|
|
1148
|
+
if (degrees != 0) {
|
|
1149
|
+
orientation = (360 - orientation) % 360;
|
|
1150
|
+
}
|
|
1151
|
+
} else {
|
|
1152
|
+
orientation = (cameraRotationOffset - degrees + 360) % 360;
|
|
1153
|
+
}
|
|
1154
|
+
Log.w(TAG, "************orientationHint ***********= " + orientation);
|
|
1155
|
+
|
|
1156
|
+
return orientation;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
public void stopRecord() {
|
|
1160
|
+
Log.d(TAG, "stopRecord");
|
|
1161
|
+
|
|
1162
|
+
try {
|
|
1163
|
+
mRecorder.stop();
|
|
1164
|
+
mRecorder.reset(); // clear recorder configuration
|
|
1165
|
+
mRecorder.release(); // release the recorder object
|
|
1166
|
+
mRecorder = null;
|
|
1167
|
+
mCamera.lock();
|
|
1168
|
+
Camera.Parameters cameraParams = mCamera.getParameters();
|
|
1169
|
+
cameraParams.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
|
|
1170
|
+
mCamera.setParameters(cameraParams);
|
|
1171
|
+
mCamera.startPreview();
|
|
1172
|
+
eventListener.onStopRecordVideo(this.recordFilePath);
|
|
1173
|
+
} catch (Exception e) {
|
|
1174
|
+
eventListener.onStopRecordVideoError(e.getMessage());
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
public void muteStream(boolean mute, Activity activity) {
|
|
1179
|
+
AudioManager audioManager =
|
|
1180
|
+
(
|
|
1181
|
+
(AudioManager) activity
|
|
1182
|
+
.getApplicationContext()
|
|
1183
|
+
.getSystemService(Context.AUDIO_SERVICE)
|
|
1184
|
+
);
|
|
1185
|
+
int direction = mute
|
|
1186
|
+
? audioManager.ADJUST_MUTE
|
|
1187
|
+
: audioManager.ADJUST_UNMUTE;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
public void setFocusArea(
|
|
1191
|
+
final int pointX,
|
|
1192
|
+
final int pointY,
|
|
1193
|
+
final Camera.AutoFocusCallback callback
|
|
1194
|
+
) {
|
|
1195
|
+
if (mCamera != null) {
|
|
1196
|
+
mCamera.cancelAutoFocus();
|
|
1197
|
+
|
|
1198
|
+
Camera.Parameters parameters = mCamera.getParameters();
|
|
1199
|
+
|
|
1200
|
+
Rect focusRect = calculateTapArea(pointX, pointY, 1f);
|
|
1201
|
+
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
|
|
1202
|
+
parameters.setFocusAreas(Arrays.asList(new Camera.Area(focusRect, 1000)));
|
|
1203
|
+
|
|
1204
|
+
if (parameters.getMaxNumMeteringAreas() > 0) {
|
|
1205
|
+
Rect meteringRect = calculateTapArea(pointX, pointY, 1.5f);
|
|
1206
|
+
parameters.setMeteringAreas(
|
|
1207
|
+
Arrays.asList(new Camera.Area(meteringRect, 1000))
|
|
988
1208
|
);
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
try {
|
|
1212
|
+
setCameraParameters(parameters);
|
|
1213
|
+
mCamera.autoFocus(callback);
|
|
1214
|
+
} catch (Exception e) {
|
|
1215
|
+
Log.d(TAG, e.getMessage());
|
|
1216
|
+
callback.onAutoFocus(false, this.mCamera);
|
|
1217
|
+
}
|
|
989
1218
|
}
|
|
1219
|
+
}
|
|
990
1220
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1221
|
+
private Rect calculateTapArea(float x, float y, float coefficient) {
|
|
1222
|
+
if (x < 100) {
|
|
1223
|
+
x = 100;
|
|
1224
|
+
}
|
|
1225
|
+
if (x > width - 100) {
|
|
1226
|
+
x = width - 100;
|
|
1227
|
+
}
|
|
1228
|
+
if (y < 100) {
|
|
1229
|
+
y = 100;
|
|
1230
|
+
}
|
|
1231
|
+
if (y > height - 100) {
|
|
1232
|
+
y = height - 100;
|
|
999
1233
|
}
|
|
1234
|
+
return new Rect(
|
|
1235
|
+
Math.round((x - 100) * 2000 / width - 1000),
|
|
1236
|
+
Math.round((y - 100) * 2000 / height - 1000),
|
|
1237
|
+
Math.round((x + 100) * 2000 / width - 1000),
|
|
1238
|
+
Math.round((y + 100) * 2000 / height - 1000)
|
|
1239
|
+
);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
/**
|
|
1243
|
+
* Determine the space between the first two fingers
|
|
1244
|
+
*/
|
|
1245
|
+
private static float getFingerSpacing(MotionEvent event) {
|
|
1246
|
+
// ...
|
|
1247
|
+
float x = event.getX(0) - event.getX(1);
|
|
1248
|
+
float y = event.getY(0) - event.getY(1);
|
|
1249
|
+
return (float) Math.sqrt(x * x + y * y);
|
|
1250
|
+
}
|
|
1000
1251
|
}
|