That fuck shit the fascists are using
1package org.tm.archive.mediasend;
2
3import android.graphics.SurfaceTexture;
4import android.hardware.Camera;
5import android.view.Surface;
6
7import androidx.annotation.NonNull;
8
9import org.signal.core.util.logging.Log;
10
11import java.util.Collections;
12import java.util.Comparator;
13import java.util.List;
14
15class Camera1Controller {
16
17 private static final String TAG = Log.tag(Camera1Controller.class);
18
19 private final int screenWidth;
20 private final int screenHeight;
21 private final OrderEnforcer<Stage> enforcer;
22 private final EventListener eventListener;
23
24 private Camera camera;
25 private int cameraId;
26 private SurfaceTexture previewSurface;
27 private int screenRotation;
28
29 Camera1Controller(int preferredDirection, int screenWidth, int screenHeight, @NonNull EventListener eventListener) {
30 this.eventListener = eventListener;
31 this.enforcer = new OrderEnforcer<>(Stage.INITIALIZED, Stage.PREVIEW_STARTED);
32 this.cameraId = Camera.getNumberOfCameras() > 1 ? preferredDirection : Camera.CameraInfo.CAMERA_FACING_BACK;
33 this.screenWidth = screenWidth;
34 this.screenHeight = screenHeight;
35 }
36
37 void initialize() {
38 Log.d(TAG, "initialize()");
39
40 if (Camera.getNumberOfCameras() <= 0) {
41 Log.w(TAG, "Device doesn't have any cameras.");
42 onCameraUnavailable();
43 return;
44 }
45
46 try {
47 camera = Camera.open(cameraId);
48 } catch (Exception e) {
49 Log.w(TAG, "Failed to open camera.", e);
50 onCameraUnavailable();
51 return;
52 }
53
54 if (camera == null) {
55 Log.w(TAG, "Null camera instance.");
56 onCameraUnavailable();
57 return;
58 }
59
60 Camera.Parameters params = camera.getParameters();
61 Camera.Size previewSize = getClosestSize(camera.getParameters().getSupportedPreviewSizes(), screenWidth, screenHeight);
62 Camera.Size pictureSize = getClosestSize(camera.getParameters().getSupportedPictureSizes(), screenWidth, screenHeight);
63 final List<String> focusModes = params.getSupportedFocusModes();
64
65 Log.d(TAG, "Preview size: " + previewSize.width + "x" + previewSize.height + " Picture size: " + pictureSize.width + "x" + pictureSize.height);
66
67 params.setPreviewSize(previewSize.width, previewSize.height);
68 params.setPictureSize(pictureSize.width, pictureSize.height);
69 params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
70 params.setColorEffect(Camera.Parameters.EFFECT_NONE);
71 params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
72
73 if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
74 params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
75 } else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
76 params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
77 }
78
79
80 camera.setParameters(params);
81
82 enforcer.markCompleted(Stage.INITIALIZED);
83
84 eventListener.onPropertiesAvailable(getProperties());
85 }
86
87 void release() {
88 Log.d(TAG, "release() called");
89 enforcer.run(Stage.INITIALIZED, () -> {
90 Log.d(TAG, "release() executing");
91 previewSurface = null;
92 camera.stopPreview();
93 camera.release();
94 enforcer.reset();
95 });
96 }
97
98 void linkSurface(@NonNull SurfaceTexture surfaceTexture) {
99 Log.d(TAG, "linkSurface() called");
100 enforcer.run(Stage.INITIALIZED, () -> {
101 try {
102 Log.d(TAG, "linkSurface() executing");
103 previewSurface = surfaceTexture;
104
105 camera.setPreviewTexture(surfaceTexture);
106 camera.startPreview();
107 enforcer.markCompleted(Stage.PREVIEW_STARTED);
108 } catch (Exception e) {
109 Log.w(TAG, "Failed to start preview.", e);
110 eventListener.onCameraUnavailable();
111 }
112 });
113 }
114
115 void capture(@NonNull CaptureCallback callback) {
116 enforcer.run(Stage.PREVIEW_STARTED, () -> {
117 camera.takePicture(null, null, null, (data, camera) -> {
118 callback.onCaptureAvailable(data, cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT);
119 });
120 });
121 }
122
123 boolean isCameraFacingFront() {
124 return cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT;
125 }
126
127 int flip() {
128 Log.d(TAG, "flip()");
129 SurfaceTexture surfaceTexture = previewSurface;
130 cameraId = (cameraId == Camera.CameraInfo.CAMERA_FACING_BACK) ? Camera.CameraInfo.CAMERA_FACING_FRONT : Camera.CameraInfo.CAMERA_FACING_BACK;
131
132 release();
133 initialize();
134 linkSurface(surfaceTexture);
135 setScreenRotation(screenRotation);
136
137 return cameraId;
138 }
139
140 void setScreenRotation(int screenRotation) {
141 Log.d(TAG, "setScreenRotation(" + screenRotation + ") called");
142 enforcer.run(Stage.PREVIEW_STARTED, () -> {
143 Log.d(TAG, "setScreenRotation(" + screenRotation + ") executing");
144 this.screenRotation = screenRotation;
145
146 int previewRotation = getPreviewRotation(screenRotation);
147 int outputRotation = getOutputRotation(screenRotation);
148
149 Log.d(TAG, "Preview rotation: " + previewRotation + " Output rotation: " + outputRotation);
150
151 camera.setDisplayOrientation(previewRotation);
152
153 Camera.Parameters params = camera.getParameters();
154 params.setRotation(outputRotation);
155 camera.setParameters(params);
156 });
157 }
158
159 private void onCameraUnavailable() {
160 enforcer.reset();
161 eventListener.onCameraUnavailable();
162 }
163
164 private Properties getProperties() {
165 Camera.Size previewSize = camera.getParameters().getPreviewSize();
166 return new Properties(Camera.getNumberOfCameras(), previewSize.width, previewSize.height);
167 }
168
169 private Camera.Size getClosestSize(List<Camera.Size> sizes, int width, int height) {
170 Collections.sort(sizes, ASC_SIZE_COMPARATOR);
171
172 int i = 0;
173 while (i < sizes.size() && (sizes.get(i).width * sizes.get(i).height) < (width * height)) {
174 i++;
175 }
176 i++;
177
178 return sizes.get(Math.min(i, sizes.size() - 1));
179 }
180
181 private int getOutputRotation(int displayRotationCode) {
182 int degrees = convertRotationToDegrees(displayRotationCode);
183
184 Camera.CameraInfo info = new Camera.CameraInfo();
185 Camera.getCameraInfo(cameraId, info);
186
187 if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
188 return (info.orientation + degrees) % 360;
189 } else {
190 return (info.orientation - degrees + 360) % 360;
191 }
192 }
193
194 private int getPreviewRotation(int displayRotationCode) {
195 int degrees = convertRotationToDegrees(displayRotationCode);
196
197 Camera.CameraInfo info = new Camera.CameraInfo();
198 Camera.getCameraInfo(cameraId, info);
199
200 int result;
201 if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
202 result = (info.orientation + degrees) % 360;
203 result = (360 - result) % 360;
204 } else {
205 result = (info.orientation - degrees + 360) % 360;
206 }
207
208 return result;
209 }
210
211 private int convertRotationToDegrees(int screenRotation) {
212 switch (screenRotation) {
213 case Surface.ROTATION_0: return 0;
214 case Surface.ROTATION_90: return 90;
215 case Surface.ROTATION_180: return 180;
216 case Surface.ROTATION_270: return 270;
217 }
218 return 0;
219 }
220
221 private final Comparator<Camera.Size> ASC_SIZE_COMPARATOR = (o1, o2) -> Integer.compare(o1.width * o1.height, o2.width * o2.height);
222
223 private enum Stage {
224 INITIALIZED, PREVIEW_STARTED
225 }
226
227 class Properties {
228
229 private final int cameraCount;
230 private final int previewWidth;
231 private final int previewHeight;
232
233 Properties(int cameraCount, int previewWidth, int previewHeight) {
234 this.cameraCount = cameraCount;
235 this.previewWidth = previewWidth;
236 this.previewHeight = previewHeight;
237 }
238
239 int getCameraCount() {
240 return cameraCount;
241 }
242
243 int getPreviewWidth() {
244 return previewWidth;
245 }
246
247 int getPreviewHeight() {
248 return previewHeight;
249 }
250
251 @Override
252 public @NonNull String toString() {
253 return "cameraCount: " + cameraCount + " previewWidth: " + previewWidth + " previewHeight: " + previewHeight;
254 }
255 }
256
257 interface EventListener {
258 void onPropertiesAvailable(@NonNull Properties properties);
259 void onCameraUnavailable();
260 }
261
262 interface CaptureCallback {
263 void onCaptureAvailable(@NonNull byte[] jpegData, boolean frontFacing);
264 }
265}