WIP: Add simple image capture/viewing blocks.
This commit is contained in:
parent
f8786abc14
commit
f82edf041c
@ -2,18 +2,25 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.codigoparallevar.minicards">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<!-- Network state on programaker bridge -->
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" android:required="false" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" android:required="false" />
|
||||
<!-- For Wifi SSID -->
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:required="false" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:required="false" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" android:required="false" />
|
||||
<!-- For vibration block on bridge -->
|
||||
<uses-permission android:name="android.permission.VIBRATE" android:required="false" />
|
||||
<!-- For Camera block -->
|
||||
<uses-permission android:name="android.permission.CAMERA" android:required="false" />
|
||||
|
||||
<!-- OpenGL ES 2.0 -->
|
||||
<uses-feature
|
||||
android:glEsVersion="0x00020000"
|
||||
android:required="true" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- For Programaker bridge -->
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-feature android:name="android.hardware.camera" />
|
||||
<uses-feature android:name="android.hardware.camera.autofocus" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
@ -23,6 +23,7 @@ import com.codigoparallevar.minicards.types.connectors.Wiring.SignalWire;
|
||||
import com.codigoparallevar.minicards.types.connectors.Wiring.Wire;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.AnyInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.BooleanInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.ImageInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.InputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.SignalInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.StringInputConnector;
|
||||
@ -517,6 +518,31 @@ public class CanvasView extends View implements PartGrid {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageInputConnector getImageInputConnectorOn(int x, int y) {
|
||||
// If no part was found, do the same for connectors
|
||||
for (int i = parts.size() - 1; i >= 0; i--){
|
||||
final Part part = parts.get(i);
|
||||
|
||||
// Then with input ones
|
||||
for (InputConnector inputConnector : part.getInputConnectors()){
|
||||
ImageInputConnector imageInputConnector;
|
||||
if (inputConnector instanceof ImageInputConnector){
|
||||
imageInputConnector = (ImageInputConnector) inputConnector;
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (imageInputConnector.containsPoint(x, y)){
|
||||
return imageInputConnector;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public void addPart(Part part) {
|
||||
parts.add(part);
|
||||
@ -581,4 +607,8 @@ public class CanvasView extends View implements PartGrid {
|
||||
part.pause();
|
||||
}
|
||||
}
|
||||
|
||||
public void requestPermission(String permission, Runnable ifAccepted) {
|
||||
this.parentActivity.requestPermissions(permission, ifAccepted);
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,15 @@ package com.codigoparallevar.minicards;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
@ -22,7 +25,9 @@ import com.programaker.api.data.api_results.ProgramakerBridgeCustomBlockResult;
|
||||
import com.programaker.api.data.api_results.ProgramakerGetCustomBlocksResult;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class CardActivity extends AppCompatActivity {
|
||||
|
||||
@ -32,6 +37,9 @@ public class CardActivity extends AppCompatActivity {
|
||||
public static final String DEVELOPER_VISUALIZATION_MODE = "DEVELOPER_VISUALIZATION_MODE";
|
||||
public static final String USER_VISUALIZATION_MODE = "USER_VISUALIZATION_MODE";
|
||||
|
||||
private int permissionRequestLatest = 1;
|
||||
private Map<Integer, Runnable> permissionRequestCallbacks = new HashMap<>();
|
||||
|
||||
CanvasView canvasView;
|
||||
com.getbase.floatingactionbutton.AddFloatingActionButton AddPartButton;
|
||||
com.getbase.floatingactionbutton.FloatingActionButton SetDevModeButton;
|
||||
@ -257,4 +265,39 @@ public class CardActivity extends AppCompatActivity {
|
||||
}
|
||||
context.startActivity(i);
|
||||
}
|
||||
|
||||
public void requestPermissions(String permission, Runnable ifAccepted) {
|
||||
permissionRequestLatest++;
|
||||
int request_code = permissionRequestLatest;
|
||||
permissionRequestCallbacks.put(request_code, ifAccepted);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
this.requestPermissions(new String[]{permission}, request_code);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||
@NonNull int[] grantResults) {
|
||||
// If request is cancelled, the result arrays are empty.
|
||||
if (grantResults.length > 0 &&
|
||||
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
// Permission is granted. Continue the action or workflow
|
||||
// in your app.
|
||||
if (permissionRequestCallbacks.containsKey(requestCode)) {
|
||||
Runnable callback = permissionRequestCallbacks.get(requestCode);
|
||||
permissionRequestCallbacks.remove(requestCode);
|
||||
callback.run();
|
||||
}
|
||||
} else {
|
||||
// TODO:
|
||||
// Explain to the user that the feature is unavailable because
|
||||
// the features requires a permission that the user has denied.
|
||||
// At the same time, respect the user's decision. Don't link to
|
||||
// system settings in an effort to convince the user to change
|
||||
// their decision.
|
||||
if (permissionRequestCallbacks.containsKey(requestCode)) {
|
||||
permissionRequestCallbacks.remove(requestCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,13 +9,14 @@ import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.codigoparallevar.minicards.parts.ProgramakerCustomBlockPart;
|
||||
import com.codigoparallevar.minicards.parts.android.CameraStreamer;
|
||||
import com.codigoparallevar.minicards.parts.buttons.RoundButton;
|
||||
import com.codigoparallevar.minicards.parts.logic.Ticker;
|
||||
import com.codigoparallevar.minicards.parts.logic.Toggle;
|
||||
import com.codigoparallevar.minicards.parts.samples.ColorBox;
|
||||
import com.codigoparallevar.minicards.parts.samples.Placeholder;
|
||||
import com.codigoparallevar.minicards.parts.strings.ConvertToString;
|
||||
import com.codigoparallevar.minicards.parts.values.StaticValuePart;
|
||||
import com.codigoparallevar.minicards.parts.viewers.ImageFrame;
|
||||
import com.codigoparallevar.minicards.types.Part;
|
||||
import com.codigoparallevar.minicards.types.PartConnection;
|
||||
import com.codigoparallevar.minicards.types.PartGrid;
|
||||
@ -258,8 +259,8 @@ public class CardFile {
|
||||
|
||||
return buttonInfo;
|
||||
}
|
||||
else if (type.equals(Placeholder.class.getName())) {
|
||||
return new Tuple2<>(Placeholder.deserialize(grid, jsonObject.getJSONObject("_data")),
|
||||
else if (type.equals(ImageFrame.class.getName())) {
|
||||
return new Tuple2<>(ImageFrame.deserialize(grid, jsonObject.getJSONObject("_data")),
|
||||
Collections.<PartConnection>emptyList());
|
||||
}
|
||||
else if (type.equals(ColorBox.class.getName())){
|
||||
@ -301,6 +302,13 @@ public class CardFile {
|
||||
|
||||
return staticValuePartInfo;
|
||||
}
|
||||
else if (type.equals(CameraStreamer.class.getName())){
|
||||
Tuple2<Part, List<PartConnection>> staticValuePartInfo = CameraStreamer.deserialize(
|
||||
grid,
|
||||
jsonObject.getJSONObject("_data"));
|
||||
|
||||
return staticValuePartInfo;
|
||||
}
|
||||
else {
|
||||
throw new JSONException("Expected known class, found " + type);
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
package com.codigoparallevar.minicards;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.codigoparallevar.minicards.types.functional.Tuple2;
|
||||
@ -42,7 +45,6 @@ public class ScrolledCanvas {
|
||||
canvas.drawPath(offsetPath, paint);
|
||||
}
|
||||
|
||||
|
||||
public void drawCenteredText(String text, int x, int y, Paint paint) {
|
||||
paint.setTextAlign(Paint.Align.LEFT);
|
||||
Rect r = new Rect();
|
||||
@ -56,4 +58,17 @@ public class ScrolledCanvas {
|
||||
public void drawText(String text, int x, int y, Paint paint) {
|
||||
canvas.drawText(text, x - xOrig, y - yOrig, paint);
|
||||
}
|
||||
|
||||
public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
|
||||
rect.offset(-xOrig, -yOrig);
|
||||
canvas.drawRoundRect(rect, rx, ry, paint);
|
||||
}
|
||||
|
||||
public void drawBitmap(Bitmap bitmap, Rect rect) {
|
||||
rect.offset(-xOrig, -yOrig);
|
||||
canvas.drawBitmap(bitmap,
|
||||
new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()),
|
||||
rect,
|
||||
null);
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package com.codigoparallevar.minicards;
|
||||
import com.codigoparallevar.minicards.types.PartGrid;
|
||||
import com.codigoparallevar.minicards.types.Selectable;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.AnyInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.ImageInputConnector;
|
||||
import com.codigoparallevar.minicards.types.functional.Tuple2;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.BooleanInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.SignalInputConnector;
|
||||
@ -45,6 +46,11 @@ class StubPartGrid implements PartGrid {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageInputConnector getImageInputConnectorOn(int xEnd, int yEnd) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tuple2<Integer, Integer> getCenteredOn() {
|
||||
return null;
|
||||
|
@ -0,0 +1,458 @@
|
||||
package com.codigoparallevar.minicards.parts.android;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ImageFormat;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.camera2.CameraAccessException;
|
||||
import android.hardware.camera2.CameraCaptureSession;
|
||||
import android.hardware.camera2.CameraCharacteristics;
|
||||
import android.hardware.camera2.CameraDevice;
|
||||
import android.hardware.camera2.CameraManager;
|
||||
import android.hardware.camera2.CaptureRequest;
|
||||
import android.media.Image;
|
||||
import android.media.ImageReader;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.codigoparallevar.minicards.CanvasView;
|
||||
import com.codigoparallevar.minicards.PartInstantiator;
|
||||
import com.codigoparallevar.minicards.ScrolledCanvas;
|
||||
import com.codigoparallevar.minicards.parts.connectors.ImageRoundOutputConnector;
|
||||
import com.codigoparallevar.minicards.parts.style.CardTheme;
|
||||
import com.codigoparallevar.minicards.types.Moveable;
|
||||
import com.codigoparallevar.minicards.types.Part;
|
||||
import com.codigoparallevar.minicards.types.PartConnection;
|
||||
import com.codigoparallevar.minicards.types.PartGrid;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.InputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.output.OutputConnector;
|
||||
import com.codigoparallevar.minicards.types.functional.Tuple2;
|
||||
import com.codigoparallevar.minicards.types.wireData.ImageSignal;
|
||||
import com.codigoparallevar.minicards.types.wireData.WireDataType;
|
||||
import com.codigoparallevar.minicards.utils.Serializations;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public class CameraStreamer implements Part {
|
||||
private static final String LogTag = "CameraStreamer";
|
||||
|
||||
private static final int DEFAULT_SIDE_SIZE = 200;
|
||||
private final String _id;
|
||||
private final PartGrid _partGrid;
|
||||
private int _left;
|
||||
private int _top;
|
||||
private int _right;
|
||||
private int _bottom;
|
||||
private List<OutputConnector> _outputConnectors;
|
||||
private final ImageRoundOutputConnector _imageRoundOutputConnector;
|
||||
private final long SLEEP_TIME = 1000;
|
||||
private ImageReader imageReader = null;
|
||||
private HandlerThread _thread = null;
|
||||
private Handler _handler = null;
|
||||
|
||||
private CameraStreamer(String id, PartGrid partGrid, int left, int top, int right, int bottom) {
|
||||
_id = id;
|
||||
_partGrid = partGrid;
|
||||
_left = left;
|
||||
_top = top;
|
||||
_right = right;
|
||||
_bottom = bottom;
|
||||
|
||||
// Create connectors
|
||||
_imageRoundOutputConnector = new ImageRoundOutputConnector(
|
||||
this,
|
||||
_partGrid,
|
||||
getOutputConnectorCenterX(), getOutputConnectorCenterY(),
|
||||
getOutputConnectRadius());
|
||||
|
||||
_outputConnectors = new LinkedList<>();
|
||||
_outputConnectors.add(_imageRoundOutputConnector);
|
||||
}
|
||||
|
||||
|
||||
public CameraStreamer(PartGrid partGrid, int left, int top, int right, int bottom) {
|
||||
this(UUID.randomUUID().toString(), partGrid, left, top, right, bottom);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void moveEnd(int x, int y) {
|
||||
final int width = _right - _left;
|
||||
final int height = _bottom - _top;
|
||||
|
||||
_left = x - width / 2;
|
||||
_right = _left + width;
|
||||
|
||||
_top = y - height / 2;
|
||||
_bottom = _top + height;
|
||||
|
||||
_imageRoundOutputConnector.updatePosition(
|
||||
getOutputConnectorCenterX(),
|
||||
getOutputConnectorCenterY());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drop(int x, int y) {
|
||||
moveEnd(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsPoint(int x, int y) {
|
||||
return (x >= get_left()) && (x <= get_right())
|
||||
&& (y >= get_top()) && (y <= get_bottom());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Moveable getMoveable() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlink() {
|
||||
pause();
|
||||
|
||||
for (InputConnector input : getInputConnectors()) {
|
||||
input.unlink();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(ScrolledCanvas canvas, boolean devMode) {
|
||||
if (devMode){
|
||||
drawConnector(canvas);
|
||||
drawWires(canvas, devMode);
|
||||
|
||||
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
paint.setColor(Color.GRAY);
|
||||
|
||||
canvas.drawRect(
|
||||
new Rect(_left, _top,
|
||||
_right, _bottom),
|
||||
paint);
|
||||
|
||||
|
||||
// Draw a little camera
|
||||
Paint iconPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
iconPaint.setStyle(Paint.Style.STROKE);
|
||||
iconPaint.setColor(Color.YELLOW);
|
||||
iconPaint.setStrokeWidth(5f);
|
||||
iconPaint.setStrokeCap(Paint.Cap.ROUND);
|
||||
iconPaint.setStrokeJoin(Paint.Join.ROUND);
|
||||
|
||||
// TODO: Refactor this into something reasonable
|
||||
float side = _right - _left;
|
||||
float mid = side / 2;
|
||||
float quarter = mid / 2;
|
||||
float oct = quarter / 2;
|
||||
float hex = oct / 2;
|
||||
float shex = hex / 2;
|
||||
|
||||
Path path = new Path();
|
||||
// Square top left
|
||||
path.moveTo(_left + oct + hex + shex, _top + quarter + hex);
|
||||
// Square top right
|
||||
path.lineTo(_left + mid + hex + shex, _top + quarter + hex);
|
||||
// Box-to-projection connection
|
||||
path.lineTo(_left + mid + hex + shex, _top + mid);
|
||||
// Projection top right
|
||||
path.lineTo(_right - quarter - hex + hex + shex, _top + quarter + hex);
|
||||
// Projection bottom right
|
||||
path.lineTo(_right - quarter - hex + hex + shex, _bottom - quarter - hex);
|
||||
// Back to box
|
||||
path.lineTo(_left + mid + hex + shex, _top + mid);
|
||||
// Box bottom right
|
||||
path.lineTo(_left + mid + hex + shex, _bottom - quarter - hex);
|
||||
// Box bottom left
|
||||
path.lineTo(_left + oct + hex + shex, _bottom - quarter - hex);
|
||||
|
||||
path.close();
|
||||
canvas.drawPath(path, iconPaint);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawConnector(ScrolledCanvas canvas) {
|
||||
Paint outerConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
outerConnectorPaint.setColor(CardTheme.IMAGE_CONNECTOR_COLOR_OUTER);
|
||||
|
||||
canvas.drawCircle(getOutputConnectorCenterX(),
|
||||
getOutputConnectorCenterY(),
|
||||
getOutputConnectRadius(),
|
||||
outerConnectorPaint);
|
||||
|
||||
Paint innerConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
innerConnectorPaint.setColor(CardTheme.IMAGE_CONNECTOR_COLOR_INNER);
|
||||
|
||||
canvas.drawCircle(getOutputConnectorCenterX(),
|
||||
getOutputConnectorCenterY(),
|
||||
getOutputConnectRadius() / 2,
|
||||
innerConnectorPaint);
|
||||
}
|
||||
|
||||
private void drawWires(ScrolledCanvas canvas, boolean devMode) {
|
||||
for (OutputConnector outputConnector : _outputConnectors){
|
||||
outputConnector.drawWires(canvas, devMode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_left() {
|
||||
return _left;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_right() {
|
||||
return _right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_top() {
|
||||
return _top;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_bottom() {
|
||||
return _bottom;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touched() {
|
||||
// Just ignore it, as it's a logic component
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<InputConnector> getInputConnectors() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OutputConnector> getOutputConnectors() {
|
||||
return _outputConnectors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialize() throws JSONException {
|
||||
JSONObject serialized = new JSONObject();
|
||||
|
||||
serialized.put("id", _id);
|
||||
serialized.put("left", _left);
|
||||
serialized.put("top", _top);
|
||||
serialized.put("right", _right);
|
||||
serialized.put("bottom", _bottom);
|
||||
serialized.put("on_signal_output_connector",
|
||||
Serializations.serialize(serializeConnectionEndpoints()));
|
||||
|
||||
return serialized;
|
||||
}
|
||||
|
||||
public static Tuple2<Part, List<PartConnection>> deserialize(PartGrid partGrid, JSONObject data) throws JSONException {
|
||||
String id = data.getString("id");
|
||||
int left = data.getInt("left");
|
||||
int top = data.getInt("top");
|
||||
int right = data.getInt("right");
|
||||
int bottom = data.getInt("bottom");
|
||||
|
||||
CameraStreamer cameraStreamer = new CameraStreamer(id, partGrid, left, top, right, bottom);
|
||||
|
||||
List<PartConnection> connections = new LinkedList<>();
|
||||
|
||||
JSONArray connectorOuts = data.getJSONArray("on_signal_output_connector");
|
||||
for (int i = 0; i < connectorOuts.length(); i++){
|
||||
connections.add(PartConnection.deserialize(
|
||||
cameraStreamer._imageRoundOutputConnector,
|
||||
connectorOuts.getJSONObject(i)));
|
||||
}
|
||||
|
||||
return new Tuple2<Part, List<PartConnection>>(cameraStreamer, connections);
|
||||
}
|
||||
|
||||
private List<Map<String, String>> serializeConnectionEndpoints() {
|
||||
List<Map<String, String>> serializedData = new LinkedList<>();
|
||||
|
||||
for (Tuple2<String, String> endpoint : _imageRoundOutputConnector.getConnectionEndpoints()){
|
||||
serializedData.add(PartConnection.serialize(endpoint.item1, endpoint.item2));
|
||||
}
|
||||
|
||||
return serializedData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(InputConnector roundInputConnector, WireDataType signal) {
|
||||
// @TODO: REMOVE THE NEED FOR THIS
|
||||
}
|
||||
|
||||
private void onNewImage(Image img) {
|
||||
_imageRoundOutputConnector.send(new ImageSignal(img));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get_id() {
|
||||
return _id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputConnector getConnectorWithId(String inputConnectorId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConnectorId(InputConnector inputConnector) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume() {
|
||||
if (!(this._partGrid instanceof CanvasView)) {
|
||||
return;
|
||||
}
|
||||
|
||||
CanvasView view = ((CanvasView) this._partGrid);
|
||||
Context ctx = view.getContext();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (ctx.checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
|
||||
view.requestPermission(Manifest.permission.CAMERA, () -> { CameraStreamer.this.resume(); });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.imageReader = ImageReader.newInstance(100, 100, ImageFormat.JPEG, 30);
|
||||
this.imageReader.setOnImageAvailableListener((ImageReader.OnImageAvailableListener) newImageReader -> {
|
||||
Image latestImage = newImageReader.acquireLatestImage();
|
||||
|
||||
CameraStreamer.this.onNewImage(latestImage);
|
||||
latestImage.close();
|
||||
}, new Handler());
|
||||
|
||||
CameraManager cm = (CameraManager) ctx.getSystemService(Context.CAMERA_SERVICE);
|
||||
try {
|
||||
String[] cameraList = cm.getCameraIdList();
|
||||
for (String cd : cameraList) {
|
||||
//get camera characteristics
|
||||
CameraCharacteristics mCameraCharacteristics = cm.getCameraCharacteristics(cd);
|
||||
|
||||
//check if the camera is in the back - if not, continue to next
|
||||
if (mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING) != CameraCharacteristics.LENS_FACING_BACK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this._thread == null) {
|
||||
this._thread = new HandlerThread("mCameraHandlerThread");
|
||||
this._thread.start();
|
||||
}
|
||||
if (this._handler == null) {
|
||||
this._handler = new Handler(this._thread.getLooper());
|
||||
}
|
||||
|
||||
cm.openCamera(cd, new CameraDevice.StateCallback() {
|
||||
@Override
|
||||
public void onOpened(@NonNull CameraDevice camera) {
|
||||
//make list of surfaces to give to camera
|
||||
List<Surface> surfaceList = new ArrayList<>();
|
||||
Surface surface = CameraStreamer.this.imageReader.getSurface();
|
||||
surfaceList.add(surface);
|
||||
|
||||
try {
|
||||
camera.createCaptureSession(surfaceList, new CameraCaptureSession.StateCallback() {
|
||||
@Override
|
||||
public void onConfigured(@NonNull CameraCaptureSession session) {
|
||||
try {
|
||||
CaptureRequest.Builder requestBuilder = session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
|
||||
requestBuilder.addTarget(surface);
|
||||
//set to null - image data will be produced but will not receive metadata
|
||||
session.setRepeatingRequest(requestBuilder.build(), null, CameraStreamer.this._handler);
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(LogTag, "createCaptureSession threw CameraAccessException.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
|
||||
Log.i(LogTag, "Error on camera configuration");
|
||||
}
|
||||
}, CameraStreamer.this._handler);
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(LogTag, "createCaptureSession threw CameraAccessException.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected(@NonNull CameraDevice camera) {
|
||||
Log.i(LogTag, "Camera disconnected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull CameraDevice camera, int error) {
|
||||
Log.i(LogTag, "Error on camera opening: " + error);
|
||||
}
|
||||
}, this._handler);
|
||||
break;
|
||||
}
|
||||
|
||||
} catch (CameraAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
this._handler = null;
|
||||
if (this._thread != null) {
|
||||
this._thread.interrupt();
|
||||
this._thread = null;
|
||||
}
|
||||
if (this.imageReader != null) {
|
||||
this.imageReader.close();
|
||||
this.imageReader = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object query(Object lastValue) {
|
||||
return null; // No relevant value (maybe time?)
|
||||
}
|
||||
|
||||
|
||||
private int getOutputConnectorCenterX() {
|
||||
return (_left + _right) / 2;
|
||||
}
|
||||
|
||||
private int getOutputConnectorCenterY() {
|
||||
return _bottom;
|
||||
}
|
||||
|
||||
private int getOutputConnectRadius() {
|
||||
return (_right - _left) / 2;
|
||||
}
|
||||
|
||||
public static PartInstantiator getInstantiator() {
|
||||
final int halfSideSize = DEFAULT_SIDE_SIZE / 2;
|
||||
return new PartInstantiator() {
|
||||
@Override
|
||||
protected Part instantiate(PartGrid grid, Tuple2<Integer, Integer> center) {
|
||||
return new CameraStreamer(grid,
|
||||
center.item1 - halfSideSize, center.item2 - halfSideSize,
|
||||
center.item1 + halfSideSize, center.item2 + halfSideSize);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package com.codigoparallevar.minicards.parts.connectors;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.codigoparallevar.minicards.types.Moveable;
|
||||
import com.codigoparallevar.minicards.types.Part;
|
||||
import com.codigoparallevar.minicards.types.connectors.Wiring.Wire;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.ImageInputConnector;
|
||||
import com.codigoparallevar.minicards.types.wireData.ImageSignal;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class ImageRoundInputConnector implements ImageInputConnector {
|
||||
private final Part _part;
|
||||
private int _xposition;
|
||||
private int _yposition;
|
||||
private final int _radius;
|
||||
private final List<Wire> _attachments = new LinkedList<>();
|
||||
|
||||
public ImageRoundInputConnector(Part part,
|
||||
int inputConnectorCenterX, int inputConnectorCenterY,
|
||||
int inputConnectorRadius) {
|
||||
_part = part;
|
||||
_xposition = inputConnectorCenterX;
|
||||
_yposition = inputConnectorCenterY;
|
||||
_radius = inputConnectorRadius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsPoint(int x, int y) {
|
||||
return ((Math.abs(x - _xposition) <= _radius)
|
||||
&& (Math.abs(y - _yposition) <= _radius));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Moveable getMoveable() {
|
||||
return new Wire(this, _xposition, _yposition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlink() {
|
||||
for (Wire wire : _attachments) {
|
||||
wire.unlink();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePosition(int x, int y) {
|
||||
_xposition = x;
|
||||
_yposition = y;
|
||||
|
||||
for (Wire wire : _attachments){
|
||||
wire.moveEnd(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return _xposition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getY() {
|
||||
return _yposition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(ImageSignal signal) {
|
||||
_part.send(this, signal);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addAttachment(Wire<ImageSignal, ImageInputConnector> wire) {
|
||||
_attachments.add(wire);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Part getPart() {
|
||||
return _part;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return _part.getConnectorId(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drop(Wire wire) {
|
||||
Log.d("InputConnector", "Dropped wire " + wire);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wireUnlinked(Wire wire) {
|
||||
_attachments.remove(wire);
|
||||
}
|
||||
}
|
@ -0,0 +1,183 @@
|
||||
package com.codigoparallevar.minicards.parts.connectors;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.codigoparallevar.minicards.ScrolledCanvas;
|
||||
import com.codigoparallevar.minicards.types.Drawable;
|
||||
import com.codigoparallevar.minicards.types.Moveable;
|
||||
import com.codigoparallevar.minicards.types.Part;
|
||||
import com.codigoparallevar.minicards.types.PartGrid;
|
||||
import com.codigoparallevar.minicards.types.connectors.Wiring.ImageWire;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.ImageInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.InputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.output.ImageOutputConnector;
|
||||
import com.codigoparallevar.minicards.types.functional.Tuple2;
|
||||
import com.codigoparallevar.minicards.types.wireData.ImageSignal;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class ImageRoundOutputConnector implements Drawable, ImageOutputConnector,
|
||||
RoundOutputConnector<ImageSignal, ImageInputConnector, ImageWire> {
|
||||
private static final String LogTag = "ImageRoundOutputConnector";
|
||||
|
||||
private PartGrid _partGrid;
|
||||
private int _centerX;
|
||||
private int _centerY;
|
||||
private final int _radius;
|
||||
private final Part _part;
|
||||
private ImageWire _currentWire = null;
|
||||
private final List<ImageWire> _wires;
|
||||
private final HashSet<InputConnector> _connections;
|
||||
|
||||
public ImageRoundOutputConnector(Part part, PartGrid partGrid, int centerX, int centerY, int radius) {
|
||||
_part = part;
|
||||
_partGrid = partGrid;
|
||||
_centerX = centerX;
|
||||
_centerY = centerY;
|
||||
_radius = radius;
|
||||
_wires = new LinkedList<>();
|
||||
_connections = new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsPoint(int x, int y) {
|
||||
return ((Math.abs(x - _centerX) <= _radius)
|
||||
&& (Math.abs(y - _centerY) <= _radius));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Moveable getMoveable() {
|
||||
if (_currentWire == null) {
|
||||
startWire();
|
||||
}
|
||||
|
||||
return _currentWire;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlink() {}
|
||||
|
||||
private void startWire() {
|
||||
_currentWire = new ImageWire(this, _centerX, _centerY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drop(ImageWire wire) {
|
||||
|
||||
if (wire == _currentWire){
|
||||
_currentWire = null;
|
||||
|
||||
ImageInputConnector resultPoint = _partGrid.getImageInputConnectorOn(
|
||||
wire.getXEnd(), wire.getYEnd());
|
||||
|
||||
Log.d(LogTag, "Dropped wire on " + resultPoint);
|
||||
|
||||
// Not connected
|
||||
if (resultPoint == null){
|
||||
return;
|
||||
}
|
||||
|
||||
// Already connected
|
||||
if (_connections.contains(resultPoint)) {
|
||||
return;
|
||||
}
|
||||
_connections.add(resultPoint);
|
||||
|
||||
wire.attachTo(resultPoint, this);
|
||||
_wires.add(wire);
|
||||
}
|
||||
else {
|
||||
Log.w(LogTag,
|
||||
"Asked to drop non matching wire "
|
||||
+ "(expected " + _currentWire + ", got " + wire + ")");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wireUnlinked(ImageWire wire) {
|
||||
_wires.remove(wire);
|
||||
_connections.remove(wire.getAttachedTo());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawWires(ScrolledCanvas canvas, boolean devMode) {
|
||||
for (ImageWire wire : _wires) {
|
||||
wire.draw(canvas, devMode);
|
||||
}
|
||||
|
||||
if (_currentWire != null) {
|
||||
_currentWire.draw(canvas, devMode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePosition(int x, int y) {
|
||||
_centerX = x;
|
||||
_centerY = y;
|
||||
|
||||
for (ImageWire wire : _wires){
|
||||
wire.moveStart(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tuple2<String, String>> getConnectionEndpoints() {
|
||||
List<Tuple2<String, String>> endpointIds = new LinkedList<>();
|
||||
|
||||
for (ImageWire wire : _wires) {
|
||||
InputConnector inputConnector = wire.getAttachedTo();
|
||||
Part endPart = inputConnector.getPart();
|
||||
endpointIds.add(new Tuple2<>(inputConnector.getId(), endPart.get_id()));
|
||||
}
|
||||
|
||||
return endpointIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectTo(ImageInputConnector inputConnector) {
|
||||
if (_connections.contains(inputConnector)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_connections.add(inputConnector);
|
||||
|
||||
ImageWire wire = new ImageWire(this, _centerX, _centerY);
|
||||
wire.attachTo(inputConnector, this);
|
||||
_wires.add(wire);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(ScrolledCanvas canvas, boolean devMode) {
|
||||
// TODO: Complete this part
|
||||
}
|
||||
|
||||
public void send(ImageSignal signal) {
|
||||
for (ImageWire wire : _wires){
|
||||
wire.send(signal);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object query(Object lastValue) {
|
||||
return _part.query(lastValue);
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return _centerX;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return _centerY;
|
||||
}
|
||||
|
||||
public float getRadius() {
|
||||
return _radius;
|
||||
}
|
||||
|
||||
public List<ImageWire> getWires() {
|
||||
return this._wires;
|
||||
}
|
||||
}
|
@ -125,7 +125,7 @@ public class Ticker implements Part {
|
||||
paint);
|
||||
|
||||
|
||||
// Craw a little clock
|
||||
// Draw a little clock
|
||||
Paint clockPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
clockPaint.setStyle(Paint.Style.STROKE);
|
||||
clockPaint.setColor(Color.YELLOW);
|
||||
@ -271,20 +271,17 @@ public class Ticker implements Part {
|
||||
|
||||
@Override
|
||||
public void resume() {
|
||||
_thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
while (Ticker.this._thread == Thread.currentThread()) {
|
||||
Ticker.this._signalOutputConnector.send(new Signal());
|
||||
_partGrid.update();
|
||||
_thread = new Thread(() -> {
|
||||
while (Ticker.this._thread == Thread.currentThread()) {
|
||||
Ticker.this._signalOutputConnector.send(new Signal());
|
||||
_partGrid.update();
|
||||
|
||||
try {
|
||||
Thread.sleep(SLEEP_TIME);
|
||||
} catch (InterruptedException e) {
|
||||
Log.e("Minicards Ticker", "Wait failed", e);
|
||||
Ticker.this._thread = null;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(SLEEP_TIME);
|
||||
} catch (InterruptedException e) {
|
||||
Log.e("Minicards Ticker", "Wait failed", e);
|
||||
Ticker.this._thread = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,189 +0,0 @@
|
||||
package com.codigoparallevar.minicards.parts.samples;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.util.Log;
|
||||
|
||||
import com.codigoparallevar.minicards.ScrolledCanvas;
|
||||
import com.codigoparallevar.minicards.types.Moveable;
|
||||
import com.codigoparallevar.minicards.types.Part;
|
||||
import com.codigoparallevar.minicards.types.PartGrid;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.InputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.output.OutputConnector;
|
||||
import com.codigoparallevar.minicards.types.wireData.WireDataType;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Placeholder implements Part {
|
||||
private final String _id;
|
||||
private final PartGrid _partGrid;
|
||||
private int _left;
|
||||
private int _top;
|
||||
private int _right;
|
||||
private int _bottom;
|
||||
|
||||
public Placeholder(String id, PartGrid partGrid, int left, int top, int right, int bottom) {
|
||||
_id = id;
|
||||
_partGrid = partGrid;
|
||||
_left = left;
|
||||
_top = top;
|
||||
_right = right;
|
||||
_bottom = bottom;
|
||||
}
|
||||
|
||||
public Placeholder(PartGrid partGrid, int left, int top, int right, int bottom) {
|
||||
this(UUID.randomUUID().toString(), partGrid, left, top, right, bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_left() {
|
||||
return _left;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_right() {
|
||||
return _right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_top() {
|
||||
return _top;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_bottom() {
|
||||
return _bottom;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(ScrolledCanvas canvas, boolean devMode) {
|
||||
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
paint.setColor(Color.WHITE);
|
||||
|
||||
// Top
|
||||
canvas.drawLine(_left, _top, _right, _top, paint);
|
||||
// Bottom
|
||||
canvas.drawLine(_left, _bottom, _right, _bottom, paint);
|
||||
// Left
|
||||
canvas.drawLine(_left, _top, _left, _bottom, paint);
|
||||
// Right
|
||||
canvas.drawLine(_right, _top, _right, _bottom, paint);
|
||||
// Cross, top-left, bottom-right
|
||||
canvas.drawLine(_left, _top, _right, _bottom, paint);
|
||||
// Cross, top-right, bottom-left
|
||||
canvas.drawLine(_right, _top, _left, _bottom, paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveEnd(int x, int y) {
|
||||
final int width = _right - _left;
|
||||
final int height = _bottom - _top;
|
||||
|
||||
_left = x - width / 2;
|
||||
_right = _left + width;
|
||||
|
||||
_top = y - height / 2;
|
||||
_bottom = _top + height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drop(int x, int y) {
|
||||
moveEnd(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touched() {
|
||||
Log.d("Placeholder", "Placeholder touched");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<InputConnector> getInputConnectors() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OutputConnector> getOutputConnectors() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialize() throws JSONException {
|
||||
JSONObject serialized = new JSONObject();
|
||||
|
||||
serialized.put("id", _id);
|
||||
serialized.put("left", _left);
|
||||
serialized.put("top", _top);
|
||||
serialized.put("right", _right);
|
||||
serialized.put("bottom", _bottom);
|
||||
|
||||
return serialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(InputConnector roundInputConnector, WireDataType signal) {
|
||||
// @TODO: REMOVE THE NEED FOR THIS
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get_id() {
|
||||
return _id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputConnector getConnectorWithId(String inputConnectorId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConnectorId(InputConnector inputConnector) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object query(Object lastValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Part deserialize(PartGrid partGrid, JSONObject data) throws JSONException {
|
||||
String id = data.getString("id");
|
||||
int left = data.getInt("left");
|
||||
int top = data.getInt("top");
|
||||
int right = data.getInt("right");
|
||||
int bottom = data.getInt("bottom");
|
||||
|
||||
return new Placeholder(id, partGrid, left, top, right, bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsPoint(int x, int y) {
|
||||
return (x >= get_left()) && (x <= get_right())
|
||||
&& (y >= get_top()) && (y <= get_bottom());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Moveable getMoveable() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlink() {
|
||||
for (InputConnector input : getInputConnectors()) {
|
||||
input.unlink();
|
||||
}
|
||||
}
|
||||
}
|
@ -28,4 +28,7 @@ public class CardTheme {
|
||||
|
||||
public static final int UNKNOWN_CONNECTOR_COLOR_OUTER = Color.parseColor("#7f7f7f");
|
||||
public static final int UNKNOWN_CONNECTOR_COLOR_INNER = DEFAULT_COLOR_INNER;
|
||||
|
||||
public static final int IMAGE_CONNECTOR_COLOR_OUTER = Color.parseColor("#007700");
|
||||
public static final int IMAGE_CONNECTOR_COLOR_INNER = DEFAULT_COLOR_INNER;
|
||||
}
|
||||
|
@ -0,0 +1,316 @@
|
||||
package com.codigoparallevar.minicards.parts.viewers;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ImageFormat;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.media.Image;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import com.codigoparallevar.minicards.PartInstantiator;
|
||||
import com.codigoparallevar.minicards.ScrolledCanvas;
|
||||
import com.codigoparallevar.minicards.parts.connectors.ImageRoundInputConnector;
|
||||
import com.codigoparallevar.minicards.parts.style.CardTheme;
|
||||
import com.codigoparallevar.minicards.types.Moveable;
|
||||
import com.codigoparallevar.minicards.types.Part;
|
||||
import com.codigoparallevar.minicards.types.PartGrid;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.ImageInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.InputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.output.OutputConnector;
|
||||
import com.codigoparallevar.minicards.types.functional.Tuple2;
|
||||
import com.codigoparallevar.minicards.types.wireData.ImageSignal;
|
||||
import com.codigoparallevar.minicards.types.wireData.WireDataType;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ImageFrame implements Part {
|
||||
private static final String LogTag = "ImageFrame";
|
||||
private static final int DEFAULT_SIDE_SIZE = 400;
|
||||
private static final String IMAGE_INPUT_CONNECTOR_ID = "image_input_connector";
|
||||
|
||||
private final String _id;
|
||||
private final PartGrid _partGrid;
|
||||
private int _left;
|
||||
private int _top;
|
||||
private int _right;
|
||||
private int _bottom;
|
||||
private List<InputConnector> inputConnectors;
|
||||
private ImageInputConnector _imageInputConnector;
|
||||
private Bitmap lastImage;
|
||||
|
||||
public ImageFrame(String id, PartGrid partGrid, int left, int top, int right, int bottom) {
|
||||
_id = id;
|
||||
_partGrid = partGrid;
|
||||
_left = left;
|
||||
_top = top;
|
||||
_right = right;
|
||||
_bottom = bottom;
|
||||
|
||||
_imageInputConnector = new ImageRoundInputConnector(
|
||||
this,
|
||||
getInputConnectorCenterX(),
|
||||
getInputConnectorCenterY(),
|
||||
getInputConnectRadius());
|
||||
inputConnectors = new LinkedList<>();
|
||||
inputConnectors.add(_imageInputConnector);
|
||||
}
|
||||
|
||||
public ImageFrame(PartGrid partGrid, int left, int top, int right, int bottom) {
|
||||
this(UUID.randomUUID().toString(), partGrid, left, top, right, bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_left() {
|
||||
return _left;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_right() {
|
||||
return _right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_top() {
|
||||
return _top;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get_bottom() {
|
||||
return _bottom;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(ScrolledCanvas canvas, boolean devMode) {
|
||||
if (devMode){
|
||||
drawConnector(canvas);
|
||||
// drawWires(canvas, devMode);
|
||||
}
|
||||
|
||||
Rect frameRect = new Rect(_left, _top, _right, _bottom);
|
||||
if (this.lastImage == null) {
|
||||
Paint backdropPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
backdropPaint.setColor(Color.parseColor("#444444"));
|
||||
|
||||
canvas.drawRoundRect(new RectF(frameRect), 50, 50, backdropPaint);
|
||||
|
||||
Paint crossPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
crossPaint.setColor(Color.WHITE);
|
||||
|
||||
// Top
|
||||
canvas.drawLine(_left, _top, _right, _top, crossPaint);
|
||||
// Bottom
|
||||
canvas.drawLine(_left, _bottom, _right, _bottom, crossPaint);
|
||||
// Left
|
||||
canvas.drawLine(_left, _top, _left, _bottom, crossPaint);
|
||||
// Right
|
||||
canvas.drawLine(_right, _top, _right, _bottom, crossPaint);
|
||||
// Cross, top-left, bottom-right
|
||||
canvas.drawLine(_left, _top, _right, _bottom, crossPaint);
|
||||
// Cross, top-right, bottom-left
|
||||
canvas.drawLine(_right, _top, _left, _bottom, crossPaint);
|
||||
}
|
||||
else {
|
||||
canvas.drawBitmap(this.lastImage, frameRect);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawConnector(ScrolledCanvas canvas) {
|
||||
Paint outerInputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
outerInputConnectorPaint.setColor(CardTheme.IMAGE_CONNECTOR_COLOR_OUTER);
|
||||
|
||||
canvas.drawCircle(
|
||||
getInputConnectorCenterX(),
|
||||
getInputConnectorCenterY(),
|
||||
getInputConnectRadius(),
|
||||
outerInputConnectorPaint);
|
||||
|
||||
Paint innerInputConnectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
innerInputConnectorPaint.setColor(CardTheme.IMAGE_CONNECTOR_COLOR_INNER);
|
||||
|
||||
canvas.drawCircle(
|
||||
getInputConnectorCenterX(),
|
||||
getInputConnectorCenterY(),
|
||||
getInputConnectRadius() / 2,
|
||||
innerInputConnectorPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveEnd(int x, int y) {
|
||||
final int width = _right - _left;
|
||||
final int height = _bottom - _top;
|
||||
|
||||
_left = x - width / 2;
|
||||
_right = _left + width;
|
||||
|
||||
_top = y - height / 2;
|
||||
_bottom = _top + height;
|
||||
|
||||
_imageInputConnector.updatePosition(
|
||||
getInputConnectorCenterX(),
|
||||
getInputConnectorCenterY());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drop(int x, int y) {
|
||||
moveEnd(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touched() {
|
||||
Log.d(LogTag, "Touched");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<InputConnector> getInputConnectors() {
|
||||
return inputConnectors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OutputConnector> getOutputConnectors() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject serialize() throws JSONException {
|
||||
JSONObject serialized = new JSONObject();
|
||||
|
||||
serialized.put("id", _id);
|
||||
serialized.put("left", _left);
|
||||
serialized.put("top", _top);
|
||||
serialized.put("right", _right);
|
||||
serialized.put("bottom", _bottom);
|
||||
|
||||
return serialized;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(InputConnector roundInputConnector, WireDataType signal) {
|
||||
if (!(signal instanceof ImageSignal)) {
|
||||
Log.e(LogTag, "Mismatched type, expected {ImageSignal}, found {" + signal + "}" );
|
||||
}
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||
// No way to get the format?
|
||||
return;
|
||||
}
|
||||
|
||||
ImageSignal imgSignal = (ImageSignal) signal;
|
||||
Image image = imgSignal.get();
|
||||
if (image.getFormat() == ImageFormat.JPEG) {
|
||||
Image.Plane[] planes = image.getPlanes();
|
||||
if (planes.length != 1) {
|
||||
// TODO: Handle this case (what would it mean?)
|
||||
return ;
|
||||
}
|
||||
|
||||
ByteBuffer jpegBuffer = planes[0].getBuffer();
|
||||
byte[] jpegData = new byte[jpegBuffer.remaining()];
|
||||
jpegBuffer.get(jpegData);
|
||||
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length);
|
||||
this.lastImage = bitmap;
|
||||
this._partGrid.update(); // Maybe this can be avoided? Directly copying the data on the canvas?
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get_id() {
|
||||
return _id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputConnector getConnectorWithId(String inputConnectorId) {
|
||||
switch (inputConnectorId){
|
||||
case ImageFrame.IMAGE_INPUT_CONNECTOR_ID:
|
||||
return _imageInputConnector;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConnectorId(InputConnector inputConnector) {
|
||||
if (inputConnector == _imageInputConnector){
|
||||
return ImageFrame.IMAGE_INPUT_CONNECTOR_ID;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public void resume() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object query(Object lastValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Part deserialize(PartGrid partGrid, JSONObject data) throws JSONException {
|
||||
String id = data.getString("id");
|
||||
int left = data.getInt("left");
|
||||
int top = data.getInt("top");
|
||||
int right = data.getInt("right");
|
||||
int bottom = data.getInt("bottom");
|
||||
|
||||
return new ImageFrame(id, partGrid, left, top, right, bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsPoint(int x, int y) {
|
||||
return (x >= get_left()) && (x <= get_right())
|
||||
&& (y >= get_top()) && (y <= get_bottom());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Moveable getMoveable() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlink() {
|
||||
for (InputConnector input : getInputConnectors()) {
|
||||
input.unlink();
|
||||
}
|
||||
}
|
||||
|
||||
public int getInputConnectorCenterX() {
|
||||
return (get_left() + get_right()) / 2;
|
||||
}
|
||||
|
||||
private int getInputConnectRadius() {
|
||||
return (get_right() - get_left()) / 4;
|
||||
}
|
||||
|
||||
public int getInputConnectorCenterY() {
|
||||
return get_top();
|
||||
}
|
||||
|
||||
public static PartInstantiator getInstantiator() {
|
||||
final int halfSideSize = DEFAULT_SIDE_SIZE / 2;
|
||||
return new PartInstantiator() {
|
||||
@Override
|
||||
protected Part instantiate(PartGrid grid, Tuple2<Integer, Integer> center) {
|
||||
return new ImageFrame(grid,
|
||||
center.item1 - halfSideSize, center.item2 - halfSideSize,
|
||||
center.item1 + halfSideSize, center.item2 + halfSideSize);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ import com.codigoparallevar.minicards.types.PartGrid;
|
||||
import com.codigoparallevar.minicards.types.Selectable;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.AnyInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.BooleanInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.ImageInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.SignalInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.StringInputConnector;
|
||||
import com.codigoparallevar.minicards.types.functional.Tuple2;
|
||||
@ -83,6 +84,11 @@ class PartShowcaseView extends View implements PartGrid {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageInputConnector getImageInputConnectorOn(int xEnd, int yEnd) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tuple2<Integer, Integer> getCenteredOn() {
|
||||
return center;
|
||||
|
@ -15,11 +15,13 @@ import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.codigoparallevar.minicards.CanvasView;
|
||||
import com.codigoparallevar.minicards.PartInstantiator;
|
||||
import com.codigoparallevar.minicards.parts.android.CameraStreamer;
|
||||
import com.codigoparallevar.minicards.parts.buttons.RoundButton;
|
||||
import com.codigoparallevar.minicards.parts.logic.Ticker;
|
||||
import com.codigoparallevar.minicards.parts.logic.Toggle;
|
||||
import com.codigoparallevar.minicards.parts.samples.ColorBox;
|
||||
import com.codigoparallevar.minicards.parts.strings.ConvertToString;
|
||||
import com.codigoparallevar.minicards.parts.viewers.ImageFrame;
|
||||
import com.codigoparallevar.minicards.types.Part;
|
||||
import com.codigoparallevar.minicards.types.functional.Consumer;
|
||||
import com.codigoparallevar.minicards.types.functional.Tuple2;
|
||||
@ -37,18 +39,37 @@ import java.util.Vector;
|
||||
public class PartsHolder {
|
||||
private final Context context;
|
||||
|
||||
private final static List<Tuple2<String, PartInstantiator>> BuiltInParts =
|
||||
private final static List<Tuple2<String, PartInstantiator>> GuiParts =
|
||||
new Vector<Tuple2<String, PartInstantiator>>(){{
|
||||
add(new Tuple2<>("Round button", RoundButton.getInstantiator()));
|
||||
add(new Tuple2<>("Ticker", Ticker.getInstantiator()));
|
||||
add(new Tuple2<>("Red/Green box", ColorBox.getInstantiator()));
|
||||
add(new Tuple2<>("Image frame", ImageFrame.getInstantiator()));
|
||||
}};
|
||||
|
||||
private final static List<Tuple2<String, PartInstantiator>> AndroidParts =
|
||||
new Vector<Tuple2<String, PartInstantiator>>(){{
|
||||
add(new Tuple2<>("Camera", CameraStreamer.getInstantiator()));
|
||||
}};
|
||||
|
||||
private final static List<Tuple2<String, PartInstantiator>> MiscParts =
|
||||
new Vector<Tuple2<String, PartInstantiator>>(){{
|
||||
add(new Tuple2<>("Ticker", Ticker.getInstantiator()));
|
||||
add(new Tuple2<>("Toggle", Toggle.getInstantiator()));
|
||||
}};
|
||||
|
||||
private final static List<Tuple2<String, PartInstantiator>> DebuggingParts =
|
||||
new Vector<Tuple2<String, PartInstantiator>>(){{
|
||||
add(new Tuple2<>("ToString", ConvertToString.getInstantiator()));
|
||||
}};
|
||||
}};
|
||||
|
||||
|
||||
private final List<PartCategory> Categories = new Vector<PartCategory>() {{
|
||||
add(new PartCategory("Testing", BuiltInParts));
|
||||
add(new PartCategory("GUI elements", GuiParts));
|
||||
add(new PartCategory("Android", AndroidParts));
|
||||
add(new PartCategory("Misc", MiscParts));
|
||||
add(new PartCategory("Debugging", DebuggingParts));
|
||||
}};
|
||||
|
||||
private Map<String, ProgramakerBridgeInfo> bridgeInfoMap;
|
||||
private final static String LogTag = "PartsHolder";
|
||||
|
||||
|
@ -3,6 +3,7 @@ package com.codigoparallevar.minicards.types;
|
||||
import com.codigoparallevar.minicards.SignalListenerManager;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.AnyInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.BooleanInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.ImageInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.SignalInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.StringInputConnector;
|
||||
import com.codigoparallevar.minicards.types.functional.Tuple2;
|
||||
@ -17,9 +18,9 @@ public interface PartGrid {
|
||||
BooleanInputConnector getBooleanInputConnectorOn(int x, int y);
|
||||
AnyInputConnector getAnyInputConnectorOn(int x, int y);
|
||||
StringInputConnector getStringInputConnectorOn(int xEnd, int yEnd);
|
||||
ImageInputConnector getImageInputConnectorOn(int xEnd, int yEnd);
|
||||
|
||||
Tuple2<Integer,Integer> getCenteredOn();
|
||||
|
||||
void update();
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
package com.codigoparallevar.minicards.types.connectors.Wiring;
|
||||
|
||||
import com.codigoparallevar.minicards.types.Drawable;
|
||||
import com.codigoparallevar.minicards.types.Moveable;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.ImageInputConnector;
|
||||
import com.codigoparallevar.minicards.types.connectors.output.OutputConnector;
|
||||
import com.codigoparallevar.minicards.types.wireData.ImageSignal;
|
||||
|
||||
public class ImageWire extends Wire<ImageSignal, ImageInputConnector> implements Moveable, Drawable {
|
||||
public ImageWire(OutputConnector dropper, int xInit, int yInit) {
|
||||
super(dropper, xInit, yInit);
|
||||
}
|
||||
|
||||
public void send(ImageSignal signal) {
|
||||
if (_attachedTo != null) {
|
||||
_attachedTo.send(signal);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package com.codigoparallevar.minicards.types.connectors.input;
|
||||
|
||||
import com.codigoparallevar.minicards.types.wireData.ImageSignal;
|
||||
|
||||
public interface ImageInputConnector extends InputConnector<ImageSignal, ImageInputConnector> {
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.codigoparallevar.minicards.types.connectors.output;
|
||||
|
||||
import com.codigoparallevar.minicards.types.connectors.Wiring.ImageWire;
|
||||
import com.codigoparallevar.minicards.types.connectors.input.ImageInputConnector;
|
||||
import com.codigoparallevar.minicards.types.wireData.ImageSignal;
|
||||
|
||||
public interface ImageOutputConnector extends OutputConnector<
|
||||
ImageSignal,
|
||||
ImageInputConnector,
|
||||
ImageWire> {
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.codigoparallevar.minicards.types.wireData;
|
||||
|
||||
import android.media.Image;
|
||||
|
||||
public class ImageSignal implements WireDataType<Image> {
|
||||
public final Image value;
|
||||
|
||||
public ImageSignal(Image value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image get() {
|
||||
return value;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user