From f82edf041c76019f95b59b8a1140c17851688081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Mart=C3=ADnez=20Portela?= Date: Fri, 5 Jun 2020 15:16:45 +0200 Subject: [PATCH] WIP: Add simple image capture/viewing blocks. --- app/src/main/AndroidManifest.xml | 23 +- .../minicards/CanvasView.java | 30 ++ .../minicards/CardActivity.java | 43 ++ .../codigoparallevar/minicards/CardFile.java | 14 +- .../minicards/ScrolledCanvas.java | 17 +- .../minicards/StubPartGrid.java | 6 + .../parts/android/CameraStreamer.java | 458 ++++++++++++++++++ .../connectors/ImageRoundInputConnector.java | 98 ++++ .../connectors/ImageRoundOutputConnector.java | 183 +++++++ .../minicards/parts/logic/Ticker.java | 25 +- .../minicards/parts/samples/Placeholder.java | 189 -------- .../minicards/parts/style/CardTheme.java | 3 + .../minicards/parts/viewers/ImageFrame.java | 316 ++++++++++++ .../minicards/toolbox/PartShowcaseView.java | 6 + .../minicards/toolbox/PartsHolder.java | 29 +- .../minicards/types/PartGrid.java | 3 +- .../types/connectors/Wiring/ImageWire.java | 19 + .../connectors/input/ImageInputConnector.java | 6 + .../output/ImageOutputConnector.java | 11 + .../minicards/types/wireData/ImageSignal.java | 16 + 20 files changed, 1275 insertions(+), 220 deletions(-) create mode 100644 app/src/main/java/com/codigoparallevar/minicards/parts/android/CameraStreamer.java create mode 100644 app/src/main/java/com/codigoparallevar/minicards/parts/connectors/ImageRoundInputConnector.java create mode 100644 app/src/main/java/com/codigoparallevar/minicards/parts/connectors/ImageRoundOutputConnector.java delete mode 100644 app/src/main/java/com/codigoparallevar/minicards/parts/samples/Placeholder.java create mode 100644 app/src/main/java/com/codigoparallevar/minicards/parts/viewers/ImageFrame.java create mode 100644 app/src/main/java/com/codigoparallevar/minicards/types/connectors/Wiring/ImageWire.java create mode 100644 app/src/main/java/com/codigoparallevar/minicards/types/connectors/input/ImageInputConnector.java create mode 100644 app/src/main/java/com/codigoparallevar/minicards/types/connectors/output/ImageOutputConnector.java create mode 100644 app/src/main/java/com/codigoparallevar/minicards/types/wireData/ImageSignal.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fb8b0c5..f395f2c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,18 +2,25 @@ + + + + + + + + + + + + + - - - - - - - - + + = 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); + } } diff --git a/app/src/main/java/com/codigoparallevar/minicards/CardActivity.java b/app/src/main/java/com/codigoparallevar/minicards/CardActivity.java index 76632a4..8ee0dca 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/CardActivity.java +++ b/app/src/main/java/com/codigoparallevar/minicards/CardActivity.java @@ -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 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); + } + } + } } diff --git a/app/src/main/java/com/codigoparallevar/minicards/CardFile.java b/app/src/main/java/com/codigoparallevar/minicards/CardFile.java index be14bd3..c4e32d9 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/CardFile.java +++ b/app/src/main/java/com/codigoparallevar/minicards/CardFile.java @@ -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.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> staticValuePartInfo = CameraStreamer.deserialize( + grid, + jsonObject.getJSONObject("_data")); + + return staticValuePartInfo; + } else { throw new JSONException("Expected known class, found " + type); } diff --git a/app/src/main/java/com/codigoparallevar/minicards/ScrolledCanvas.java b/app/src/main/java/com/codigoparallevar/minicards/ScrolledCanvas.java index 90a3858..1bc5cad 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/ScrolledCanvas.java +++ b/app/src/main/java/com/codigoparallevar/minicards/ScrolledCanvas.java @@ -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); + } } \ No newline at end of file diff --git a/app/src/main/java/com/codigoparallevar/minicards/StubPartGrid.java b/app/src/main/java/com/codigoparallevar/minicards/StubPartGrid.java index 4cff119..2d7ced6 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/StubPartGrid.java +++ b/app/src/main/java/com/codigoparallevar/minicards/StubPartGrid.java @@ -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 getCenteredOn() { return null; diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/android/CameraStreamer.java b/app/src/main/java/com/codigoparallevar/minicards/parts/android/CameraStreamer.java new file mode 100644 index 0000000..9bf4d6b --- /dev/null +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/android/CameraStreamer.java @@ -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 _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 getInputConnectors() { + return Collections.emptyList(); + } + + @Override + public List 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> 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 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>(cameraStreamer, connections); + } + + private List> serializeConnectionEndpoints() { + List> serializedData = new LinkedList<>(); + + for (Tuple2 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 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 center) { + return new CameraStreamer(grid, + center.item1 - halfSideSize, center.item2 - halfSideSize, + center.item1 + halfSideSize, center.item2 + halfSideSize); + } + }; + } +} diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/ImageRoundInputConnector.java b/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/ImageRoundInputConnector.java new file mode 100644 index 0000000..9789d60 --- /dev/null +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/ImageRoundInputConnector.java @@ -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 _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 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); + } +} diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/ImageRoundOutputConnector.java b/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/ImageRoundOutputConnector.java new file mode 100644 index 0000000..0bac6a7 --- /dev/null +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/connectors/ImageRoundOutputConnector.java @@ -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 { + 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 _wires; + private final HashSet _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> getConnectionEndpoints() { + List> 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 getWires() { + return this._wires; + } +} diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/logic/Ticker.java b/app/src/main/java/com/codigoparallevar/minicards/parts/logic/Ticker.java index f706311..68c7ab0 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/parts/logic/Ticker.java +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/logic/Ticker.java @@ -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; } } }); diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/samples/Placeholder.java b/app/src/main/java/com/codigoparallevar/minicards/parts/samples/Placeholder.java deleted file mode 100644 index b471966..0000000 --- a/app/src/main/java/com/codigoparallevar/minicards/parts/samples/Placeholder.java +++ /dev/null @@ -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 getInputConnectors() { - return Collections.emptyList(); - } - - @Override - public List 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(); - } - } -} diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/style/CardTheme.java b/app/src/main/java/com/codigoparallevar/minicards/parts/style/CardTheme.java index f1d051d..559780d 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/parts/style/CardTheme.java +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/style/CardTheme.java @@ -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; } diff --git a/app/src/main/java/com/codigoparallevar/minicards/parts/viewers/ImageFrame.java b/app/src/main/java/com/codigoparallevar/minicards/parts/viewers/ImageFrame.java new file mode 100644 index 0000000..9e3e86e --- /dev/null +++ b/app/src/main/java/com/codigoparallevar/minicards/parts/viewers/ImageFrame.java @@ -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 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 getInputConnectors() { + return inputConnectors; + } + + @Override + public List 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 center) { + return new ImageFrame(grid, + center.item1 - halfSideSize, center.item2 - halfSideSize, + center.item1 + halfSideSize, center.item2 + halfSideSize); + } + }; + } +} diff --git a/app/src/main/java/com/codigoparallevar/minicards/toolbox/PartShowcaseView.java b/app/src/main/java/com/codigoparallevar/minicards/toolbox/PartShowcaseView.java index 5a6c59b..5d7fbc1 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/toolbox/PartShowcaseView.java +++ b/app/src/main/java/com/codigoparallevar/minicards/toolbox/PartShowcaseView.java @@ -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 getCenteredOn() { return center; diff --git a/app/src/main/java/com/codigoparallevar/minicards/toolbox/PartsHolder.java b/app/src/main/java/com/codigoparallevar/minicards/toolbox/PartsHolder.java index 21ab32c..ad40bce 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/toolbox/PartsHolder.java +++ b/app/src/main/java/com/codigoparallevar/minicards/toolbox/PartsHolder.java @@ -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> BuiltInParts = + private final static List> GuiParts = new Vector>(){{ 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> AndroidParts = + new Vector>(){{ + add(new Tuple2<>("Camera", CameraStreamer.getInstantiator())); + }}; + + private final static List> MiscParts = + new Vector>(){{ + add(new Tuple2<>("Ticker", Ticker.getInstantiator())); add(new Tuple2<>("Toggle", Toggle.getInstantiator())); + }}; + + private final static List> DebuggingParts = + new Vector>(){{ add(new Tuple2<>("ToString", ConvertToString.getInstantiator())); - }}; + }}; + private final List Categories = new Vector() {{ - 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 bridgeInfoMap; private final static String LogTag = "PartsHolder"; diff --git a/app/src/main/java/com/codigoparallevar/minicards/types/PartGrid.java b/app/src/main/java/com/codigoparallevar/minicards/types/PartGrid.java index 2cffe7e..7c08c2e 100644 --- a/app/src/main/java/com/codigoparallevar/minicards/types/PartGrid.java +++ b/app/src/main/java/com/codigoparallevar/minicards/types/PartGrid.java @@ -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 getCenteredOn(); void update(); - } diff --git a/app/src/main/java/com/codigoparallevar/minicards/types/connectors/Wiring/ImageWire.java b/app/src/main/java/com/codigoparallevar/minicards/types/connectors/Wiring/ImageWire.java new file mode 100644 index 0000000..2874546 --- /dev/null +++ b/app/src/main/java/com/codigoparallevar/minicards/types/connectors/Wiring/ImageWire.java @@ -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 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); + } + } +} diff --git a/app/src/main/java/com/codigoparallevar/minicards/types/connectors/input/ImageInputConnector.java b/app/src/main/java/com/codigoparallevar/minicards/types/connectors/input/ImageInputConnector.java new file mode 100644 index 0000000..e2af6f0 --- /dev/null +++ b/app/src/main/java/com/codigoparallevar/minicards/types/connectors/input/ImageInputConnector.java @@ -0,0 +1,6 @@ +package com.codigoparallevar.minicards.types.connectors.input; + +import com.codigoparallevar.minicards.types.wireData.ImageSignal; + +public interface ImageInputConnector extends InputConnector { +} diff --git a/app/src/main/java/com/codigoparallevar/minicards/types/connectors/output/ImageOutputConnector.java b/app/src/main/java/com/codigoparallevar/minicards/types/connectors/output/ImageOutputConnector.java new file mode 100644 index 0000000..d60ce77 --- /dev/null +++ b/app/src/main/java/com/codigoparallevar/minicards/types/connectors/output/ImageOutputConnector.java @@ -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> { +} diff --git a/app/src/main/java/com/codigoparallevar/minicards/types/wireData/ImageSignal.java b/app/src/main/java/com/codigoparallevar/minicards/types/wireData/ImageSignal.java new file mode 100644 index 0000000..6890511 --- /dev/null +++ b/app/src/main/java/com/codigoparallevar/minicards/types/wireData/ImageSignal.java @@ -0,0 +1,16 @@ +package com.codigoparallevar.minicards.types.wireData; + +import android.media.Image; + +public class ImageSignal implements WireDataType { + public final Image value; + + public ImageSignal(Image value) { + this.value = value; + } + + @Override + public Image get() { + return value; + } +}