package com.dappervision.wearscript;
import android.util.Base64;
import android.webkit.JavascriptInterface;
import com.dappervision.wearscript.events.ActivityEvent;
import com.dappervision.wearscript.events.BluetoothBondEvent;
import com.dappervision.wearscript.events.BluetoothModeEvent;
import com.dappervision.wearscript.events.BluetoothWriteEvent;
import com.dappervision.wearscript.events.CallbackRegistration;
import com.dappervision.wearscript.events.CameraEvents;
import com.dappervision.wearscript.events.CardTreeEvent;
import com.dappervision.wearscript.events.ChannelSubscribeEvent;
import com.dappervision.wearscript.events.ChannelUnsubscribeEvent;
import com.dappervision.wearscript.events.ControlEvent;
import com.dappervision.wearscript.events.DataLogEvent;
import com.dappervision.wearscript.events.GistSyncEvent;
import com.dappervision.wearscript.events.JsCall;
import com.dappervision.wearscript.events.LiveCardEvent;
import com.dappervision.wearscript.events.LiveCardSetMenuEvent;
import com.dappervision.wearscript.events.MediaActionEvent;
import com.dappervision.wearscript.events.MediaEvent;
import com.dappervision.wearscript.events.PebbleMessageEvent;
import com.dappervision.wearscript.events.PicarusBenchmarkEvent;
import com.dappervision.wearscript.events.PicarusEvent;
import com.dappervision.wearscript.events.PicarusModelCreateEvent;
import com.dappervision.wearscript.events.PicarusModelProcessEvent;
import com.dappervision.wearscript.events.PicarusModelProcessStreamEvent;
import com.dappervision.wearscript.events.PicarusModelProcessWarpEvent;
import com.dappervision.wearscript.events.SayEvent;
import com.dappervision.wearscript.events.ScreenEvent;
import com.dappervision.wearscript.events.SendEvent;
import com.dappervision.wearscript.events.SendSubEvent;
import com.dappervision.wearscript.events.SensorJSEvent;
import com.dappervision.wearscript.events.ServerConnectEvent;
import com.dappervision.wearscript.events.ShutdownEvent;
import com.dappervision.wearscript.events.SoundEvent;
import com.dappervision.wearscript.events.SpeechRecognizeEvent;
import com.dappervision.wearscript.events.WarpModeEvent;
import com.dappervision.wearscript.events.WarpSetAnnotationEvent;
import com.dappervision.wearscript.events.WarpSetupHomographyEvent;
import com.dappervision.wearscript.events.WifiEvent;
import com.dappervision.wearscript.events.WifiScanEvent;
import com.dappervision.wearscript.managers.BarcodeManager;
import com.dappervision.wearscript.managers.BluetoothManager;
import com.dappervision.wearscript.managers.CameraManager;
import com.dappervision.wearscript.managers.ConnectionManager;
import com.dappervision.wearscript.managers.EyeManager;
import com.dappervision.wearscript.managers.GestureManager;
import com.dappervision.wearscript.managers.OpenCVManager;
import com.dappervision.wearscript.managers.PicarusManager;
import com.dappervision.wearscript.managers.WarpManager;
import com.dappervision.wearscript.managers.PebbleManager;
import com.dappervision.wearscript.managers.WifiManager;
import org.json.simple.JSONObject;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.Buffer;
import java.util.Arrays;
import java.util.List;
import java.util.TreeMap;
public class WearScript {
BackgroundService bs;
String TAG = "WearScript";
TreeMap<String, Integer> sensors;
String sensorsJS;
List<String> touchGesturesList;
List<String> pebbleGesturesList;
WearScript(BackgroundService bs) {
this.bs = bs;
this.sensors = new TreeMap<String, Integer>();
// Sensor Types
for (SENSOR s : SENSOR.values()) {
this.sensors.put(s.toString(), s.id());
}
this.sensorsJS = (new JSONObject(this.sensors)).toJSONString();
String[] touchGestures = {"onGesture", "onFingerCountChanged", "onScroll", "onTwoFingerScroll"};
touchGesturesList = Arrays.asList(touchGestures);
String[] pebbleGestures = {"onPebbleSingleClick", "onPebbleLongClick", "onPebbleAccelTap"};
pebbleGesturesList = Arrays.asList(pebbleGestures);
}
private String classToChar(Class c) {
if (c.equals(float.class) || c.equals(int.class))
return "D";
else if (c.equals(String.class))
return "S";
else if (c.equals(boolean.class))
return "B";
else if (Buffer.class.isAssignableFrom(c) || c.equals(Buffer.class))
return "U";
else if (c.equals(void.class))
return "V";
return "?";
}
@JavascriptInterface
public int sensor(String name) {
return this.sensors.get(name);
}
@JavascriptInterface
public void shutdown() {
//Global event
Utils.getEventBus().post(new ShutdownEvent());
}
@JavascriptInterface
public String sensors() {
return this.sensorsJS;
}
@JavascriptInterface
public void say(String text) {
Utils.eventBusPost(new SayEvent(text));
Log.i(TAG, "say: " + text);
}
@JavascriptInterface
public void serverTimeline(String ti) {
Log.i(TAG, "timeline");
Utils.eventBusPost(new SendSubEvent("mirror", ti));
}
@JavascriptInterface
public void sensorOn(int type, double sampleTime) {
Log.i(TAG, "sensorOn: " + Integer.toString(type));
Utils.eventBusPost(new SensorJSEvent(type, true, sampleTime, null));
}
@JavascriptInterface
public void sensorOn(int type, double sampleTime, String callback) {
Log.i(TAG, "sensorOn: " + Integer.toString(type) + " callback: " + callback);
Utils.eventBusPost(new SensorJSEvent(type, true, sampleTime, callback));
}
@JavascriptInterface
public void log(String msg) {
//Global event
Utils.eventBusPost(new SendSubEvent("log", msg));
}
@JavascriptInterface
public void sensorOff(int type) {
Log.i(TAG, "sensorOff: " + Integer.toString(type));
Utils.eventBusPost(new SensorJSEvent(type, false));
}
@JavascriptInterface
public void mediaLoad(String uri, boolean looping){
try {
Utils.eventBusPost(new MediaEvent(new URI(uri), looping));
} catch (URISyntaxException e) {
// TODO(kurtisnelson): Handle
}
}
@JavascriptInterface
public void mediaPlay(){
Utils.eventBusPost(new MediaActionEvent("play"));
}
@JavascriptInterface
public void mediaPause(){
Utils.eventBusPost(new MediaActionEvent("pause"));
}
@JavascriptInterface
public void mediaStop(){
Utils.eventBusPost(new MediaActionEvent("stop"));
}
@JavascriptInterface
public void serverConnect(String server, String callback) {
Log.i(TAG, "serverConnect: " + server);
if (server.equals("{{WSUrl}}"))
server = bs.getDefaultUrl();
if (server == null) {
Log.e(TAG, "Lifecycle: Invalid url provided");
return;
}
try {
Utils.eventBusPost(new ServerConnectEvent(new URI(server), callback));
} catch (URISyntaxException e) {
// TODO(brandyn): Handle
}
}
@JavascriptInterface
public void displayWebView() {
Log.i(TAG, "displayWebView");
Utils.eventBusPost(new ActivityEvent(ActivityEvent.Mode.WEBVIEW));
}
@JavascriptInterface
public void displayWarpView() {
Log.i(TAG, "displayWarpView");
Utils.eventBusPost(new ActivityEvent(ActivityEvent.Mode.WARP));
}
@JavascriptInterface
public void displayWarpView(String homography) {
Log.i(TAG, "displayWarpView");
Utils.eventBusPost(new WarpSetupHomographyEvent(homography));
Utils.eventBusPost(new ActivityEvent(ActivityEvent.Mode.WARP));
}
@JavascriptInterface
public void cvInit(String callback) {
Utils.eventBusPost(new CallbackRegistration(OpenCVManager.class, callback).setEvent(OpenCVManager.LOAD));
}
@JavascriptInterface
public void warpPreviewSamplePlane(String callback) {
Log.i(TAG, "warpPreviewsample");
Utils.eventBusPost(new CallbackRegistration(WarpManager.class, callback).setEvent(WarpManager.SAMPLE));
Utils.eventBusPost(new WarpModeEvent(WarpManager.Mode.SAMPLEWARPPLANE));
}
@JavascriptInterface
public void warpPreviewSampleGlass(String callback) {
Log.i(TAG, "warpPreviewsample");
Utils.eventBusPost(new CallbackRegistration(WarpManager.class, callback).setEvent(WarpManager.SAMPLE));
Utils.eventBusPost(new WarpModeEvent(WarpManager.Mode.SAMPLEWARPGLASS));
}
@JavascriptInterface
public void warpARTags(String callback) {
Log.i(TAG, "warpARTags");
Utils.eventBusPost(new CallbackRegistration(WarpManager.class, callback).setEvent(WarpManager.ARTAGS));
}
@JavascriptInterface
public void warpGlassToPreviewH(String callback) {
Log.i(TAG, "warpPreviewsample");
Utils.eventBusPost(new CallbackRegistration(WarpManager.class, callback).setEvent(WarpManager.GLASS2PREVIEWH));
}
@JavascriptInterface
public void warpSetOverlay(String image) {
Utils.eventBusPost(new WarpSetAnnotationEvent(Base64.decode(image, Base64.NO_WRAP)));
}
@JavascriptInterface
public void cameraOff() {
Utils.eventBusPost(new CameraEvents.Start(0));
}
@JavascriptInterface
public void cameraPhotoData(String callback) {
CallbackRegistration cr = new CallbackRegistration(CameraManager.class, callback);
cr.setEvent(CameraManager.PHOTO);
Utils.eventBusPost(cr);
}
@JavascriptInterface
public void cameraPhoto(String callback) {
CallbackRegistration cr = new CallbackRegistration(CameraManager.class, callback);
cr.setEvent(CameraManager.PHOTO_PATH);
Utils.eventBusPost(cr);
}
@JavascriptInterface
public void cameraPhoto() {
// TODO(brandyn): This is a hack, we should have a separate event to take a photo and just register the callback prior to that
CallbackRegistration cr = new CallbackRegistration(CameraManager.class, null);
cr.setEvent(CameraManager.PHOTO_PATH);
Utils.eventBusPost(cr);
}
@JavascriptInterface
public void cameraVideo() {
CallbackRegistration cr = new CallbackRegistration(CameraManager.class, null);
cr.setEvent(CameraManager.VIDEO_PATH);
Utils.eventBusPost(cr);
}
@JavascriptInterface
public void cameraVideo(String callback) {
CallbackRegistration cr = new CallbackRegistration(CameraManager.class, callback);
cr.setEvent(CameraManager.VIDEO_PATH);
Utils.eventBusPost(cr);
}
@JavascriptInterface
public void cameraOn(double imagePeriod, int maxHeight, int maxWidth, boolean background) {
Utils.eventBusPost(new CameraEvents.Start(imagePeriod, maxHeight, maxWidth, background));
}
@JavascriptInterface
public void cameraOn(double imagePeriod, int maxHeight, int maxWidth, boolean background, String callback) {
Log.d(TAG, "cameraOn: Callback: " + callback);
cameraOn(imagePeriod, maxHeight, maxWidth, background);
CallbackRegistration cr = new CallbackRegistration(CameraManager.class, callback);
cr.setEvent(0);
Utils.eventBusPost(cr);
}
@JavascriptInterface
public void activityCreate() {
Utils.eventBusPost(new ActivityEvent(ActivityEvent.Mode.CREATE));
}
@JavascriptInterface
public void activityDestroy() {
Utils.eventBusPost(new ActivityEvent(ActivityEvent.Mode.DESTROY));
}
@JavascriptInterface
public void wifiOff() {
Utils.eventBusPost(new WifiEvent(false));
}
@JavascriptInterface
public void wifiOn() {
Utils.eventBusPost(new WifiEvent(true));
}
@JavascriptInterface
public void wifiOn(String callback) {
CallbackRegistration cr = new CallbackRegistration(WifiManager.class, callback);
cr.setEvent(WifiManager.WIFI);
Utils.eventBusPost(cr);
Utils.eventBusPost(new WifiEvent(true));
}
@JavascriptInterface
public void wifiScan() {
Utils.eventBusPost(new WifiScanEvent());
}
@JavascriptInterface
public void dataLog(boolean local, boolean server, double sensorDelay) {
Utils.eventBusPost(new DataLogEvent(local, server, sensorDelay));
}
@JavascriptInterface
public boolean scriptVersion(int version) {
if (version == 1) {
return false;
} else {
Utils.eventBusPost(new SayEvent("Script version incompatible with client"));
return true;
}
}
@JavascriptInterface
public void wake() {
Log.i(TAG, "wake");
Utils.eventBusPost(new ScreenEvent(true));
}
@JavascriptInterface
public void qr(String cb) {
Log.i(TAG, "QR");
Utils.eventBusPost(new CallbackRegistration(BarcodeManager.class, cb).setEvent(BarcodeManager.QR_CODE));
}
@JavascriptInterface
public void subscribe(String name, String cb) {
Log.i(TAG, "subscribe");
Utils.eventBusPost(new ChannelSubscribeEvent(name, cb));
}
@JavascriptInterface
public void unsubscribe(String name) {
Log.i(TAG, "unsubscribe");
Utils.eventBusPost(new ChannelUnsubscribeEvent(name));
}
@JavascriptInterface
public void publish(String channel, String data) {
Log.i(TAG, "publish " + channel);
Utils.eventBusPost(new SendEvent(channel, Base64.decode(data, Base64.NO_WRAP)));
}
@JavascriptInterface
public String echo(String data) {
Log.i(TAG, "echo");
return data;
}
@JavascriptInterface
public int echolen(String data) {
Log.i(TAG, "echolen");
return data.length();
}
@JavascriptInterface
public void echocall(String data) {
Log.i(TAG, "echocb");
Utils.eventBusPost(new JsCall(data));
}
@JavascriptInterface
public void gistSync() {
Log.i(TAG, "gistSync");
Utils.eventBusPost(new GistSyncEvent());
}
@JavascriptInterface
public void gestureCallback(String event, String callback) {
Log.i(TAG, "gestureCallback: " + event + " " + callback);
Class route = EyeManager.class;
for (String gesture : touchGesturesList)
if (event.startsWith(gesture)) {
route = GestureManager.class;
break;
}
for (String pebbleGesture : pebbleGesturesList) {
if (event.startsWith(pebbleGesture)) {
route = PebbleManager.class;
break;
}
}
Utils.eventBusPost(new CallbackRegistration(route, callback).setEvent(event));
}
@JavascriptInterface
public void pebbleSetTitle(String title, boolean clear) {
Log.i(TAG, "pebbleSetTitle: " + title);
Utils.eventBusPost(new PebbleMessageEvent("setTitle", title, clear));
}
@JavascriptInterface
public void pebbleSetSubtitle(String subTitle, boolean clear) {
Log.i(TAG, "pebbleSetSubtitle: " + subTitle);
Utils.eventBusPost(new PebbleMessageEvent("setSubtitle", subTitle, clear));
}
@JavascriptInterface
public void pebbleSetBody(String body, boolean clear) {
Log.i(TAG, "pebbleSetSubTitle: " + body);
Utils.eventBusPost(new PebbleMessageEvent("setBody", body, clear));
}
@JavascriptInterface
public void pebbleVibe(int type) {
Log.i(TAG, "pebbleVibe: " + type);
Utils.eventBusPost(new PebbleMessageEvent("vibe", type));
}
@JavascriptInterface
public void speechRecognize(String prompt, String callback) {
Utils.eventBusPost(new SpeechRecognizeEvent(prompt, callback));
}
@JavascriptInterface
public void liveCardCreate(boolean nonSilent, double period, String menu) {
requiresGDK();
Utils.eventBusPost(new LiveCardSetMenuEvent(menu));
Utils.eventBusPost(new LiveCardEvent(nonSilent, period));
}
@JavascriptInterface
public void liveCardDestroy() {
requiresGDK();
Utils.eventBusPost(new LiveCardEvent(false, 0));
}
@JavascriptInterface
public void displayCardTree() {
Utils.eventBusPost(new ActivityEvent(ActivityEvent.Mode.CARD_TREE));
}
@JavascriptInterface
public void sound(String type) {
Log.i(TAG, "sound");
Utils.eventBusPost(new SoundEvent(type));
}
@JavascriptInterface
public void cardTree(String treeJS) {
requiresGDK();
Utils.eventBusPost(new CardTreeEvent(treeJS));
}
@JavascriptInterface
public void bluetoothList(String callback) {
Utils.eventBusPost(new CallbackRegistration(BluetoothManager.class, callback).setEvent(BluetoothManager.LIST));
}
@JavascriptInterface
public void bluetoothDiscover(String callback) {
Utils.eventBusPost(new CallbackRegistration(BluetoothManager.class, callback).setEvent(BluetoothManager.DISCOVERY_START));
}
@JavascriptInterface
public void bluetoothBond(String address, String pin) {
Utils.eventBusPost(new BluetoothBondEvent(address, pin));
}
@JavascriptInterface
public void bluetoothRead(String device, String callback) {
Utils.eventBusPost(new CallbackRegistration(BluetoothManager.class, callback).setEvent(BluetoothManager.READ + device));
}
@JavascriptInterface
public void bluetoothWrite(String address, String data) {
Utils.eventBusPost(new BluetoothWriteEvent(address, data));
}
@JavascriptInterface
public void bluetoothEnable() {
Utils.eventBusPost(new BluetoothModeEvent(true));
}
@JavascriptInterface
public void bluetoothDisable() {
Utils.eventBusPost(new BluetoothModeEvent(false));
}
@JavascriptInterface
public String groupDevice() {
ConnectionManager cm = (ConnectionManager) bs.getManager(ConnectionManager.class);
if (cm == null)
return null;
return cm.groupDevice();
}
@JavascriptInterface
public String group() {
ConnectionManager cm = (ConnectionManager) bs.getManager(ConnectionManager.class);
if (cm == null)
return null;
return cm.group();
}
@JavascriptInterface
public String device() {
ConnectionManager cm = (ConnectionManager) bs.getManager(ConnectionManager.class);
if (cm == null)
return null;
return cm.device();
}
@JavascriptInterface
public void control(String event, boolean adb){
Utils.eventBusPost(new ControlEvent(event, adb));
}
@JavascriptInterface
public void picarus(String model, String input, String callback) {
Utils.eventBusPost((new CallbackRegistration(PicarusManager.class, callback)).setEvent(callback));
Utils.eventBusPost(new PicarusEvent(Base64.decode(model.getBytes(), Base64.NO_WRAP),
Base64.decode(input.getBytes(), Base64.NO_WRAP),
callback));
}
@JavascriptInterface
public void picarusBenchmark() {
Utils.eventBusPost(new PicarusBenchmarkEvent());
}
@JavascriptInterface
public void picarusModelCreate(String model, int id, String callback) {
Utils.eventBusPost(new PicarusModelCreateEvent(Base64.decode(model.getBytes(), Base64.NO_WRAP), id, callback));
}
@JavascriptInterface
public void picarusModelProcess(int id, String input, String callback) {
Utils.eventBusPost(new PicarusModelProcessEvent(id, Base64.decode(input.getBytes(), Base64.NO_WRAP), callback));
}
@JavascriptInterface
public void picarusModelProcessStream(int id, String callback) {
Utils.eventBusPost((new CallbackRegistration(PicarusManager.class, callback)).setEvent(PicarusManager.MODEL_STREAM + id));
Utils.eventBusPost(new PicarusModelProcessStreamEvent(id));
}
@JavascriptInterface
public void picarusModelProcessWarp(int id, String callback) {
Utils.eventBusPost((new CallbackRegistration(PicarusManager.class, callback)).setEvent(PicarusManager.MODEL_WARP + id));
Utils.eventBusPost(new PicarusModelProcessWarpEvent(id));
}
private void requiresGDK() {
if (HardwareDetector.hasGDK)
return;
Utils.eventBusPost(new SendSubEvent("log", "Script requires glass"));
Utils.eventBusPost(new SayEvent("This script requires Glass"));
throw new RuntimeException("GDK not available");
}
public static enum SENSOR {
PEBBLE_ACCELEROMETER("pebbleAccelerometer", -7),
BATTERY("battery", -3),
PUPIL("pupil", -2),
GPS("gps", -1),
ACCELEROMETER("accelerometer", 1),
MAGNETIC_FIELD("magneticField", 2),
ORIENTATION("orientation", 3),
GYROSCOPE("gyroscope", 4),
LIGHT("light", 5),
GRAVITY("gravity", 9),
LINEAR_ACCELERATION("linearAcceleration", 10),
ROTATION_VECTOR("rotationVector", 11);
private final int id;
private final String name;
private SENSOR(String name, final int id) {
this.id = id;
this.name = name;
}
public int id() {
return id;
}
public String toString() {
return name;
}
}
}