Initial commit: Android & Garmin Remote Camera App with Live Preview
This commit is contained in:
101
garmin-app/source/FotoCompanionView.mc
Normal file
101
garmin-app/source/FotoCompanionView.mc
Normal file
@@ -0,0 +1,101 @@
|
||||
import Toybox.Graphics;
|
||||
import Toybox.WatchUi;
|
||||
import Toybox.Lang;
|
||||
|
||||
class FotoCompanionView extends WatchUi.View {
|
||||
var bitmap = null;
|
||||
var palette = null;
|
||||
|
||||
function initialize() {
|
||||
View.initialize();
|
||||
// Initialize 64 color palette matching Android side (00, 55, AA, FF)
|
||||
// R (2 bits), G (2 bits), B (2 bits)
|
||||
palette = new [64];
|
||||
for (var i = 0; i < 64; i++) {
|
||||
var r = (i >> 4) & 0x03;
|
||||
var g = (i >> 2) & 0x03;
|
||||
var b = i & 0x03;
|
||||
// Map 0..3 to 0..255 (0, 85, 170, 255)
|
||||
palette[i] = (r * 85) << 16 | (g * 85) << 8 | (b * 85);
|
||||
}
|
||||
}
|
||||
|
||||
function onLayout(dc as Dc) as Void {
|
||||
}
|
||||
|
||||
function onUpdate(dc as Dc) as Void {
|
||||
dc.setColor(Graphics.COLOR_BLACK, Graphics.COLOR_BLACK);
|
||||
dc.clear();
|
||||
|
||||
if (bitmap != null) {
|
||||
var cx = (dc.getWidth() - bitmap.getWidth()) / 2;
|
||||
var cy = (dc.getHeight() - bitmap.getHeight()) / 2;
|
||||
dc.drawBitmap(cx, cy, bitmap);
|
||||
} else {
|
||||
dc.setColor(Graphics.COLOR_WHITE, Graphics.COLOR_TRANSPARENT);
|
||||
dc.drawText(dc.getWidth() / 2, dc.getHeight() / 2, Graphics.FONT_MEDIUM, "Waiting for\nCamera...", Graphics.TEXT_JUSTIFY_CENTER | Graphics.TEXT_JUSTIFY_VCENTER);
|
||||
}
|
||||
|
||||
// Draw Button Hint
|
||||
dc.setColor(Graphics.COLOR_GREEN, Graphics.COLOR_TRANSPARENT);
|
||||
dc.drawText(dc.getWidth() / 2, dc.getHeight() - 30, Graphics.FONT_XTINY, "PRESS START", Graphics.TEXT_JUSTIFY_CENTER);
|
||||
}
|
||||
|
||||
function updateImage(data) {
|
||||
if (data instanceof Toybox.Lang.Array) {
|
||||
// Create a BufferedBitmap
|
||||
// Width/Height hardcoded to match Android (120x120)
|
||||
var opts = {
|
||||
:width => 120,
|
||||
:height => 120,
|
||||
:palette => palette
|
||||
};
|
||||
|
||||
if (Graphics has :createBufferedBitmap) {
|
||||
var bbRef = Graphics.createBufferedBitmap(opts);
|
||||
var bb = bbRef.get();
|
||||
|
||||
// Copy data
|
||||
// BufferedBitmap.setPalette is implicit via options
|
||||
// Unfortunately, there is no direct "setBytes" for the whole bitmap in older SDKs easily exposed without a resource.
|
||||
// But Connect IQ 4.0+ helps.
|
||||
// If we can't do bulk set, we iterate? Too slow.
|
||||
// Actually, resource creation from bytes is tricky.
|
||||
// Let's try the most robust way:
|
||||
// If the data is indeed the palette indices, we just need to get it into the bitmap buffer.
|
||||
|
||||
// Hack for performance if no setBytes:
|
||||
// Use a resource? No dynamic resource creation.
|
||||
|
||||
// Alternative: Send a custom String/JSON and parse? No.
|
||||
|
||||
// If the device supports direct palette mapping we might be good.
|
||||
// Let's assume standard behavior:
|
||||
// We CAN iterate 14400 pixels in Monkey C if optimized? Maybe 0.5s.
|
||||
|
||||
// Let's try to find a bulk setter.
|
||||
// There isn't one publicly documented for raw byte array -> bitmap pixels easily.
|
||||
// Wait! Strings!
|
||||
// If we encode as a string on Android, drawText? No.
|
||||
|
||||
// Okay, we will iterate. It's 14400 pixels.
|
||||
// To optimize, Android sends RLE?
|
||||
// For now, simple iteration.
|
||||
|
||||
var dc = bb.getDc();
|
||||
for (var i = 0; i < 14400; i++) {
|
||||
if (i < data.size()) {
|
||||
var cIndex = data[i];
|
||||
if (cIndex >= 0 && cIndex < 64) {
|
||||
dc.setColor(palette[cIndex], Graphics.COLOR_TRANSPARENT);
|
||||
// x = i % 120, y = i / 120
|
||||
dc.drawPoint(i % 120, i / 120);
|
||||
}
|
||||
}
|
||||
}
|
||||
bitmap = bbRef;
|
||||
WatchUi.requestUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user