WIP: Add simple image capture/viewing blocks.

This commit is contained in:
Sergio Martínez Portela 2020-06-05 15:16:45 +02:00
parent f8786abc14
commit f82edf041c
20 changed files with 1275 additions and 220 deletions

View File

@ -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"

View File

@ -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);
}
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);
}
};
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
});

View File

@ -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();
}
}
}

View File

@ -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;
}

View File

@ -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);
}
};
}
}

View File

@ -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;

View File

@ -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";

View File

@ -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();
}

View File

@ -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);
}
}
}

View File

@ -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> {
}

View File

@ -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> {
}

View File

@ -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;
}
}