remove deprecated half-camera dependency

This commit is contained in:
adbenitez 2025-02-04 18:40:02 +01:00
parent cd07f3de96
commit 5ce1f415ce
11 changed files with 3 additions and 1448 deletions

View file

@ -184,7 +184,6 @@ dependencies {
annotationProcessor 'androidx.annotation:annotation:1.9.1'
implementation 'com.makeramen:roundedimageview:2.1.0' // crops the avatars to circles
implementation 'com.pnikosis:materialish-progress:1.5' // used only in the "Progress Wheel" in Share Activity.
implementation 'com.nineoldandroids:library:2.4.0' // DEPRECATED! Used to slide in the half-camera.
implementation 'com.github.amulyakhare:TextDrawable:558677ea31' // number of unread messages,
// the one-letter circle for the contacts (when there is not avatar) and a white background.
implementation 'com.googlecode.mp4parser:isoparser:1.0.6' // MP4 recoding; upgrading eg. to 1.1.22 breaks recoding, however, i have not investigated further, just reset to 1.0.6

View file

@ -88,9 +88,6 @@ import org.thoughtcrime.securesms.components.InputPanel;
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout.OnKeyboardShownListener;
import org.thoughtcrime.securesms.components.ScaleStableImageView;
import org.thoughtcrime.securesms.components.SendButton;
import org.thoughtcrime.securesms.components.camera.QuickAttachmentDrawer;
import org.thoughtcrime.securesms.components.camera.QuickAttachmentDrawer.AttachmentDrawerListener;
import org.thoughtcrime.securesms.components.camera.QuickAttachmentDrawer.DrawerState;
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard;
import org.thoughtcrime.securesms.connect.AccountManager;
import org.thoughtcrime.securesms.connect.DcEventCenter;
@ -142,7 +139,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
SearchView.OnQueryTextListener,
DcEventCenter.DcEventDelegate,
OnKeyboardShownListener,
AttachmentDrawerListener,
InputPanel.Listener,
InputPanel.MediaListener
{
@ -181,7 +177,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
private FrameLayout emojiPickerContainer;
private MediaKeyboard emojiPicker;
protected HidingLinearLayout quickAttachmentToggle;
private QuickAttachmentDrawer quickAttachmentDrawer;
private InputPanel inputPanel;
private ApplicationContext context;
@ -291,7 +286,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
@Override
protected void onResume() {
super.onResume();
quickAttachmentDrawer.onResume();
initializeEnabledCheck();
composeText.setTransport(sendButton.getSelectedTransport());
@ -311,7 +305,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
DcHelper.getNotificationCenter(this).clearVisibleChat();
if (isFinishing()) overridePendingTransition(R.anim.fade_scale_in, R.anim.slide_to_right);
quickAttachmentDrawer.onPause();
inputPanel.onPause();
AudioSlidePlayer.stopAll();
}
@ -321,7 +314,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
Log.i(TAG, "onConfigurationChanged(" + newConfig.orientation + ")");
super.onConfigurationChanged(newConfig);
composeText.setTransport(sendButton.getSelectedTransport());
quickAttachmentDrawer.onConfigurationChanged();
if (emojiPicker != null && container.getCurrentInput() == emojiPicker) {
container.hideAttachedInput(true);
@ -817,7 +809,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
emojiPickerContainer = ViewUtil.findById(this, R.id.emoji_picker_container);
composePanel = ViewUtil.findById(this, R.id.bottom_panel);
container = ViewUtil.findById(this, R.id.layout_container);
quickAttachmentDrawer = ViewUtil.findById(this, R.id.quick_attachment_drawer);
quickAttachmentToggle = ViewUtil.findById(this, R.id.quick_attachment_toggle);
inputPanel = ViewUtil.findById(this, R.id.bottom_panel);
backgroundView = ViewUtil.findById(this, R.id.conversation_background);
@ -857,8 +848,7 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
composeText.setOnClickListener(composeKeyPressedListener);
composeText.setOnFocusChangeListener(composeKeyPressedListener);
quickAttachmentDrawer.setListener(this);
quickCameraToggle.setOnClickListener(new QuickCameraToggleListener());
quickCameraToggle.setOnClickListener(v -> attachmentManager.capturePhoto(ConversationActivity.this, TAKE_PHOTO));
initializeBackground();
}
@ -1159,43 +1149,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
}
@Override
public void onAttachmentDrawerStateChanged(DrawerState drawerState) {
ActionBar supportActionBar = getSupportActionBar();
if (supportActionBar == null) throw new AssertionError();
if (drawerState == DrawerState.FULL_EXPANDED) {
supportActionBar.hide();
} else {
supportActionBar.show();
}
if (drawerState == DrawerState.COLLAPSED) {
container.hideAttachedInput(true);
}
}
@Override
public void onImageCapture(@NonNull final byte[] imageBytes) {
setMedia(PersistentBlobProvider.getInstance()
.create(this, imageBytes, MediaUtil.IMAGE_JPEG, "image.jpeg"),
MediaType.IMAGE);
quickAttachmentDrawer.hide(false);
}
@Override
public void onCameraFail() {
Toast.makeText(this, R.string.chat_camera_unavailable, Toast.LENGTH_SHORT).show();
quickAttachmentDrawer.hide(false);
quickAttachmentToggle.disable();
}
@Override
public void onCameraStart() {}
@Override
public void onCameraStop() {}
@Override
public void onRecorderPermissionRequired() {
Permissions.with(this)
@ -1350,31 +1303,6 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
}
}
private class QuickCameraToggleListener implements OnClickListener {
@Override
public void onClick(View v) {
fragment.hideAddReactionView();
if (Prefs.isBuiltInCameraPreferred(ConversationActivity.this)
&& QuickAttachmentDrawer.isDeviceSupported(ConversationActivity.this)) {
if (!quickAttachmentDrawer.isShowing()) {
Permissions.with(ConversationActivity.this)
.request(Manifest.permission.CAMERA)
.ifNecessary()
.withPermanentDenialDialog(getString(R.string.perm_explain_access_to_camera_denied))
.onAllGranted(() -> {
composeText.clearFocus();
container.show(composeText, quickAttachmentDrawer);
})
.execute();
} else {
container.hideAttachedInput(false);
}
} else {
attachmentManager.capturePhoto(ConversationActivity.this, TAKE_PHOTO);
}
}
}
private class SendButtonListener implements OnClickListener, TextView.OnEditorActionListener {
@Override
public void onClick(View v) {

View file

@ -1,33 +0,0 @@
package org.thoughtcrime.securesms.components.camera;
import android.content.Context;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private boolean ready;
@SuppressWarnings("deprecation")
public CameraSurfaceView(Context context) {
super(context);
getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
getHolder().addCallback(this);
}
public boolean isReady() {
return ready;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
ready = true;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
ready = false;
}
}

View file

@ -1,106 +0,0 @@
package org.thoughtcrime.securesms.components.camera;
import android.app.Activity;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Surface;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
@SuppressWarnings("deprecation")
public class CameraUtils {
private static final String TAG = CameraUtils.class.getSimpleName();
/*
* modified from: https://github.com/commonsguy/cwac-camera/blob/master/camera/src/com/commonsware/cwac/camera/CameraUtils.java
*/
public static @Nullable Size getPreferredPreviewSize(int displayOrientation,
int width,
int height,
@NonNull Parameters parameters) {
final int targetWidth = displayOrientation % 180 == 90 ? height : width;
final int targetHeight = displayOrientation % 180 == 90 ? width : height;
final double targetRatio = (double) targetWidth / targetHeight;
Log.w(TAG, String.format("getPreferredPreviewSize(%d, %d, %d) -> target %dx%d, AR %.02f",
displayOrientation, width, height,
targetWidth, targetHeight, targetRatio));
List<Size> sizes = parameters.getSupportedPreviewSizes();
List<Size> ideals = new LinkedList<>();
List<Size> bigEnough = new LinkedList<>();
for (Size size : sizes) {
Log.w(TAG, String.format(" %dx%d (%.02f)", size.width, size.height, (float)size.width / size.height));
if (size.height == size.width * targetRatio && size.height >= targetHeight && size.width >= targetWidth) {
ideals.add(size);
Log.w(TAG, " (ideal ratio)");
} else if (size.width >= targetWidth && size.height >= targetHeight) {
bigEnough.add(size);
Log.w(TAG, " (good size, suboptimal ratio)");
}
}
if (!ideals.isEmpty()) return Collections.min(ideals, new AreaComparator());
else if (!bigEnough.isEmpty()) return Collections.min(bigEnough, new AspectRatioComparator(targetRatio));
else return Collections.max(sizes, new AreaComparator());
}
// based on
// http://developer.android.com/reference/android/hardware/Camera.html#setDisplayOrientation(int)
// and http://stackoverflow.com/a/10383164/115145
public static int getCameraDisplayOrientation(@NonNull Activity activity,
@NonNull CameraInfo info)
{
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
DisplayMetrics dm = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(dm);
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break;
case Surface.ROTATION_90: degrees = 90; break;
case Surface.ROTATION_180: degrees = 180; break;
case Surface.ROTATION_270: degrees = 270; break;
}
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
return (360 - ((info.orientation + degrees) % 360)) % 360;
} else {
return (info.orientation - degrees + 360) % 360;
}
}
private static class AreaComparator implements Comparator<Size> {
@Override
public int compare(Size lhs, Size rhs) {
return Long.signum(lhs.width * lhs.height - rhs.width * rhs.height);
}
}
private static class AspectRatioComparator extends AreaComparator {
private final double target;
public AspectRatioComparator(double target) {
this.target = target;
}
@Override
public int compare(Size lhs, Size rhs) {
final double lhsDiff = Math.abs(target - (double) lhs.width / lhs.height);
final double rhsDiff = Math.abs(target - (double) rhs.width / rhs.height);
if (lhsDiff < rhsDiff) return -1;
else if (lhsDiff > rhsDiff) return 1;
else return super.compare(lhs, rhs);
}
}
}

View file

@ -1,625 +0,0 @@
/***
Copyright (c) 2013-2014 CommonsWare, LLC
Portions Copyright (C) 2007 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package org.thoughtcrime.securesms.components.camera;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Rect;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Build.VERSION;
import android.util.AttributeSet;
import android.util.Log;
import android.view.OrientationEventListener;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.JobParameters;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.guava.Optional;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@SuppressWarnings("deprecation")
public class CameraView extends ViewGroup {
private static final String TAG = CameraView.class.getSimpleName();
private final CameraSurfaceView surface;
private final OnOrientationChange onOrientationChange;
private volatile Optional<Camera> camera = Optional.absent();
private volatile int cameraId = CameraInfo.CAMERA_FACING_BACK;
private volatile int displayOrientation = -1;
private @NonNull State state = State.PAUSED;
private @Nullable Size previewSize;
private final @NonNull List<CameraViewListener> listeners = Collections.synchronizedList(new LinkedList<CameraViewListener>());
private int outputOrientation = -1;
public CameraView(Context context) {
this(context, null);
}
public CameraView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CameraView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setBackgroundColor(Color.BLACK);
if (attrs != null) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CameraView);
int camera = typedArray.getInt(R.styleable.CameraView_camera, -1);
if (camera != -1) cameraId = camera;
else if (isMultiCamera()) cameraId = Prefs.getDirectCaptureCameraId(context);
typedArray.recycle();
}
surface = new CameraSurfaceView(getContext());
onOrientationChange = new OnOrientationChange(context.getApplicationContext());
addView(surface);
}
public void onResume() {
if (state != State.PAUSED) return;
state = State.RESUMED;
Log.w(TAG, "onResume() queued");
enqueueTask(new SerialAsyncTask<Void>() {
@Override
protected
@Nullable
Void onRunBackground() {
try {
long openStartMillis = System.currentTimeMillis();
camera = Optional.fromNullable(Camera.open(cameraId));
Log.w(TAG, "camera.open() -> " + (System.currentTimeMillis() - openStartMillis) + "ms");
synchronized (CameraView.this) {
CameraView.this.notifyAll();
}
if (camera.isPresent()) onCameraReady(camera.get());
} catch (Exception e) {
Log.w(TAG, e);
}
return null;
}
@Override
protected void onPostMain(Void avoid) {
if (!camera.isPresent()) {
Log.w(TAG, "tried to open camera but got null");
for (CameraViewListener listener : listeners) {
listener.onCameraFail();
}
return;
}
if (getActivity().getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
onOrientationChange.enable();
}
Log.w(TAG, "onResume() completed");
}
});
}
public void onPause() {
if (state == State.PAUSED) return;
state = State.PAUSED;
Log.w(TAG, "onPause() queued");
enqueueTask(new SerialAsyncTask<Void>() {
private Optional<Camera> cameraToDestroy;
@Override
protected void onPreMain() {
cameraToDestroy = camera;
camera = Optional.absent();
}
@Override
protected Void onRunBackground() {
if (cameraToDestroy.isPresent()) {
try {
stopPreview();
cameraToDestroy.get().setPreviewCallback(null);
cameraToDestroy.get().release();
Log.w(TAG, "released old camera instance");
} catch (Exception e) {
Log.w(TAG, e);
}
}
return null;
}
@Override protected void onPostMain(Void avoid) {
onOrientationChange.disable();
displayOrientation = -1;
outputOrientation = -1;
removeView(surface);
addView(surface);
Log.w(TAG, "onPause() completed");
}
});
for (CameraViewListener listener : listeners) {
listener.onCameraStop();
}
}
public boolean isStarted() {
return state != State.PAUSED;
}
@SuppressWarnings("SuspiciousNameCombination")
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int width = r - l;
final int height = b - t;
final int previewWidth;
final int previewHeight;
if (camera.isPresent() && previewSize != null) {
if (displayOrientation == 90 || displayOrientation == 270) {
previewWidth = previewSize.height;
previewHeight = previewSize.width;
} else {
previewWidth = previewSize.width;
previewHeight = previewSize.height;
}
} else {
previewWidth = width;
previewHeight = height;
}
if (previewHeight == 0 || previewWidth == 0) {
Log.i(TAG, "skipping layout due to zero-width/height preview size");
return;
}
if (width * previewHeight > height * previewWidth) {
final int scaledChildHeight = previewHeight * width / previewWidth;
surface.layout(0, (height - scaledChildHeight) / 2, width, (height + scaledChildHeight) / 2);
} else {
final int scaledChildWidth = previewWidth * height / previewHeight;
surface.layout((width - scaledChildWidth) / 2, 0, (width + scaledChildWidth) / 2, height);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Log.w(TAG, "onSizeChanged(" + oldw + "x" + oldh + " -> " + w + "x" + h + ")");
super.onSizeChanged(w, h, oldw, oldh);
if (camera.isPresent()) startPreview(camera.get().getParameters());
}
public void addListener(@NonNull CameraViewListener listener) {
listeners.add(listener);
}
public void setPreviewCallback(final @NonNull PreviewCallback previewCallback) {
enqueueTask(new PostInitializationTask<Void>() {
@Override
protected void onPostMain(Void avoid) {
if (camera.isPresent()) {
camera.get().setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
if (!CameraView.this.camera.isPresent()) {
return;
}
final int rotation = getCameraPictureOrientation();
final Size previewSize = camera.getParameters().getPreviewSize();
if (data != null) {
previewCallback.onPreviewFrame(new PreviewFrame(data, previewSize.width, previewSize.height, rotation));
}
}
});
}
}
});
}
public boolean isMultiCamera() {
return Camera.getNumberOfCameras() > 1;
}
public boolean isRearCamera() {
return cameraId == CameraInfo.CAMERA_FACING_BACK;
}
public void flipCamera() {
if (Camera.getNumberOfCameras() > 1) {
cameraId = cameraId == CameraInfo.CAMERA_FACING_BACK
? CameraInfo.CAMERA_FACING_FRONT
: CameraInfo.CAMERA_FACING_BACK;
onPause();
onResume();
Prefs.setDirectCaptureCameraId(getContext(), cameraId);
}
}
private void onCameraReady(final @NonNull Camera camera) {
final Parameters parameters = camera.getParameters();
parameters.setRecordingHint(true);
final List<String> focusModes = parameters.getSupportedFocusModes();
if (focusModes.contains(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else if (focusModes.contains(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
}
displayOrientation = CameraUtils.getCameraDisplayOrientation(getActivity(), getCameraInfo());
camera.setDisplayOrientation(displayOrientation);
camera.setParameters(parameters);
enqueueTask(new PostInitializationTask<Void>() {
@Override
protected Void onRunBackground() {
try {
camera.setPreviewDisplay(surface.getHolder());
startPreview(parameters);
} catch (Exception e) {
Log.w(TAG, "couldn't set preview display", e);
}
return null;
}
});
}
private void startPreview(final @NonNull Parameters parameters) {
if (this.camera.isPresent()) {
try {
final Camera camera = this.camera.get();
final Size preferredPreviewSize = getPreferredPreviewSize(parameters);
if (preferredPreviewSize != null && !parameters.getPreviewSize().equals(preferredPreviewSize)) {
Log.w(TAG, "starting preview with size " + preferredPreviewSize.width + "x" + preferredPreviewSize.height);
if (state == State.ACTIVE) stopPreview();
previewSize = preferredPreviewSize;
parameters.setPreviewSize(preferredPreviewSize.width, preferredPreviewSize.height);
camera.setParameters(parameters);
} else {
previewSize = parameters.getPreviewSize();
}
long previewStartMillis = System.currentTimeMillis();
camera.startPreview();
Log.w(TAG, "camera.startPreview() -> " + (System.currentTimeMillis() - previewStartMillis) + "ms");
state = State.ACTIVE;
Util.runOnMain(new Runnable() {
@Override
public void run() {
requestLayout();
for (CameraViewListener listener : listeners) {
listener.onCameraStart();
}
}
});
} catch (Exception e) {
Log.w(TAG, e);
}
}
}
private void stopPreview() {
if (camera.isPresent()) {
try {
camera.get().stopPreview();
state = State.RESUMED;
} catch (Exception e) {
Log.w(TAG, e);
}
}
}
private Size getPreferredPreviewSize(@NonNull Parameters parameters) {
return CameraUtils.getPreferredPreviewSize(displayOrientation,
getMeasuredWidth(),
getMeasuredHeight(),
parameters);
}
private int getCameraPictureOrientation() {
if (getActivity().getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
outputOrientation = getCameraPictureRotation(getActivity().getWindowManager()
.getDefaultDisplay()
.getOrientation());
} else if (getCameraInfo().facing == CameraInfo.CAMERA_FACING_FRONT) {
outputOrientation = (360 - displayOrientation) % 360;
} else {
outputOrientation = displayOrientation;
}
return outputOrientation;
}
// https://github.com/signalapp/Signal-Android/issues/4715
private boolean isTroublemaker() {
return getCameraInfo().facing == CameraInfo.CAMERA_FACING_FRONT &&
"JWR66Y".equals(Build.DISPLAY) &&
"yakju".equals(Build.PRODUCT);
}
private @NonNull CameraInfo getCameraInfo() {
final CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
return info;
}
// XXX this sucks
private Activity getActivity() {
return (Activity)getContext();
}
public int getCameraPictureRotation(int orientation) {
final CameraInfo info = getCameraInfo();
final int rotation;
orientation = (orientation + 45) / 90 * 90;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - orientation + 360) % 360;
} else {
rotation = (info.orientation + orientation) % 360;
}
return rotation;
}
private class OnOrientationChange extends OrientationEventListener {
public OnOrientationChange(Context context) {
super(context);
disable();
}
@Override
public void onOrientationChanged(int orientation) {
if (camera.isPresent() && orientation != ORIENTATION_UNKNOWN) {
int newOutputOrientation = getCameraPictureRotation(orientation);
if (newOutputOrientation != outputOrientation) {
outputOrientation = newOutputOrientation;
Camera.Parameters params = camera.get().getParameters();
params.setRotation(outputOrientation);
try {
camera.get().setParameters(params);
}
catch (Exception e) {
Log.e(TAG, "Exception updating camera parameters in orientation change", e);
}
}
}
}
}
public void takePicture(final Rect previewRect) {
if (!camera.isPresent() || camera.get().getParameters() == null) {
Log.w(TAG, "camera not in capture-ready state");
return;
}
camera.get().setOneShotPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, final Camera camera) {
final int rotation = getCameraPictureOrientation();
final Size previewSize = camera.getParameters().getPreviewSize();
final Rect croppingRect = getCroppedRect(previewSize, previewRect, rotation);
Log.w(TAG, "previewSize: " + previewSize.width + "x" + previewSize.height);
Log.w(TAG, "data bytes: " + data.length);
Log.w(TAG, "previewFormat: " + camera.getParameters().getPreviewFormat());
Log.w(TAG, "croppingRect: " + croppingRect.toString());
Log.w(TAG, "rotation: " + rotation);
new CaptureTask(previewSize, rotation, croppingRect).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, data);
}
});
}
private Rect getCroppedRect(Size cameraPreviewSize, Rect visibleRect, int rotation) {
final int previewWidth = cameraPreviewSize.width;
final int previewHeight = cameraPreviewSize.height;
if (rotation % 180 > 0) rotateRect(visibleRect);
float scale = (float) previewWidth / visibleRect.width();
if (visibleRect.height() * scale > previewHeight) {
scale = (float) previewHeight / visibleRect.height();
}
final float newWidth = visibleRect.width() * scale;
final float newHeight = visibleRect.height() * scale;
final float centerX = isTroublemaker() ? previewWidth - newWidth / 2 : previewWidth / 2;
final float centerY = previewHeight / 2;
visibleRect.set((int) (centerX - newWidth / 2),
(int) (centerY - newHeight / 2),
(int) (centerX + newWidth / 2),
(int) (centerY + newHeight / 2));
if (rotation % 180 > 0) rotateRect(visibleRect);
return visibleRect;
}
@SuppressWarnings("SuspiciousNameCombination")
private void rotateRect(Rect rect) {
rect.set(rect.top, rect.left, rect.bottom, rect.right);
}
private void enqueueTask(SerialAsyncTask job) {
ApplicationContext.getInstance(getContext()).getJobManager().add(job);
}
private static abstract class SerialAsyncTask<Result> extends Job {
public SerialAsyncTask() {
super(JobParameters.newBuilder().withGroupId(CameraView.class.getSimpleName()).create());
}
@Override public void onAdded() {}
@Override public final void onRun() {
try {
onWait();
Util.runOnMainSync(new Runnable() {
@Override public void run() {
onPreMain();
}
});
final Result result = onRunBackground();
Util.runOnMainSync(new Runnable() {
@Override public void run() {
onPostMain(result);
}
});
} catch (PreconditionsNotMetException e) {
Log.w(TAG, "skipping task, preconditions not met in onWait()");
}
}
@Override public boolean onShouldRetry(Exception e) {
return false;
}
@Override public void onCanceled() { }
protected void onWait() throws PreconditionsNotMetException {}
protected void onPreMain() {}
protected Result onRunBackground() { return null; }
protected void onPostMain(Result result) {}
}
private abstract class PostInitializationTask<Result> extends SerialAsyncTask<Result> {
@Override protected void onWait() throws PreconditionsNotMetException {
synchronized (CameraView.this) {
if (!camera.isPresent()) {
throw new PreconditionsNotMetException();
}
while (getMeasuredHeight() <= 0 || getMeasuredWidth() <= 0 || !surface.isReady()) {
Log.w(TAG, String.format("waiting. surface ready? %s", surface.isReady()));
Util.wait(CameraView.this, 0);
}
}
}
}
private class CaptureTask extends AsyncTask<byte[], Void, byte[]> {
private final Size previewSize;
private final int rotation;
private final Rect croppingRect;
public CaptureTask(Size previewSize, int rotation, Rect croppingRect) {
this.previewSize = previewSize;
this.rotation = rotation;
this.croppingRect = croppingRect;
}
@Override
protected byte[] doInBackground(byte[]... params) {
final byte[] data = params[0];
try {
return BitmapUtil.createFromNV21(data,
previewSize.width,
previewSize.height,
rotation,
croppingRect,
cameraId == CameraInfo.CAMERA_FACING_FRONT);
} catch (IOException e) {
Log.w(TAG, e);
return null;
}
}
@Override
protected void onPostExecute(byte[] imageBytes) {
if (imageBytes != null) {
for (CameraViewListener listener : listeners) {
listener.onImageCapture(imageBytes);
}
}
}
}
private static class PreconditionsNotMetException extends Exception {}
public interface CameraViewListener {
void onImageCapture(@NonNull final byte[] imageBytes);
void onCameraFail();
void onCameraStart();
void onCameraStop();
}
public interface PreviewCallback {
void onPreviewFrame(@NonNull PreviewFrame frame);
}
public static class PreviewFrame {
private final @NonNull byte[] data;
private final int width;
private final int height;
private final int orientation;
private PreviewFrame(@NonNull byte[] data, int width, int height, int orientation) {
this.data = data;
this.width = width;
this.height = height;
this.orientation = orientation;
}
public @NonNull byte[] getData() {
return data;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int getOrientation() {
return orientation;
}
}
private enum State {
PAUSED, RESUMED, ACTIVE
}
}

View file

@ -1,571 +0,0 @@
package org.thoughtcrime.securesms.components.camera;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.hardware.Camera;
import androidx.annotation.NonNull;
import androidx.core.view.MotionEventCompat;
import androidx.core.view.ViewCompat;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import androidx.customview.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import com.nineoldandroids.animation.ObjectAnimator;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.InputAwareLayout.InputView;
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout;
import org.thoughtcrime.securesms.components.camera.CameraView.CameraViewListener;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
public class QuickAttachmentDrawer extends ViewGroup implements InputView, CameraViewListener {
private static final String TAG = QuickAttachmentDrawer.class.getSimpleName();
private final ViewDragHelper dragHelper;
private CameraView cameraView;
private int coverViewPosition;
private KeyboardAwareLinearLayout container;
private View coverView;
private View controls;
private ImageButton fullScreenButton;
private ImageButton swapCameraButton;
private ImageButton shutterButton;
private int slideOffset;
private float initialMotionX;
private float initialMotionY;
private int rotation;
private AttachmentDrawerListener listener;
private int halfExpandedHeight;
private ObjectAnimator animator;
private DrawerState drawerState = DrawerState.COLLAPSED;
private final Rect drawChildrenRect = new Rect();
private boolean paused = false;
public QuickAttachmentDrawer(Context context) {
this(context, null);
}
public QuickAttachmentDrawer(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public QuickAttachmentDrawer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
dragHelper = ViewDragHelper.create(this, 1.f, new ViewDragHelperCallback());
initializeView();
updateHalfExpandedAnchorPoint();
onConfigurationChanged();
}
private void initializeView() {
inflate(getContext(), R.layout.quick_attachment_drawer, this);
cameraView = ViewUtil.findById(this, R.id.quick_camera);
updateControlsView();
coverViewPosition = getChildCount();
controls.setVisibility(GONE);
cameraView.setVisibility(GONE);
cameraView.addListener(this);
}
public static boolean isDeviceSupported(Context context) {
return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA) &&
Camera.getNumberOfCameras() > 0;
}
@Override
public boolean isShowing() {
return drawerState.isVisible();
}
@Override
public void hide(boolean immediate) {
setDrawerStateAndUpdate(DrawerState.COLLAPSED, immediate);
}
@Override
public void show(int height, boolean immediate) {
setDrawerStateAndUpdate(DrawerState.HALF_EXPANDED, immediate);
}
public void onConfigurationChanged() {
int rotation = ServiceUtil.getWindowManager(getContext()).getDefaultDisplay().getRotation();
final boolean rotationChanged = this.rotation != rotation;
this.rotation = rotation;
if (rotationChanged) {
updateControlsView();
setDrawerStateAndUpdate(drawerState, true);
if (isShowing()) {
cameraView.onPause();
cameraView.onResume();
}
}
}
private void updateControlsView() {
Log.w(TAG, "updateControlsView()");
View controls = LayoutInflater.from(getContext()).inflate(isLandscape() ? R.layout.quick_camera_controls_land
: R.layout.quick_camera_controls,
this, false);
shutterButton = (ImageButton) controls.findViewById(R.id.shutter_button);
swapCameraButton = (ImageButton) controls.findViewById(R.id.swap_camera_button);
fullScreenButton = (ImageButton) controls.findViewById(R.id.fullscreen_button);
if (cameraView.isMultiCamera()) {
swapCameraButton.setVisibility(View.VISIBLE);
swapCameraButton.setImageResource(cameraView.isRearCamera() ? R.drawable.quick_camera_front
: R.drawable.quick_camera_rear);
swapCameraButton.setOnClickListener(new CameraFlipClickListener());
}
shutterButton.setOnClickListener(new ShutterClickListener());
fullScreenButton.setOnClickListener(new FullscreenClickListener());
ViewUtil.swapChildInPlace(this, this.controls, controls, indexOfChild(cameraView) + 1);
this.controls = controls;
}
private boolean isLandscape() {
return rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270;
}
private View getCoverView() {
if (coverView == null) coverView = getChildAt(coverViewPosition);
return coverView;
}
private KeyboardAwareLinearLayout getContainer() {
if (container == null) container = (KeyboardAwareLinearLayout)getParent();
return container;
}
private void updateHalfExpandedAnchorPoint() {
if (getContainer() != null) {
halfExpandedHeight = getContainer().getKeyboardHeight();
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && drawerState == DrawerState.FULL_EXPANDED) {
setSlideOffset(getMeasuredHeight());
}
final int paddingLeft = getPaddingLeft();
final int paddingTop = getPaddingTop();
for (int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
final int childHeight = child.getMeasuredHeight();
int childTop = paddingTop;
int childLeft = paddingLeft;
int childBottom;
if (child == cameraView) {
childTop = computeCameraTopPosition(slideOffset);
childBottom = childTop + childHeight;
if (cameraView.getMeasuredWidth() < getMeasuredWidth())
childLeft = (getMeasuredWidth() - cameraView.getMeasuredWidth()) / 2 + paddingLeft;
} else if (child == controls) {
childBottom = getMeasuredHeight();
} else {
childTop = computeCoverTopPosition(slideOffset);
childBottom = childTop + childHeight;
}
final int childRight = childLeft + child.getMeasuredWidth();
child.layout(childLeft, childTop, childRight, childBottom);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException("Width must have an exact value or MATCH_PARENT");
} else if (heightMode != MeasureSpec.EXACTLY) {
throw new IllegalStateException("Height must have an exact value or MATCH_PARENT");
}
int layoutHeight = heightSize - getPaddingTop() - getPaddingBottom();
for (int i = 0; i < getChildCount(); i++) {
final View child = getChildAt(i);
final LayoutParams lp = child.getLayoutParams();
if (child.getVisibility() == GONE && i == 0) {
continue;
}
int childWidthSpec;
switch (lp.width) {
case LayoutParams.WRAP_CONTENT:
childWidthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.AT_MOST);
break;
case LayoutParams.MATCH_PARENT:
childWidthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
break;
default:
childWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
break;
}
int childHeightSpec;
switch (lp.height) {
case LayoutParams.WRAP_CONTENT:
childHeightSpec = MeasureSpec.makeMeasureSpec(layoutHeight, MeasureSpec.AT_MOST);
break;
case LayoutParams.MATCH_PARENT:
childHeightSpec = MeasureSpec.makeMeasureSpec(layoutHeight, MeasureSpec.EXACTLY);
break;
default:
childHeightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
break;
}
child.measure(childWidthSpec, childHeightSpec);
}
setMeasuredDimension(widthSize, heightSize);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (h != oldh) updateHalfExpandedAnchorPoint();
}
@Override
protected boolean drawChild(@NonNull Canvas canvas, @NonNull View child, long drawingTime) {
boolean result;
final int save = canvas.save();
canvas.getClipBounds(drawChildrenRect);
if (child == coverView) {
drawChildrenRect.bottom = Math.min(drawChildrenRect.bottom, child.getBottom());
} else if (coverView != null) {
drawChildrenRect.top = Math.max(drawChildrenRect.top, coverView.getBottom());
}
canvas.clipRect(drawChildrenRect);
result = super.drawChild(canvas, child, drawingTime);
canvas.restoreToCount(save);
return result;
}
@Override
public void computeScroll() {
if (dragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
if (slideOffset == 0 && cameraView.isStarted()) {
cameraView.onPause();
controls.setVisibility(GONE);
cameraView.setVisibility(GONE);
} else if (slideOffset != 0 && !cameraView.isStarted() & !paused) {
controls.setVisibility(VISIBLE);
cameraView.setVisibility(VISIBLE);
cameraView.onResume();
}
}
private void setDrawerState(DrawerState drawerState) {
switch (drawerState) {
case COLLAPSED:
fullScreenButton.setImageResource(R.drawable.quick_camera_fullscreen);
break;
case HALF_EXPANDED:
if (isLandscape()) {
setDrawerState(DrawerState.FULL_EXPANDED);
return;
}
fullScreenButton.setImageResource(R.drawable.quick_camera_fullscreen);
break;
case FULL_EXPANDED:
fullScreenButton.setImageResource(isLandscape() ? R.drawable.quick_camera_hide
: R.drawable.quick_camera_exit_fullscreen);
break;
}
if (listener != null && drawerState != this.drawerState) {
this.drawerState = drawerState;
listener.onAttachmentDrawerStateChanged(drawerState);
}
}
public void setSlideOffset(int slideOffset) {
this.slideOffset = slideOffset;
requestLayout();
}
public int getTargetSlideOffset() {
switch (drawerState) {
case FULL_EXPANDED: return getMeasuredHeight();
case HALF_EXPANDED: return halfExpandedHeight;
default: return 0;
}
}
public void setDrawerStateAndUpdate(final DrawerState requestedDrawerState) {
setDrawerStateAndUpdate(requestedDrawerState, false);
}
public void setDrawerStateAndUpdate(final DrawerState requestedDrawerState, boolean instant) {
DrawerState oldDrawerState = this.drawerState;
setDrawerState(requestedDrawerState);
if (oldDrawerState != drawerState) {
updateHalfExpandedAnchorPoint();
slideTo(getTargetSlideOffset(), instant);
}
}
public void setListener(AttachmentDrawerListener listener) {
this.listener = listener;
cameraView.addListener(listener);
}
@Override
public void onImageCapture(@NonNull byte[] imageBytes) {}
@Override
public void onCameraFail() {
swapCameraButton.setEnabled(false);
shutterButton.setEnabled(false);
}
@Override
public void onCameraStart() {
swapCameraButton.setEnabled(true);
shutterButton.setEnabled(true);
}
@Override
public void onCameraStop() {
swapCameraButton.setEnabled(false);
shutterButton.setEnabled(false);
}
public interface AttachmentDrawerListener extends CameraViewListener {
void onAttachmentDrawerStateChanged(DrawerState drawerState);
}
private class ViewDragHelperCallback extends ViewDragHelper.Callback {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child == controls;
}
@Override
public void onViewDragStateChanged(int state) {
if (dragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE) {
setDrawerState(drawerState);
slideOffset = getTargetSlideOffset();
requestLayout();
}
}
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
slideOffset = Util.clamp(slideOffset - dy, 0, getMeasuredHeight());
requestLayout();
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
if (releasedChild == controls) {
float direction = -yvel;
DrawerState drawerState = DrawerState.COLLAPSED;
if (direction > 1) {
drawerState = DrawerState.FULL_EXPANDED;
} else if (direction < -1) {
boolean halfExpand = (slideOffset > halfExpandedHeight && !isLandscape());
drawerState = halfExpand ? DrawerState.HALF_EXPANDED : DrawerState.COLLAPSED;
} else if (!isLandscape()) {
if (slideOffset >= (halfExpandedHeight + getMeasuredHeight()) / 2) {
drawerState = DrawerState.FULL_EXPANDED;
} else if (slideOffset >= halfExpandedHeight / 2) {
drawerState = DrawerState.HALF_EXPANDED;
}
}
setDrawerState(drawerState);
int slideOffset = getTargetSlideOffset();
dragHelper.captureChildView(coverView, 0);
dragHelper.settleCapturedViewAt(coverView.getLeft(), computeCoverTopPosition(slideOffset));
dragHelper.captureChildView(cameraView, 0);
dragHelper.settleCapturedViewAt(cameraView.getLeft(), computeCameraTopPosition(slideOffset));
ViewCompat.postInvalidateOnAnimation(QuickAttachmentDrawer.this);
}
}
@Override
public int getViewVerticalDragRange(View child) {
return getMeasuredHeight();
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return top;
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
final int action = MotionEventCompat.getActionMasked(event);
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
dragHelper.cancel();
return false;
}
final float x = event.getX();
final float y = event.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
initialMotionX = x;
initialMotionY = y;
break;
case MotionEvent.ACTION_MOVE:
final float adx = Math.abs(x - initialMotionX);
final float ady = Math.abs(y - initialMotionY);
final int dragSlop = dragHelper.getTouchSlop();
if (adx > dragSlop && ady < dragSlop) {
return super.onInterceptTouchEvent(event);
}
if ((ady > dragSlop && adx > ady) || !isDragViewUnder((int) initialMotionX, (int) initialMotionY)) {
dragHelper.cancel();
return false;
}
break;
}
return dragHelper.shouldInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
dragHelper.processTouchEvent(event);
return true;
}
// NOTE: Android Studio bug misreports error, squashing the warning.
// https://code.google.com/p/android/issues/detail?id=175977
@SuppressWarnings("ResourceType")
private boolean isDragViewUnder(int x, int y) {
int[] viewLocation = new int[2];
cameraView.getLocationOnScreen(viewLocation);
int[] parentLocation = new int[2];
this.getLocationOnScreen(parentLocation);
int screenX = parentLocation[0] + x;
int screenY = parentLocation[1] + y;
return screenX >= viewLocation[0] && screenX < viewLocation[0] + cameraView.getWidth() &&
screenY >= viewLocation[1] && screenY < viewLocation[1] + cameraView.getHeight();
}
private int computeCameraTopPosition(int slideOffset) {
final int baseCameraTop = (cameraView.getMeasuredHeight() - halfExpandedHeight) / 2;
final int baseOffset = getMeasuredHeight() - slideOffset - baseCameraTop;
final float slop = Util.clamp((float)(slideOffset - halfExpandedHeight) / (getMeasuredHeight() - halfExpandedHeight),
0f,
1f);
return baseOffset + (int)(slop * baseCameraTop);
}
private int computeCoverTopPosition(int slideOffset) {
return getMeasuredHeight() - getPaddingBottom() - slideOffset - getCoverView().getMeasuredHeight();
}
private void slideTo(int slideOffset, boolean forceInstant) {
if (animator != null) {
animator.cancel();
animator = null;
}
if (!forceInstant) {
animator = ObjectAnimator.ofInt(this, "slideOffset", this.slideOffset, slideOffset);
animator.setInterpolator(new FastOutSlowInInterpolator());
animator.setDuration(400);
animator.start();
ViewCompat.postInvalidateOnAnimation(this);
} else {
this.slideOffset = slideOffset;
requestLayout();
invalidate();
}
}
public void onPause() {
paused = true;
cameraView.onPause();
}
public void onResume() {
paused = false;
if (drawerState.isVisible()) cameraView.onResume();
}
public enum DrawerState {
COLLAPSED, HALF_EXPANDED, FULL_EXPANDED;
public boolean isVisible() {
return this != COLLAPSED;
}
}
private class ShutterClickListener implements OnClickListener {
@Override
public void onClick(View v) {
boolean crop = drawerState != DrawerState.FULL_EXPANDED;
int imageHeight = crop ? getContainer().getKeyboardHeight() : cameraView.getMeasuredHeight();
Rect previewRect = new Rect(0, 0, cameraView.getMeasuredWidth(), imageHeight);
cameraView.takePicture(previewRect);
}
}
private class CameraFlipClickListener implements OnClickListener {
@Override
public void onClick(View v) {
cameraView.flipCamera();
swapCameraButton.setImageResource(cameraView.isRearCamera() ? R.drawable.quick_camera_front
: R.drawable.quick_camera_rear);
}
}
private class FullscreenClickListener implements OnClickListener {
@Override
public void onClick(View v) {
if (drawerState != DrawerState.FULL_EXPANDED) {
setDrawerStateAndUpdate(DrawerState.FULL_EXPANDED);
} else if (isLandscape()) {
setDrawerStateAndUpdate(DrawerState.COLLAPSED);
} else {
setDrawerStateAndUpdate(DrawerState.HALF_EXPANDED);
}
}
}
}

View file

@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.util;
import android.content.ContentUris;
import android.content.Context;
import android.content.SharedPreferences;
import android.hardware.Camera.CameraInfo;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
@ -51,8 +50,6 @@ public class Prefs {
public static final String NOTIFICATION_PRIVACY_PREF = "pref_notification_privacy";
public static final String NOTIFICATION_PRIORITY_PREF = "pref_notification_priority";
public static final String BUILTIN_CAMERA_PREF = "pref_builtin_camera";
public static final String DIRECT_CAPTURE_CAMERA_ID = "pref_direct_capture_camera_id";
private static final String PROFILE_AVATAR_ID_PREF = "pref_profile_avatar_id";
public static final String INCOGNITO_KEYBORAD_PREF = "pref_incognito_keyboard";
@ -105,15 +102,6 @@ public class Prefs {
return Integer.valueOf(getStringPreference(context, NOTIFICATION_PRIORITY_PREF, String.valueOf(NotificationCompat.PRIORITY_HIGH)));
}
public static void setDirectCaptureCameraId(Context context, int value) {
setIntegerPreference(context, DIRECT_CAPTURE_CAMERA_ID, value);
}
@SuppressWarnings("deprecation")
public static int getDirectCaptureCameraId(Context context) {
return getIntegerPreference(context, DIRECT_CAPTURE_CAMERA_ID, CameraInfo.CAMERA_FACING_FRONT);
}
public static NotificationPrivacyPreference getNotificationPrivacy(Context context) {
return new NotificationPrivacyPreference(getStringPreference(context, NOTIFICATION_PRIVACY_PREF, "all"));
}
@ -270,10 +258,6 @@ public class Prefs {
setStringPreference(context, BACKGROUND_PREF+accountId, path);
}
public static boolean isBuiltInCameraPreferred(Context context) {
return getBooleanPreference(context, BUILTIN_CAMERA_PREF, false);
}
public static boolean getAlwaysLoadRemoteContent(Context context) {
return getBooleanPreference(context, Prefs.ALWAYS_LOAD_REMOTE_CONTENT,
Prefs.ALWAYS_LOAD_REMOTE_CONTENT_DEFAULT);

View file

@ -15,12 +15,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.thoughtcrime.securesms.components.camera.QuickAttachmentDrawer
android:id="@+id/quick_attachment_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout android:id="@+id/conversation_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -64,6 +58,5 @@
/>
</LinearLayout>
</org.thoughtcrime.securesms.components.camera.QuickAttachmentDrawer>
</org.thoughtcrime.securesms.components.InputAwareLayout>
</RelativeLayout>

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<org.thoughtcrime.securesms.components.camera.CameraView
android:id="@+id/quick_camera"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
</merge>

View file

@ -742,7 +742,9 @@
<string name="pref_manage_keys">Manage Keys</string>
<string name="pref_use_system_emoji">Use System Emoji</string>
<string name="pref_use_system_emoji_explain">Turn off Delta Chat\'s built-in emoji support</string>
<!-- deprecated -->
<string name="pref_use_inapp_camera">Use In-App Camera</string>
<!-- deprecated -->
<string name="pref_use_inapp_camera_explain">In-app camera usually has less features than the system camera</string>
<string name="pref_show_system_contacts">Read System Address Book</string>
<string name="pref_show_system_contacts_explain">Offer to create chats with contacts from the address book. Some providers need end-to-end encryption setup first.</string>

View file

@ -62,12 +62,6 @@
android:summary="@string/pref_incognito_keyboard_explain"
android:title="@string/pref_incognito_keyboard" />
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="false"
android:key="pref_builtin_camera"
android:title="@string/pref_use_inapp_camera"
android:summary="@string/pref_use_inapp_camera_explain"/>
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
android:defaultValue="false"
android:key="pref_show_system_contacts"