Java tutorial
/** * Copyright 2014 Matthew Congrove * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.mcongrove.pebble; import org.appcelerator.kroll.KrollDict; import org.appcelerator.kroll.KrollFunction; import org.appcelerator.kroll.KrollModule; import org.appcelerator.kroll.KrollProxy; import org.appcelerator.kroll.KrollProxyListener; import org.appcelerator.kroll.annotations.Kroll; import org.appcelerator.kroll.common.Log; import org.appcelerator.kroll.common.TiConfig; import org.appcelerator.titanium.TiApplication; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.UUID; import org.json.JSONArray; import org.json.JSONObject; import com.getpebble.android.kit.PebbleKit; import com.getpebble.android.kit.util.PebbleDictionary; @Kroll.module(name = "TitaniumPebble", id = "com.mcongrove.pebble") public class TitaniumPebbleModule extends KrollModule { private static final String LCAT = "Pebble"; private static UUID uuid; private int connectedCount = 0; private boolean isListeningToPebble = false; private static HashMap<Integer, HashMap<String, KrollFunction>> callbacks = new HashMap<Integer, HashMap<String, KrollFunction>>(); private static Integer transactionCounter = 0; private BroadcastReceiver connectedReceiver = null; private BroadcastReceiver disconnectedReceiver = null; private PebbleKit.PebbleDataReceiver dataReceiver = null; private PebbleKit.PebbleAckReceiver ackReceiver = null; private PebbleKit.PebbleNackReceiver nackReceiver = null; public TitaniumPebbleModule() { super(); } public TiApplication getApplicationContext() { return TiApplication.getInstance(); } // Lifecycle Events @Kroll.onAppCreate public static void onAppCreate(TiApplication app) { } @Override public void onPause(Activity activity) { super.onPause(activity); if (connectedReceiver != null) { getApplicationContext().unregisterReceiver(connectedReceiver); connectedReceiver = null; } if (disconnectedReceiver != null) { getApplicationContext().unregisterReceiver(disconnectedReceiver); disconnectedReceiver = null; } if (dataReceiver != null) { getApplicationContext().unregisterReceiver(dataReceiver); dataReceiver = null; } if (ackReceiver != null) { getApplicationContext().unregisterReceiver(ackReceiver); ackReceiver = null; } if (nackReceiver != null) { getApplicationContext().unregisterReceiver(nackReceiver); nackReceiver = null; } } @Override public void onResume(Activity activity) { super.onResume(activity); if (isListeningToPebble) { addReceivers(); } } @Override public void onDestroy(Activity activity) { super.onDestroy(activity); } // Methods @Kroll.method private void listenToConnectedWatch() { Log.d(LCAT, "listenToConnectedWatch: Listening"); if (!checkWatchConnected()) { Log.w(LCAT, "listenToConnectedWatch: No watch connected"); return; } if (!isListeningToPebble) { isListeningToPebble = true; } addReceivers(); } @Kroll.method private void addReceivers() { if (isListeningToPebble) { if (connectedReceiver == null) { connectedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d(LCAT, "watchDidConnect"); setConnectedCount(0); fireEvent("watchConnected", new Object[] {}); } }; PebbleKit.registerPebbleConnectedReceiver(getApplicationContext(), connectedReceiver); } if (disconnectedReceiver == null) { disconnectedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.d(LCAT, "watchDidDisconnect"); setConnectedCount(0); fireEvent("watchDisconnected", new Object[] {}); } }; PebbleKit.registerPebbleDisconnectedReceiver(getApplicationContext(), disconnectedReceiver); } if (dataReceiver == null) { dataReceiver = new PebbleKit.PebbleDataReceiver(uuid) { @Override public void receiveData(final Context context, final int transactionId, final PebbleDictionary data) { if (!data.contains(0)) { Log.e(LCAT, "listenToConnectedWatch: Received message, data corrupt"); PebbleKit.sendNackToPebble(context, transactionId); return; } PebbleKit.sendAckToPebble(context, transactionId); try { JSONArray jsonArray = new JSONArray(data.toJsonString()); if (jsonArray.length() > 0) { JSONObject jsonObject = jsonArray.getJSONObject(0); if (jsonObject.has("value")) { Log.i(LCAT, "listenToConnectedWatch: Received message"); HashMap message = new HashMap(); message.put("message", jsonObject.getString("value")); fireEvent("update", message); } } } catch (Throwable e) { Log.e(LCAT, "listenToConnectedWatch: Received message, data corrupt"); } } }; PebbleKit.registerReceivedDataHandler(getApplicationContext(), dataReceiver); } if (ackReceiver == null) { ackReceiver = new PebbleKit.PebbleAckReceiver(uuid) { @Override public void receiveAck(Context context, int transactionId) { Log.i(LCAT, "Received ACK for transaction: " + transactionId); if (callbacks.containsKey(transactionId)) { HashMap callbackArray = (HashMap) callbacks.get(transactionId); if (callbackArray.containsKey("success")) { KrollFunction successCallback = (KrollFunction) callbackArray.get("success"); successCallback.call(getKrollObject(), new Object[] {}); } } } }; PebbleKit.registerReceivedAckHandler(getApplicationContext(), ackReceiver); } if (nackReceiver == null) { nackReceiver = new PebbleKit.PebbleNackReceiver(uuid) { @Override public void receiveNack(Context context, int transactionId) { Log.e(LCAT, "Received NACK for transaction: " + transactionId); if (callbacks.containsKey(transactionId)) { HashMap callbackArray = (HashMap) callbacks.get(transactionId); if (callbackArray.containsKey("error")) { KrollFunction errorCallback = (KrollFunction) callbackArray.get("error"); errorCallback.call(getKrollObject(), new Object[] {}); } } } }; PebbleKit.registerReceivedNackHandler(getApplicationContext(), nackReceiver); } } } @Kroll.method public void setAppUUID(String uuidString) { uuid = UUID.fromString(uuidString); } @Kroll.method public boolean checkWatchConnected() { try { boolean connected = PebbleKit.isWatchConnected(getApplicationContext()); if (!connected) { Log.w(LCAT, "checkWatchConnected: No watch connected"); } return connected; } catch (SecurityException e) { return false; } } @Kroll.getProperty @Kroll.method public int getConnectedCount() { return connectedCount; } @Kroll.setProperty @Kroll.method public void setConnectedCount(int ignore) { if (checkWatchConnected()) { connectedCount = 1; } else { connectedCount = 0; } } @Kroll.method public void connect(HashMap args) { Log.d(LCAT, "connect"); final KrollFunction successCallback = (KrollFunction) args.get("success"); final KrollFunction errorCallback = (KrollFunction) args.get("error"); if (!PebbleKit.areAppMessagesSupported(getApplicationContext())) { Log.e(LCAT, "connect: Watch does not support messages"); if (errorCallback != null) { errorCallback.call(getKrollObject(), new Object[] {}); } return; } setConnectedCount(0); listenToConnectedWatch(); Log.d(LCAT, "connect: Messages supported"); if (successCallback != null) { successCallback.call(getKrollObject(), new Object[] {}); } } @Kroll.method public void getVersionInfo(HashMap args) { Log.d(LCAT, "getVersionInfo"); final KrollFunction successCallback = (KrollFunction) args.get("success"); final KrollFunction errorCallback = (KrollFunction) args.get("error"); int majorVersion; int minorVersion; try { PebbleKit.FirmwareVersionInfo versionInfo = PebbleKit.getWatchFWVersion(getApplicationContext()); majorVersion = versionInfo.getMajor(); minorVersion = versionInfo.getMinor(); } catch (Exception e) { Log.w(LCAT, "Could not retrieve version info from Pebble"); HashMap event = new HashMap(); event.put("message", "Could not retrieve version info from Pebble"); errorCallback.call(getKrollObject(), event); return; } Log.d(LCAT, "Pebble FW Major " + majorVersion); Log.d(LCAT, "Pebble FW Minor " + minorVersion); if (successCallback != null) { HashMap versionInfoHash = new HashMap(); versionInfoHash.put("major", majorVersion); versionInfoHash.put("minor", minorVersion); successCallback.call(getKrollObject(), versionInfoHash); } } @Kroll.method public void launchApp(HashMap args) { Log.d(LCAT, "launchApp"); if (!checkWatchConnected()) { Log.w(LCAT, "launchApp: No watch connected"); return; } final KrollFunction successCallback = (KrollFunction) args.get("success"); final KrollFunction errorCallback = (KrollFunction) args.get("error"); try { PebbleKit.startAppOnPebble(getApplicationContext(), uuid); setConnectedCount(0); listenToConnectedWatch(); Log.d(LCAT, "launchApp: Success"); if (successCallback != null) { HashMap event = new HashMap(); event.put("message", "Successfully launched app"); successCallback.call(getKrollObject(), event); } } catch (IllegalArgumentException e) { Log.e(LCAT, "launchApp: Error"); if (errorCallback != null) { errorCallback.call(getKrollObject(), new Object[] {}); } return; } } @Kroll.method public void killApp(HashMap args) { Log.d(LCAT, "killApp"); if (!checkWatchConnected()) { Log.w(LCAT, "killApp: No watch connected"); return; } final KrollFunction successCallback = (KrollFunction) args.get("success"); final KrollFunction errorCallback = (KrollFunction) args.get("error"); try { PebbleKit.closeAppOnPebble(getApplicationContext(), uuid); Log.d(LCAT, "killApp: Success"); if (successCallback != null) { HashMap event = new HashMap(); event.put("message", "Successfully killed app"); successCallback.call(getKrollObject(), event); } } catch (IllegalArgumentException e) { Log.e(LCAT, "killApp: Error"); if (errorCallback != null) { errorCallback.call(getKrollObject(), new Object[] {}); } return; } } @Kroll.method public void sendMessage(HashMap args) { Log.d(LCAT, "sendMessage"); if (!checkWatchConnected()) { Log.w(LCAT, "sendMessage: No watch connected"); return; } final KrollFunction successCallback = (KrollFunction) args.get("success"); final KrollFunction errorCallback = (KrollFunction) args.get("error"); final Object message = args.get("message"); Map<Integer, Object> messageHash = (HashMap<Integer, Object>) message; Iterator<Map.Entry<Integer, Object>> entries = messageHash.entrySet().iterator(); HashMap<String, KrollFunction> callbackArray = new HashMap<String, KrollFunction>(); PebbleDictionary data = new PebbleDictionary(); if (successCallback != null) { callbackArray.put("success", successCallback); } if (errorCallback != null) { callbackArray.put("error", errorCallback); } callbacks.put(transactionCounter, callbackArray); while (entries.hasNext()) { Map.Entry<Integer, Object> entry = entries.next(); if (entry.getValue() instanceof Integer) { data.addInt32((Integer) entry.getKey(), (Integer) entry.getValue()); } else if (entry.getValue() instanceof String) { data.addString((Integer) entry.getKey(), (String) entry.getValue()); } } PebbleKit.sendDataToPebbleWithTransactionId(getApplicationContext(), uuid, data, transactionCounter); transactionCounter++; } }