Example Android Application (POST/GET)

Hitchhikers Guide to the Android Universe

Dear Sparksters, and anyone interested in building your own Android application. Since I had the problem that I have not that much knowledge about Java/Android/JSON it was a hard trial-n-error process for myself. With this tutorial/example I would like to make your way a bit easier than mine was. Hope you like it, feel free to test it and report errors to this thread. I will update it asap.

1. The Spark Core Code
Fire up your browser and point it to the Spark Cloud IDE and “Create a new app” there. Name it as you like.

include "application.h"
    
    void setup(){
    }
    
    void loop(){
    		char foo[64];
    		unsigned bar = "Metasyntactic Variable";
    		sprintf(foo, "{\"Foobar:  \"}", bar);
    		Spark.publish("baz",foo);
    }

In simple terms we put “{\”Foobar: \” \”Metasyntactic Variable”\ } into foo and send it to the spark-cloud api. At a closer look we use sprintf to compose a text string into a C variable:
Spark.publish() is used to send the data to the Spark Cloud via the API. There is a very good tutorial out there written by @bko It is highly recommended that you first try this one it is HTML based with JavaScript. It helped me a lot to get this to work.

Sadly we are not finished yet, we need a little bit more for this to run. We need to add the post example, and a little bit of cleaning up our code.

  /*
 * _________        .__
 * \_   ___ \_______|__| _____   __________   ____
 * /    \  \/\_  __ \  |/     \ /  ___/  _ \ /    \
 * \     \____|  | \/  |  | |  \\___ (  <_> )   |  \
 *  \______  /|__|  |__|__|_|  /____  >____/|___|  /
 *         \/                \/     \/           \/
 * Project: CrimsonCTRL
 * Spark Core
 *
 * Author : CrimsonClyde
 * E-Mail : clyde_at_darkpack.net
 * Use at your own risk!
 */

void setup(){
	// Register the post function
    Spark.function("POST", postExample); 
    // Pin setup
    pinMode(D7, OUTPUT);
    digitalWrite(D7, LOW);
}
    
void loop(){
		getExample();
		delay(2000);
}
    
// Hitchikers Guide to Android Universe - GET function example
void getExample(void) {
	char foo[64];
	char bar[] = "Metasyntactic Variable";
	sprintf(foo, "{\"Foobar:  %s\"}", bar);
	Spark.publish("baz",foo);
}
    
    
// Hitchikers Guide to Android Universe - POST function example
int postExample(String command)    {
    int state = 0;
       
    //find out the pin number and convert the ascii to integer
     int pinNumber = (command.charAt(1) - '0') - 1;
     //Sanity check to see if the pin numbers are within limits
     if (pinNumber != 7 ) return -1;
     // find out the state of the led
    
     if(command.substring(7,7) == "HIGH") state = 1;
     else if(command.substring(7,6) == "LOW") state = 0;
     else return -1;
    
    // write to the appropriate pin
    digitalWrite(D7, state);
         
    return 1;
}

Woah that is much code! Keep calm, this seems to be more than it is right now. First I have created a function for the GET example to keep the main loop clean. Second I have added the function for the POST example. With that one we are able to set a Pin to HIGH or to LOW based on what we send with our application. Note the sanity check? I use PIN d7 in this example because of the build in LED into the Spark Core. If you need more than one PIN than you can use something like if (pinNumber <2 || pinNumber > 4) { … }.

Test? Of course we should test if everything works.
First Test check if our Function “POST” is registered correctly. Point your Browser to https://api.spark.io/v1/devices/YOURCOREID/?access_token=YOURACCESSTOKEN and you see something like this as output:

    // 20150114121812
    // https://api.spark.io/v1/devices/YOURCOREID/?access_token=YOURACCESSTOKEN
    
    {
      "id": "YOURCOREID",
      "name": "YOURCORENAME",
      "connected": true,
      "variables": {
        
      },
      "functions": [
        "POST"
      ],
      "cc3000_patch_version": "1.29"
    }

YES, we get closer, now if you are lucky and use a Unix, Linux or OSX as your operating system simple open up a terminal and use curl.

    curl https://api.spark.io/v1/devices/<<CoreID>>/ -d access_token=<<accessToken>> -d params=d3,LOW

This should set your PIN d7 to HIGH and the build in LED (blue) should now light up. If you have Windows you can use Chrome Extension such as DHC Rest Client.

Request: HTTPS://api.spark.io/v1/devices/COREID/POST/
Headers: (form) Content-Type: application/x-www-form-urlencoded
Body: (form)access_token(text)YOURACCESSTOKEN
Body: (form)params(text)d7,HIGH

Woohoooo we have now set up the basic requirements. Thumbs up!

2. IDE
I build my project with Android Studio 1.0.2, it is now stable and the recommended tool for building Android Apps. If you want to use Eclipse feel free, the code should work in both IDEs.

3. New Project
Configure your new project: Application Name: AndroidUniverse, Company Domain: to.guide.hitchhikers
Select the form factors: Phone and Tablet Minimum SDK 21 (since I use Lollipop with Material Design, if you want to use lower SDK Version you have to change the Theme in style.xml)
Add an activity to Mobile: Blank Activity
Choose options for your new file: Activity Name: MainActivity, Layout Name: activity_main, Title: MainActivity, Menu Ressource Name: menu_main

4. Permissions (AndroidManifest.xml)
Since we want to connect to the spark-cloud our application needs the permission to access the internet. Open up the AndroidManifest.xml file located under app->manifests-AndroidManifest.xml.
Replace the content with this one:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="hitchikers.guide.to.androiduniverse" >
    
        // Permission to get the values from spark-cloud
        <uses-permission android:name="android.permission.INTERNET" />
    
        <application
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name=".MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
  1. Layout (activity_main.xml)
    We need a layout with a TextView we can update with our example and a button to submit our parameters and switch on our LED. The Layout is located under app->res->layout->activity_layout.xml – same as before, open it and replace the complete content with this one:
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
                    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
                    android:paddingRight="@dimen/activity_horizontal_margin"
                    android:paddingTop="@dimen/activity_vertical_margin"
                    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="MyCoreApp"
            android:id="@+id/headerTextView"
            android:textSize="30sp"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Wait... foobar you said?"
            android:id="@+id/getTextView"
            android:textSize="24sp"
            android:layout_marginTop="123dp"
            android:layout_below="@+id/headerTextView"
            android:layout_centerHorizontal="true"
            android:focusableInTouchMode="true"/>
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Get Example"
            android:id="@+id/getButton"
            android:layout_below="@+id/getTextView"
            android:layout_centerHorizontal="true"/>
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="POST EXAMPLE"
            android:id="@+id/button"
            android:layout_alignParentBottom="true"
            android:layout_alignEnd="@+id/getButton"/>
    
    </RelativeLayout>

We have a TextView with default content “Wait….foobar you said?”
We have a button which we will later use for get content and update the TextView.
Last not least a button for the post example which when tapped should post a request to set the PIN d7 to HIGH and the Core built-in app should light on.

6. Data Class (data.java)
Right-click in the left panel “app” and choose New -> Java Class. Name it “data.java”. Open it and replace the content with this:

    package hitchikers.guide.to.androiduniverse;
    public class Data {
         private String foobar = null;
    
         public boolean isReady() {
         return (foobar != null);
         }
    
         public Integer getFoobar() { return foobar; }
    
         public void setFoobar(Integer foobar) { this.foobar = foobar; }
    
         @Override
         public String toString() {
         return "Data [Foobar=" + foobar + "]";
         }
        } 

7. Remove the ActionBar (styles.xml)
We do not need the ActionBar for our project, open up app->res->values->styles.xml and replace the content with this:

    <resources>
     <!-- Base application theme. -->
     <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
     <!-- Customize your theme here. -->
     </style>
    </resources>

8. Main Activity (MainActivity.class)
This is our master file, it is a bit messy I know but it can show you how the post and get commands differ from each other. You have a lot of log and toast messages all around which you can safely remove but they can come in quite handy. Don´t forget to enter your AccessToken and CoreID on lines: 52,172 and 173!

    package hitchikers.guide.to.androiduniverse;
    
    /**
     * _________        .__
     * \_   ___ \_______|__| _____   __________   ____
     * /    \  \/\_  __ \  |/     \ /  ___/  _ \ /    \
     * \     \____|  | \/  |  | |  \\___ (  <_> )   |  \
     *  \______  /|__|  |__|__|_|  /____  >____/|___|  /
     *         \/                \/     \/           \/
     * Project: CrimsonCTRL
     * File: ControlActivity.java
     *
     * The Hitchikers Guide to Android Universe
     * Example GET/POST tutorial for the Spark Core.
     * See https://spark.io
     *
     * Author: CrimsonClyde
     * Do this at your own risk, do not give your CoreID
     * nor your AccessToken to anyone!
     *
     * Line 61 enter your CoreID & AccessToken
     * Line 173 + 174 enter your CoreID & AccessToken
     * Retrieve it from https://spark.io/build
     */
    
    import android.app.Activity;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    import android.widget.Toast;
    import org.json.JSONObject;
    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.URL;
    import javax.net.ssl.HttpsURLConnection;
    
    
    public class MainActivity extends Activity {
        // Set actvity name as debug tag
        public static final String TAG = HttpsClient.class.getSimpleName();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // Declare and assign our buttons and text
            final Button getButton = (Button) findViewById(R.id.getButton);
            final Button postButton = (Button) findViewById(R.id.postButton);
    
            View.OnClickListener getListener = new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // Update the <> with your CoreID and your AccessToken from https://build.spark.io
                    Toast.makeText(MainActivity.this, "GET baz", Toast.LENGTH_SHORT).show();
                    new HttpsClient().execute("https://api.spark.io/v1/devices/YOURCOREID/events/?access_token=YOURACCESSTOKEN");
                }
            };
            getButton.setOnClickListener(getListener);
    
            View.OnClickListener postListener = new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // Post d7,HIGH to spark core
                    Toast.makeText(MainActivity.this, "POST d7,HIGH", Toast.LENGTH_SHORT).show();
                    new PostClient().execute("HIGH");
                }
            };
            postButton.setOnClickListener(postListener);
    
    
        }
    
    
        /*
         * GET EXAMPLE
         */
        class HttpsClient extends AsyncTask<String, Void, String> {
            private Exception exception;
            public String doInBackground(String... urls) {
    
                try {
                    Log.d(TAG, "*******************    Open Connection    *****************************");
                    URL url = new URL(urls[0]);
                    Log.d(TAG, "Received URL:  " + url);
    
                    HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
                    Log.d(TAG, "Con Status: " + con);
    
                    InputStream in = con.getInputStream();
                    Log.d(TAG, "GetInputStream:  " + in);
    
                    Log.d(TAG, "*******************    String Builder     *****************************");
                    String line = null;
    
                    BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
    
                    Data data = new Data();
    
                    while ((line = br.readLine()) != null) {
                        if (line.contains("event")) {
                            //do nothing since the event tag is of no interest
                            Log.d(TAG, "Failed fetching needed values.");
                            return null;
                        }
                        if (line.contains("data: ")) {
                            //convert to JSON (stripping the beginning "data: "
                            JSONObject jObject = new JSONObject(line.substring(6));
                            String json_data = (String) jObject.get("data");
                            //convert again
                            jObject = new JSONObject(json_data);
    
                            //reading photocell
                            if (jObject.has("baz")) {
                                data.setBaz(jObject.getString("baz"));
                            }
    
                        }
                        //check if we have all needed data
                        if (data.isReady()) {
                            //exit endless connection
                            Log.d(TAG, "*******************    Data received    *****************************");
                            Log.d(TAG, "data:  " + data);
                            break;
                        }
                    }
    
                    // Creation of finalized containers for UI usage
                    final String gBaz = data.getBaz();
                    // To access the findViewById we need this to runOnUiThread
                    runOnUiThread(new Runnable(){
                        public void run() {
                            Log.d(TAG, "*******************    Run UI Thread     *****************************");
                            Log.d(TAG, "gFoobar:   " + gBaz);
                            // Assign and declare
                            final TextView updateGetExample  = (TextView) findViewById(R.id.getTextView);
                            // Update the TextViews
                            Log.d(TAG, "*******************    Update TextView       *************************");
                            updateGetExample.setText(gBaz);
    
                        }
    
                    });
                    // Closing the stream
                    Log.d(TAG, "*******************  Stream closed, exiting     ******************************");
                    br.close();
                } catch (Exception e) {
                    this.exception = e;
                    return null;
                }
                return null; }
    
        }
    
        /*
         * POST EXAMPLE
         */
        // We must do this as a background task, elsewhere our app crashes
        class PostClient extends AsyncTask<String, Void, String> {
            public String doInBackground(String... IO) {
    
                // Predefine variables
                String io = new String(IO[0]);
                URL url;
    
                try {
                    // Stuff variables
                    url = new URL("https://api.spark.io/v1/devices/YOURCOREID/SCL/");
                    String param = "access_token=YOURACCESSTOKEN&params=d7,"+io;
                    Log.d(TAG, "param:" + param);
    
                    // Open a connection using HttpURLConnection
                    HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
    
                    con.setReadTimeout(7000);
                    con.setConnectTimeout(7000);
                    con.setDoOutput(true);
                    con.setDoInput(true);
                    con.setInstanceFollowRedirects(false);
                    con.setRequestMethod("POST");
                    con.setFixedLengthStreamingMode(param.getBytes().length);
                    con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    
                    // Send
                    PrintWriter out = new PrintWriter(con.getOutputStream());
                    out.print(param);
                    out.close();
    
                    con.connect();
    
                    BufferedReader in = null;
                    if (con.getResponseCode() != 200) {
                        in = new BufferedReader(new InputStreamReader(con.getErrorStream()));
                        Log.d(TAG, "!=200: " + in);
                    } else {
                        in = new BufferedReader(new InputStreamReader(con.getInputStream()));
                        Log.d(TAG, "POST request send successful: " + in);
                    };
    
    
                } catch (Exception e) {
                    Log.d(TAG, "Exception");
                    e.printStackTrace();
                    return null;
                }
                // Set null and we´e good to go
                return null;
            }
        }
    }

That´s it - fire up your app! Cheers clyde

10 Likes

this is great, thanks Clyde!!!

1 Like

yw :wink:
@gusgonnet: Pls let me know if this works for you!

Unfortunately this doesn’t work for me. There are a few errors in the Spark firmware you provided.

This compiles but I didn’t get to test it:

   void setup(){
    		// Register our post function
                    Spark.function("POST", postExample); 
                    //Set up our used PIN
                    pinMode(D7, OUTPUT);
                    digitalWrite(D7, LOW);
    }
    
    void loop(){
    		getExample();
    		delay(2000);
    }
    
    // Hitchikers Guide to Android Universe - GET function example
    void getExample(void) {
    		char foo[64];
    		char bar[] = "Metasyntactic Variable";
    		sprintf(foo, "{\"Foobar:  %s\"}", bar);
    		Spark.publish("baz",foo);
    }
    
    
    // Hitchikers Guide to Android Universe - POST function example
    int postExample(String command)
    {
       int state = 0;
       
         //find out the pin number and convert the ascii to integer
         int pinNumber = (command.charAt(1) - '0') - 1;
         //Sanity check to see if the pin numbers are within limits
         if (pinNumber != 7 ) return -1;
         // find out the state of the led
    
         if(command.substring(7,7) == "HIGH") state = 1;
         else if(command.substring(7,6) == "LOW") state = 0;
         else return -1;
    
         // write to the appropriate pin
         digitalWrite(D7, state);
         
         return 1;
    }
1 Like

Made my changes based on @bkos post.
I solemnly swear to test the complete tutorial when I got my Photon :slight_smile: currently I have no hardware to do a full test run… sorry!

I am desperately trying to create a POST request to my spark core from android, but I can’t get the android app to establish the connection. I’ve also tried it using the source from the official app, but still no success.

Has anyone succeed with this?
Thanks!

Can you share your code? Maybe I can have a look at it.

@steliosk
Did that part work?

EDIT: I forgot to mention, that I used code from this tutorial that helped me a lot: How to call RESTful web services in Android.

I finally got it working with another approach. I used a third-party library for the http client (AsyncHttpClient). You have first to download this library into your libs folder and by right-clicking on them, add them as Library. So I will post my example code which worked perfectly for me, in order to help others who are trying to achieve a similar task.

Firstly, the AndroidManifest.xml file with the required INTERNET permission:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >

 // YOU NEED TO ADD ONLY THIS LINE IN YOUR MANIFEST FILE
<uses-permission android:name="android.permission.INTERNET" />


<application
    ...

The layout for the MainActivity activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <Button
        android:id="@+id/talk_to_spark"
        android:text="Talk to Spark"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="talkToSpark"/>

</RelativeLayout>

This is my main activity MainActivity.java that has the button onClick-function (talkToSpark) that starts a GET request in order to get a variable from Spark Core and a POST request to call a published function on Spark Core:

package <YOUR.PACKAGE>;


import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

import <YOURPACKAGE>.ApiFacade;
import org.json.JSONException;

public class MainActivity extends Activity {
    protected ApiFacade api;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        api = ApiFacade.getInstance(this);

        setContentView(R.layout.activity_main);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    public void talkToSpark(View view){
        try {
            // Retrieve an exposed variable from Spark Core. Currently not saving the value!
            // Only in debug logs you can see the retrieved variable value!!!
            api.getVariable("variableName"); 
            // Call a Spark Core function.
            api.callFunction("functionName","arguments"); 
        }
        catch (JSONException e){
            Log.d("MainActivity",e.toString());
        }

    }

The next one is ApiFacade.java. It handles the responses form you requests, in case of success or failure. In this particular example it doesn’t really do anything meaningful. It just shows a Toast on your screen.

package <YOUR.PACKAGE>;

import android.content.Context;
import android.util.Log;
import android.widget.Toast;

import org.apache.http.Header;
import org.json.*;
import com.loopj.android.http.*;

public class ApiFacade {
    protected Context ctx;

    public static ApiFacade getInstance(Context context) {
        ApiFacade api = new ApiFacade();
        api.ctx = context;

        return api;
    }


    public void getVariable(String variable) throws JSONException {

        RestClient.get(variable, null, new JsonHttpResponseHandler() {
            @Override
            public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
                Toast.makeText(ctx,"Success!", Toast.LENGTH_LONG).show();
            }

            @Override
            public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
        
                Toast.makeText(ctx,"Success!", Toast.LENGTH_LONG).show();
                Log.i("ApiFacade", response.toString());
               
                 // Do something with the response
            }
            // When the response returned by REST has Http response code other than '200'
            @Override
            public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
                // Hide Progress Dialog
                //prgDialog.hide();
                // When Http response code is '404'
                if(statusCode == 404){
                    Toast.makeText(ctx,"Requested resource not found", Toast.LENGTH_LONG).show();
                }
                // When Http response code is '500'
                else if(statusCode == 500){
                    Toast.makeText(ctx, "Something went wrong at server end", Toast.LENGTH_LONG).show();
                }
                // When Http response code other than 404, 500
                else{
                    Toast.makeText(ctx, errorResponse.toString(), Toast.LENGTH_LONG).show();
                    Toast.makeText(ctx, "Unexpected Error occcured! " + statusCode, Toast.LENGTH_LONG).show();
                }
            }

            // When the response returned by REST has Http response code other than '200'
            @Override
            public void onFailure(int statusCode, org.apache.http.Header[] headers, java.lang.Throwable throwable, org.json.JSONArray errorResponse) {
                // Hide Progress Dialog
                //prgDialog.hide();
                // When Http response code is '404'
                if(statusCode == 404){
                    Toast.makeText(ctx,"Requested resource not found", Toast.LENGTH_LONG).show();
                }
                // When Http response code is '500'
                else if(statusCode == 500){
                    Toast.makeText(ctx, "Something went wrong at server end", Toast.LENGTH_LONG).show();
                }
                // When Http response code other than 404, 500
                else{
                    Toast.makeText(ctx, "Unexpected Error occcured! [Most common Error: Device might not be connected to Internet or remote server is not up and running]", Toast.LENGTH_LONG).show();
                }
            }
        });
    }

    public void callFunction(String functionName, String params) throws JSONException {


        RestClient.post(functionName, null, new JsonHttpResponseHandler() {
            @Override
            public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
                Toast.makeText(ctx, "Success!", Toast.LENGTH_LONG).show();
            }

            @Override
            public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
            
                Toast.makeText(ctx, "Success!", Toast.LENGTH_LONG).show();
                Log.i("ApiFacade", response.toString());
               
                    // Do something with the response


            }

            // When the response returned by REST has Http response code other than '200'
            @Override
            public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
                // Hide Progress Dialog
                //prgDialog.hide();
                // When Http response code is '404'
                if (statusCode == 404) {
                    Toast.makeText(ctx, "Requested resource not found", Toast.LENGTH_LONG).show();
                }
                // When Http response code is '500'
                else if (statusCode == 500) {
                    Toast.makeText(ctx, "Something went wrong at server end", Toast.LENGTH_LONG).show();
                }
                // When Http response code other than 404, 500
                else {
                    Toast.makeText(ctx, errorResponse.toString(), Toast.LENGTH_LONG).show();
                    Toast.makeText(ctx, "Unexpected Error occcured! " + statusCode, Toast.LENGTH_LONG).show();
                }
            }

            // When the response returned by REST has Http response code other than '200'
            @Override
            public void onFailure(int statusCode, org.apache.http.Header[] headers, java.lang.Throwable throwable, org.json.JSONArray errorResponse) {
                // Hide Progress Dialog
                //prgDialog.hide();
                // When Http response code is '404'
                if (statusCode == 404) {
                    Toast.makeText(ctx, "Requested resource not found", Toast.LENGTH_LONG).show();
                }
                // When Http response code is '500'
                else if (statusCode == 500) {
                    Toast.makeText(ctx, "Something went wrong at server end", Toast.LENGTH_LONG).show();
                }
                // When Http response code other than 404, 500
                else {
                    Toast.makeText(ctx, "Unexpected Error occcured! [Most common Error: Device might not be connected to Internet or remote server is not up and running]", Toast.LENGTH_LONG).show();
                }
            }
        });
    }
}

And last but not least the actual HttpClient implementation is in RestClient.java:

package <YOURPACKAGE>;

import com.loopj.android.http.*;

public class RestClient {
    private static final String BASE_URL = "https://api.spark.io:443/v1/devices/<DEVICE_ID>/";

    private static AsyncHttpClient client = new AsyncHttpClient(false, 80, 443);

    public static void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {

        client.get(getAbsoluteUrl(url), params, responseHandler);
    }

    public static void post(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
        client.post(getAbsoluteUrl(url), params, responseHandler);
    }

    private static String getAbsoluteUrl(String relativeUrl) {
        return BASE_URL + relativeUrl + "?access_token=<YOUR_ACCESS_TOKEN>";
    }
}

Don’t forget to replace the noted FIELDS ! I will happily answer any questions, if I’m able to :smiley:

1 Like

Yes that part is ok. Only one thing, d3 has to be D7. (Capital letter) Thank’s for your time! :slight_smile:

I was looking for a good starting point to tinker around with my Spark Core and try to create some interaction with an Android application.

@clyde I really like the overall idea of your example, however, both the Spark firmware and Android example seem to have some issues. Nevertheless, going through the provided code and instructions got me to understand the basic concepts of this implementation of the POST/GET <> Android concept. And hey, you’ve introduced me to the Android Studio :smile:

I think I’m going to give the example provided by @steliosk a go; the async http client seems to be a good option here.

I know this thread is pretty old, but I had a few questions about how secure this is and figured other beginners may have similar questions. So here’s my line of thought, please correct me if I’m wrong. Any advice would be greatly appreciated.

The example uses a HTTPS connection, so I assume it uses SSL. This means that the entire message of the request will be encrypted and anyone listening in on the request shouldn’t be able to read any sensitive information such as the device id, access token, or commands/request.

I am able to successfully run this https request without pinning the public key in the program (to later compare with the particle website). I am inclined to believe that the particle website has a certificate issued by an certificate authority (CA). This basically means that when the application opens the HTTPS connection it will request/receive the public key from the particle website and compare this key to one from a list of known certificates (provided by the different major CA).

I’m primarily concerned about:

  1. is the message encrypted (information like the device id, access token, or commands/request)?
  2. does Particle use a CA for it’s certificates?