Device provisioning

Closes #4553
// FREEBIE
This commit is contained in:
Moxie Marlinspike
2015-11-19 10:21:19 -08:00
parent 02c37e815c
commit 7c0bf0c871
38 changed files with 1047 additions and 246 deletions

View File

@@ -0,0 +1,107 @@
package org.thoughtcrime.securesms.components;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import org.thoughtcrime.securesms.R;
public class ShapeScrim extends View {
private enum ShapeType {
CIRCLE, SQUARE
}
private final Paint eraser;
private final ShapeType shape;
private final float radius;
private Bitmap scrim;
private Canvas scrimCanvas;
public ShapeScrim(Context context) {
this(context, null);
}
public ShapeScrim(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ShapeScrim(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (attrs != null) {
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ShapeScrim, 0, 0);
String shapeName = typedArray.getString(R.styleable.ShapeScrim_shape);
if ("square".equalsIgnoreCase(shapeName)) this.shape = ShapeType.SQUARE;
else if ("circle".equalsIgnoreCase(shapeName)) this.shape = ShapeType.CIRCLE;
else this.shape = ShapeType.SQUARE;
this.radius = typedArray.getFloat(R.styleable.ShapeScrim_radius, 0.4f);
typedArray.recycle();
} else {
this.shape = ShapeType.SQUARE;
this.radius = 0.4f;
}
this.eraser = new Paint();
this.eraser.setColor(0xFFFFFFFF);
this.eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
int shortDimension = getWidth() < getHeight() ? getWidth() : getHeight();
float drawRadius = shortDimension * radius;
if (scrimCanvas == null) {
scrim = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
scrimCanvas = new Canvas(scrim);
}
scrim.eraseColor(Color.TRANSPARENT);
scrimCanvas.drawColor(Color.parseColor("#55BDBDBD"));
if (shape == ShapeType.CIRCLE) drawCircle(scrimCanvas, drawRadius, eraser);
else drawSquare(scrimCanvas, drawRadius, eraser);
canvas.drawBitmap(scrim, 0, 0, null);
}
@Override
public void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
super.onSizeChanged(width, height, oldHeight, oldHeight);
if (width != oldWidth || height != oldHeight) {
scrim = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
scrimCanvas = new Canvas(scrim);
}
}
private void drawCircle(Canvas canvas, float radius, Paint eraser) {
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, eraser);
}
private void drawSquare(Canvas canvas, float radius, Paint eraser) {
float left = (getWidth() / 2 ) - radius;
float top = (getHeight() / 2) - radius;
float right = left + (radius * 2);
float bottom = top + (radius * 2);
RectF square = new RectF(left, top, right, bottom);
canvas.drawRoundRect(square, 25, 25, eraser);
}
}

View File

@@ -7,6 +7,7 @@ import android.hardware.Camera.Size;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Surface;
import java.util.Collections;
@@ -22,6 +23,7 @@ public class CameraUtils {
int width,
int height,
@NonNull Camera camera) {
Log.w("CameraUtils", String.format("getPreferredPreviewSize(%d, %d, %d)", displayOrientation, width, height));
double targetRatio = (double)width / height;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;

View File

@@ -19,6 +19,7 @@ import android.annotation.TargetApi;
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;
@@ -39,6 +40,7 @@ import java.io.IOException;
import java.util.List;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.BitmapUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
@@ -73,7 +75,15 @@ public class CameraView extends FrameLayout {
super(context, attrs, defStyle);
setBackgroundColor(Color.BLACK);
if (isMultiCamera()) cameraId = TextSecurePreferences.getDirectCaptureCameraId(context);
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 = TextSecurePreferences.getDirectCaptureCameraId(context);
typedArray.recycle();
}
surface = new CameraSurfaceView(getContext());
onOrientationChange = new OnOrientationChange(context.getApplicationContext());
@@ -87,7 +97,9 @@ public class CameraView extends FrameLayout {
Log.w(TAG, "onResume() queued");
enqueueTask(new SerialAsyncTask<Camera>() {
@Override
protected @Nullable Camera onRunBackground() {
protected
@Nullable
Camera onRunBackground() {
try {
return Camera.open(cameraId);
} catch (Exception e) {
@@ -131,15 +143,19 @@ public class CameraView extends FrameLayout {
enqueueTask(new SerialAsyncTask<Void>() {
private Optional<Camera> cameraToDestroy;
@Override protected void onPreMain() {
@Override
protected void onPreMain() {
cameraToDestroy = camera;
camera = Optional.absent();
}
@Override protected Void onRunBackground() {
@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) {
@@ -224,6 +240,30 @@ public class CameraView extends FrameLayout {
this.listener = listener;
}
public void setPreviewCallback(final 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;
}
@@ -515,4 +555,38 @@ public class CameraView extends FrameLayout {
void onImageCapture(@NonNull final byte[] imageBytes);
void onCameraFail();
}
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;
}
}
}