vrijdag 11 oktober 2013

Philips Hue gets Groovy

My first Groovy script when figuring out how to use the Philips Hue lights.
Details on the Philips Hue Api can be found here.


import groovyx.net.http.*
@Grab(group='org.codehaus.groovy.modules.http-builder',
    module='http-builder', version='0.5.2' )


class HueLamp {
int id 

HueLamp(int id = 1) {
this.id = id
}

def status(boolean on, int hue) {
def base = "http://192.168.2.32/"
def api = "api/newdeveloper/lights/$id/state"
def url = base + api

def http = new HTTPBuilder( url)
http.request( Method.PUT, ContentType.JSON ) { req ->
           body = ["on" : on, "transitiontime" : 1,
                      "hue" : hue, "sat" : 255, "bri" : 255 ]
           response.success = { resp, json ->
println json
           }

           response.failure = { resp ->
println resp
           }
}
}
}

Details on how to use the Groovy Http builder are found here
The status method updates the lamp hue. Below an example of looping over different colors:

def hueMax = 65535
def stepSize = (int)hueMax/nrSteps

def hues = (0..25).collect{ it*stepSize }

def lamp = new HueLamp(1)

hues.each{ hue ->
lamp.status(true, hue)
Thread.sleep(100)
}

Interested an need more code? Check out this java/groovy project on Github from Stephan Jaetzold.

Enjoy. 

woensdag 17 juli 2013

RoboLectric with Gradle and Android Studio

Below you will find a small log of trying to run Robolectric on Android studio using the gradle build.

Used sources:
[1] build.gradle file: http://stackoverflow.com/questions/16649397/robolectric-with-gradle-resources-not-found?rq=1
[2] Add jars to Android Studio: http://stackoverflow.com/questions/16881936/android-studio-missing-external-dependencies

Adapting the build.gradle file according to this link on stackoverflow. build.gradle:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.5.+'
    }
}

repositories {
    mavenCentral()
    maven {
        url 'https://oss.sonatype.org/content/repositories/snapshots/'
    }
}

apply plugin: 'android'

android {
    compileSdkVersion 17
    buildToolsVersion "17.0.0"

    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 16
    }
}

sourceSets {
    testLocal {
        java.srcDir file('src/test/java')
        resources.srcDir file('src/test/resources')
    }
}

dependencies {
    compile 'org.roboguice:roboguice:2.0'
    compile 'com.google.android:support-v4:r6'


    testLocalCompile 'junit:junit:4.8.2'
    testLocalCompile 'org.robolectric:robolectric:2.1'
    testLocalCompile 'com.google.android:android:4.0.1.2'
    testLocalCompile 'com.google.android:support-v4:r6'
    testLocalCompile 'org.roboguice:roboguice:2.0'
}

task localTest(type: Test, dependsOn: assemble) {
    testClassesDir = sourceSets.testLocal.output.classesDir

    android.sourceSets.main.java.srcDirs.each { dir ->
        def buildDir = dir.getAbsolutePath().split('/')
        buildDir =  (buildDir[0..(buildDir.length - 4)] + ['build', 'classes', 'debug']).join('/')

        sourceSets.testLocal.compileClasspath += files(buildDir)
        sourceSets.testLocal.runtimeClasspath += files(buildDir)
    }

    classpath = sourceSets.testLocal.runtimeClasspath
}

check.dependsOn localTest


This results in a working build using this DummyTest class in src/test/java/...

package org.fhict.calculator.rtest;

import junit.framework.Assert;

import roboguice.test.RobolectricRoboTestRunner;

import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

import org.junit.runner.RunWith;
import org.junit.Before;
import org.junit.Test;

import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;


@RunWith(RobolectricTestRunner.class)
public class DummyTest {

    @Before
    public void setUp() {
    }

    @Test
    public void testSomeNumber() {
        Assert.assertEquals(true,true);
    }

}

From command line a build is now running ('gradle localTest' from terminal). Generating a test-report in file:///home/ben/AndroidStudioProjects/CalculatorProject/Calculator/build/reports/tests/org.fhict.calculator.rtest.DummyTest.html




AndroidStudio does not yet recognize the new jar files as defined by testLocalCompile in build.gradle. Manually add them to AndroidStudio using this link.



Remaining open issues:

(1) How to show the output of the Robolectric unit tests in AndroidStudio?
(2) How to force recompile when the RoboLectric unit test has been changed? Now only a gradle clean && gradle localTest. Not so nice...

Please comment if you know how to solve these?

donderdag 11 juli 2013

Android-Studio keyboard shortcuts

Some basic Android-Studio keyboard links:

Shortcut: Meaning:
SHIFT + SPACEAuto completion
ALT + TABShow automatic fix options
CTRL + QShow documentation
CTRL + BGo to declaration of class
SHIFT + F6Go to declaration of class
CTRL + OOverride method
CTRL + IImplement interface
CTRL + ALT + IAuto indent
CTLR + NOpen class
CTLR + SHIFT + NOpen file
CTLR + EOpen recent files
CTLR + WSelect word
CTLR + F4Close file
CTLR + /Put in comment
CTLR + SHIFT + /Uncomment

woensdag 30 maart 2011

Android testing of Activities: first experiments.

Below an initial example of Activity testcase in Android. A first experiment after reading the android development page on Activity Testing.

The GuessPictureActivity is connected to a simple screen containing a TextView and ImageView. When the image is 'Clicked' a name will be displayed. On the next click a new photo will be loaded.



The activity under test is:
package com.ben.android.xmlweb;

import java.util.HashMap;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.TextView;

public class GuessPictureActivity extends Activity {
   
    private TextView textFaceName;
    private ImageView imageView;
    private HashMap<String,Integer> drawingsByName;
    private int counter;
    static final String LOGID = "FaceMemory";
    private String names[];
    private Boolean guessed;
               
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        drawingsByName = new HashMap<String, Integer>();               
        drawingsByName.put("Pip", new Integer(R.drawable.pip));
        drawingsByName.put("The Stig", new Integer(R.drawable.stig));
        drawingsByName.put("Tux",new Integer(R.drawable.tux));
        names = new String[drawingsByName.size()];
        drawingsByName.keySet().toArray(names);
        counter = 0;
        guessed = false;
               
        textFaceName = (TextView)findViewById(R.id.textFaceName);       
        imageView= (ImageView)findViewById(R.id.imageView);
       
        imageView.setOnClickListener( new OnClickListener() {
            @Override
            public void onClick(View v) {   
                if(!guessed) {
                    textFaceName.setText(names[counter]);
                    guessed = true;
                } else {
                    counter++;
                    if(counter>=names.length) counter = 0;
                    imageView.setImageResource(drawingsByName.get(names[counter]));
                    textFaceName.setText(R.string.textGuessName);
                    guessed = false;
                }                           
            }
        });
    }
}


The activity test case looks like: 
package com.ben.android.xmlweb.test;

import com.ben.android.xmlweb.GuessPictureActivity;

import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.widget.ImageView;
import android.widget.TextView;

public class GuessPictureActivityTest extends ActivityInstrumentationTestCase2<GuessPictureActivity> {
    private GuessPictureActivity activity;
    private ImageView imageView;
    private TextView textView;
    private String guessWhoString;
   
           
    public GuessPictureActivityTest() {
        super("com.ben.android.xmlweb.XmlGetter", GuessPictureActivity.class);
    }
   
    @Override
    protected void setUp() throws Exception {       
        super.setUp();
       
        activity = getActivity();
        imageView = (ImageView)getActivity().findViewById(com.ben.android.xmlweb.R.id.imageView);
        textView = (TextView)getActivity().findViewById(com.ben.android.xmlweb.R.id.textFaceName);
        guessWhoString = activity.getResources().getString(com.ben.android.xmlweb.R.string.textGuessName);
    }
   
    @Override
    protected void tearDown() throws Exception {
        super.tearDown();
    }

    @UiThreadTest
    public void testAfterStartAQuestionIsAsked() {
        assertNotNull(imageView);
        assertNotNull(textView);
        assertEquals(guessWhoString,textView.getText());
    }   
   
    public void testOnClickTheNameOfPipIsDisplayed() throws InterruptedException{
        Drawable initialDrawable = imageView.getDrawable();
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                imageView.performClick();
            }
        });
       
        getInstrumentation().waitForIdleSync();               
        String expectedText = "Pip";       
        assertEquals(expectedText,textView.getText());
        assertSame(initialDrawable, imageView.getDrawable());   
    }
   
    public void testOnTwoClicksADifferentImageIsDisplayed() {
        Drawable initialDrawable = imageView.getDrawable();
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                imageView.performClick();
                imageView.performClick();
            }
        });
       
        getInstrumentation().waitForIdleSync();               
        assertEquals(guessWhoString,textView.getText());
        assertNotSame(initialDrawable, imageView.getDrawable());
    }
}

If you like to see more, please drop a comment.