com.github.hobbe.android.openkarotz.karotz.OpenKarotz.java Source code

Java tutorial

Introduction

Here is the source code for com.github.hobbe.android.openkarotz.karotz.OpenKarotz.java

Source

/*
 * OpenKarotz-Android
 * http://github.com/hobbe/OpenKarotz-Android
 *
 * Copyright (c) 2014 Olivier Bagot (http://github.com/hobbe)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * http://opensource.org/licenses/MIT
 *
 */

package com.github.hobbe.android.openkarotz.karotz;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import org.json.JSONException;
import org.json.JSONObject;

import android.graphics.Color;
import android.util.Log;

import com.github.hobbe.android.openkarotz.net.NetUtils;

/**
 * OpenKarotz implementation.
 */
public class OpenKarotz implements IKarotz {

    /**
     * Initialize a new OpenKarotz instance.
     * @param hostname the hostname or IP
     */
    public OpenKarotz(String hostname) {

        this.hostname = hostname;

        try {
            this.api = new URL(PROTOCOL + "://" + hostname + ":" + PORT);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public EarPosition[] ears(EarPosition left, EarPosition right) throws IOException {

        // Default position
        EarPosition[] newPositions = new EarPosition[] { EarPosition.POSITION_1, EarPosition.POSITION_1 };

        // Current position, if available
        if (state != null) {
            newPositions = new EarPosition[] { state.getLeftEarPosition(), state.getRightEarPosition() };
        }

        URL url = new URL(api, CGI_BIN + "/ears?noreset=1&left=" + left.toString() + "&right=" + right.toString());
        Log.d(LOG_TAG, url.toString());

        String result = NetUtils.downloadUrl(url);
        Log.d(LOG_TAG, result);

        // Answer: {"return":"0","left":"0","right":"0"}
        try {
            JSONObject json = new JSONObject(result);
            boolean ok = "0".equals(json.getString("return"));

            if (ok) {
                newPositions[0] = EarPosition.fromIntValue(Integer.valueOf(json.getString("left")).intValue());
                newPositions[1] = EarPosition.fromIntValue(Integer.valueOf(json.getString("right")).intValue());
            }
        } catch (JSONException e) {
            Log.e(LOG_TAG, "Cannot move Karotz ears: " + e.getMessage(), e);
        }

        if (state != null) {
            state.setLeftEarPosition(newPositions[0]);
            state.setRightEarPosition(newPositions[1]);
        }

        return newPositions;
    }

    @Override
    public EarMode earsMode(EarMode mode) throws IOException {
        EarMode currentMode = getEarMode();
        if (currentMode == mode) {
            // No change
            Log.d(LOG_TAG, "No change in ear mode");
            return mode;
        }

        URL url = new URL(api, CGI_BIN + "/ears_mode?disable=" + (mode.isEnabled() ? "0" : "1"));
        Log.d(LOG_TAG, url.toString());

        String result = NetUtils.downloadUrl(url);
        Log.d(LOG_TAG, result);

        // Answer: {"return":"0","disabled":"0"}
        try {
            JSONObject json = new JSONObject(result);
            boolean ok = "0".equals(json.getString("return"));

            if (ok) {
                EarMode newMode = "0".equals(json.getString("disabled")) ? EarMode.ENABLED : EarMode.DISABLED;
                state.setEarMode(newMode);
                return newMode;
            }
        } catch (JSONException e) {
            Log.e(LOG_TAG, "Cannot en/disable Karotz ears: " + e.getMessage(), e);
        }

        return currentMode;
    }

    @Override
    public EarPosition[] earsRandom() throws IOException {

        // Default position
        EarPosition[] newPositions = new EarPosition[] { EarPosition.POSITION_1, EarPosition.POSITION_1 };

        // Current position, if available
        if (state != null) {
            newPositions = new EarPosition[] { state.getLeftEarPosition(), state.getRightEarPosition() };
        }

        URL url = new URL(api, CGI_BIN + "/ears_random");
        Log.d(LOG_TAG, url.toString());

        String result = NetUtils.downloadUrl(url);
        Log.d(LOG_TAG, result);

        // Answer: {"left":"0","right":"0","return":"0"}
        // Answer: {"return":"1","msg":"Unable to perform action, rabbit is sleeping."}
        // Answer: {"return":"1","msg":"Unable to perform action, ears disabled."}
        try {
            JSONObject json = new JSONObject(result);
            boolean ok = "0".equals(json.getString("return"));

            if (ok) {
                newPositions[0] = EarPosition.fromIntValue(Integer.valueOf(json.getString("left")).intValue());
                newPositions[1] = EarPosition.fromIntValue(Integer.valueOf(json.getString("right")).intValue());
            }
        } catch (JSONException e) {
            Log.e(LOG_TAG, "Cannot put Karotz ears in random position: " + e.getMessage(), e);
        }

        if (state != null) {
            state.setLeftEarPosition(newPositions[0]);
            state.setRightEarPosition(newPositions[1]);
        }

        return newPositions;
    }

    @Override
    public void earsReset() throws IOException {
        URL url = new URL(api, CGI_BIN + "/ears_reset");
        Log.d(LOG_TAG, url.toString());

        String result = NetUtils.downloadUrl(url);
        Log.d(LOG_TAG, result);

        // Answer: {"return":"0"}
        // Answer: {"return":"1","msg":"Unable to perform action, rabbit is sleeping."}
        // Answer: {"return":"1","msg":"Unable to perform action, ears disabled."}
        try {
            JSONObject json = new JSONObject(result);
            boolean ok = "0".equals(json.getString("return"));

            if (ok) {
                if (state != null) {
                    state.setLeftEarPosition(EarPosition.POSITION_1);
                    state.setRightEarPosition(EarPosition.POSITION_1);
                }
                return;
            }
        } catch (JSONException e) {
            Log.e(LOG_TAG, "Cannot reset Karotz ears: " + e.getMessage(), e);
        }
    }

    @Override
    public int getColor() throws IOException {
        if (state == null) {
            status();
        }
        return state.getLedColor();
    }

    @Override
    public EarMode getEarMode() throws IOException {
        if (isOffline()) {
            // Re-check state
            status();
        }
        return state.getEarMode();
    }

    @Override
    public EarPosition[] getEarPositions() throws IOException {
        if (isOffline()) {
            // Re-check state
            status();
        }

        // Default position
        EarPosition[] positions = new EarPosition[] { EarPosition.POSITION_1, EarPosition.POSITION_1 };

        if (state != null) {
            positions = new EarPosition[] { state.getLeftEarPosition(), state.getRightEarPosition() };
        }

        return positions;
    }

    @Override
    public String getHostname() {
        return hostname;
    }

    @Override
    public KarotzStatus getStatus() throws IOException {
        if (isOffline()) {
            // Re-check state
            status();
        }
        return state.getStatus();
    }

    @Override
    public String getVersion() throws IOException {
        if (isOffline()) {
            // Re-check state
            status();
        }
        return state.getVersion();
    }

    @Override
    public boolean isPulsing() throws IOException {
        if (isOffline()) {
            // Re-check state
            status();
        }
        return state.isPulsing();
    }

    @Override
    public void led(int color, boolean pulse) throws IOException {
        int rgb = color & 0x00FFFFFF;

        if (pulse == state.isPulsing() && rgb == state.getLedColor()) {
            // No change
            return;
        }

        String c = toColorCode(rgb);

        URL url = new URL(api, CGI_BIN + "/leds?color=" + c + (pulse ? "&pulse=1" : ""));
        Log.d(LOG_TAG, url.toString());

        String result = NetUtils.downloadUrl(url);
        Log.d(LOG_TAG, result);

        // Answer: {"color":"0000FF","secondary_color":"000000","pulse":"0","no_memory":"0","speed":"700","return":"0"}
        // Answer: {"return":"1","msg":"Unable to perform action, rabbit is sleeping."}
        try {
            JSONObject json = new JSONObject(result);
            boolean ok = "0".equals(json.getString("return"));

            if (ok) {
                state.setLedColor(Color.parseColor("#" + json.getString("color")));
                state.setPulsing("1".equals(json.getString("pulse")));
                return;
            }
        } catch (JSONException e) {
            Log.e(LOG_TAG, "Cannot change LED on Karotz: " + e.getMessage(), e);
        }

        // Not OK, set back to previous values
        state.setLedColor(rgb);
        state.setPulsing(pulse);
    }

    @Override
    public boolean sleep() throws IOException {
        if (isSleeping()) {
            // No change
            Log.d(LOG_TAG, "Already sleeping, no need to go to sleep");
            return true;
        }

        URL url = new URL(api, CGI_BIN + "/sleep");
        Log.d(LOG_TAG, url.toString());

        String result = NetUtils.downloadUrl(url);
        Log.d(LOG_TAG, result);

        // Answer: {"return":"0"}
        // Answer: {"return":"1","msg":"Unable to perform action, rabbit is already sleeping."}
        try {
            JSONObject json = new JSONObject(result);
            state.setStatus("0".equals(json.getString("return")) ? KarotzStatus.SLEEPING : KarotzStatus.AWAKE);
            return true;
        } catch (JSONException e) {
            state.setStatus(KarotzStatus.UNKNOWN);
            return false;
        }

    }

    @Override
    public boolean sound(String soundUrl) throws IOException {
        if (soundUrl == null || soundUrl.length() <= 0) {
            return true;
        }

        URL url = new URL(api, CGI_BIN + "/sound?url=" + soundUrl);
        Log.d(LOG_TAG, url.toString());

        String result = NetUtils.downloadUrl(url);
        Log.d(LOG_TAG, result);

        // Answer: {"return":"0"}
        // Answer: {"return":"1","msg":"Unable to perform action, rabbit is sleeping."}
        try {
            JSONObject json = new JSONObject(result);
            boolean ok = "0".equals(json.getString("return"));

            if (ok) {
                Log.i(LOG_TAG, "Karotz is playing sound");
                return true;
            }
            Log.e(LOG_TAG, "Karotz cannot play the sound");
        } catch (JSONException e) {
            Log.e(LOG_TAG, "Cannot make Karotz play a sound: " + e.getMessage(), e);
        }

        return false;
    }

    @Override
    public boolean soundControl(SoundControlCommand command) throws IOException {
        URL url = new URL(api, CGI_BIN + "/sound_control?cmd=" + command.toString());
        Log.d(LOG_TAG, url.toString());

        String result = NetUtils.downloadUrl(url);
        Log.d(LOG_TAG, result);

        // Answer: {"return":"0"}
        // Answer: {"return":"1","msg":"No sound currently playing."}
        // Answer: {"return":"1","msg":"Unable to perform action, rabbit is already sleeping."}
        try {
            JSONObject json = new JSONObject(result);
            return ("0".equals(json.getString("return")));
        } catch (JSONException e) {
            Log.e(LOG_TAG, "Cannot call sound control on Karotz: " + e.getMessage(), e);
        }

        return false;
    }

    @Override
    public boolean wakeup(boolean silent) throws IOException {
        if (isAwake()) {
            // No change
            Log.d(LOG_TAG, "Already awake, no need to wake up");
            return true;
        }

        URL url = new URL(api, CGI_BIN + "/wakeup" + (silent ? "?silent=1" : ""));
        Log.d(LOG_TAG, url.toString());

        String result = NetUtils.downloadUrl(url);
        Log.d(LOG_TAG, result);

        // Answer: {"return":"0","silent":"1"}
        try {
            JSONObject json = new JSONObject(result);
            state.setStatus("0".equals(json.getString("return")) ? KarotzStatus.AWAKE : KarotzStatus.UNKNOWN);
        } catch (JSONException e) {
            state.setStatus(KarotzStatus.UNKNOWN);
        }

        return (state.getStatus() == KarotzStatus.AWAKE);
    }

    private boolean isAwake() {
        return (state != null && state.getStatus() == KarotzStatus.AWAKE);
    }

    private boolean isOffline() {
        return (state == null || state.getStatus().isOffline());
    }

    private boolean isSleeping() {
        return (state != null && state.getStatus() == KarotzStatus.SLEEPING);
    }

    private void status() throws IOException {
        URL url = new URL(api, CGI_BIN + "/status");
        Log.d(LOG_TAG, url.toString());

        String result = NetUtils.downloadUrl(url);
        Log.d(LOG_TAG, result);

        state = new OpenKarotzState(result);
        Log.d(LOG_TAG, state.toString());
    }

    private static String toColorCode(int c) {
        String cc = Integer.toHexString(c);
        while (cc.length() < 6) {
            cc = '0' + cc;
        }
        return cc;
    }

    private final String hostname;

    private URL api = null;

    private OpenKarotzState state = null;

    private static final String PROTOCOL = "http";

    private static final String CGI_BIN = "/cgi-bin";

    private static final int PORT = 80;

    private static final String LOG_TAG = OpenKarotz.class.getSimpleName();
}