Sunday, June 19, 2016

Android BroadcastReceiver

Android applications need some mechanism to know when some event is occurred. For example some applications need to perform tasks when Android OS booting is completed. Android SDK provide BroadcastReceiver class for that purpose. This blog post content is about using BroadcastReceiver to get notification about connecting and disconnecting Android OS running device from external power source.
Name of this application is ConDisConInfo. So it has the main package with name com.blogspot.nipunswritings.ConDisConInfo. To create a BroadcastReceiver follow these steps.
  • Right Click on Main package
  • New
  • Other
  • Broadcast Receiver
  • Give name and click Finish
Once Finish is clicked a new java file can be seen in main package with the name PowerConnInfoReceiver.java. It has a PowerConnInfoReceiver class which extends from super class BroadcastReceiver. PowerConnInfoReceiver has below method which receive power connection/disconnection information which is sent by system.

@Overridepublic void onReceive(Context context, Intent intent) {
    
}

After  PowerConnInfoReceiver is created AndroidManifest.xml file has been updated with receiver element. That is registering a Broadcast Receiver. The receiver element in AndroidManifest.xml file is this.

<receiver 
     android:name=".PowerConnInfoReceiver" 
     android:enabled="true"
     android:exported="true">
</receiver>

Though that element is in the AndroidManifest.xml file PowerConnInfoReceiver will not receive any broadcast. A BroadcastReceiver to receive broadcasts it must be specified what broadcasts it must be received through the intent-filter element. Therefore receiver element is updated like below to receive broadcasts as mentioned above.

<receiver 
    android:name=".PowerConnInfoReceiver" 
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
        <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
    </intent-filter>
</receiver>

Notice the actions inside intent-filter. Without those actions this application doesn't work as expected. 

Method onReceive(Context, Intent) is updated to filter received information via Intent object and to display information to user as a Toast. So updated onReceive(Context, Intent) method is this.

@Overridepublic void onReceive(Context context, Intent intent) {
    if (intent.getAction().equals(Intent.ACTION_POWER_CONNECTED)){
        Toast.makeText(context, "Power Connected", Toast.LENGTH_LONG).show();
    } else if (intent.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
        Toast.makeText(context, "Power Disconnected", Toast.LENGTH_LONG).show();
    }
}

Run this app on a emulator. This application can be tested with battery section in extended controls of emulator. When charger connection is toggled between AC Charger and None corresponding Toast is displayed.



Reference:
  • https://developer.android.com/reference/android/content/BroadcastReceiver.html
  • https://developer.android.com/reference/android/content/Intent.html#ACTION_POWER_CONNECTED
  • https://developer.android.com/reference/android/content/Intent.html#ACTION_POWER_DISCONNECTED

Sunday, June 12, 2016

HelloCharts for Android Example

This example is using HelloCharts for Android to plot line chart for function |sin(x)|. The value range for x axis is from 0 to 360 degrees. The x values are given like 0, 15, 30, 45 ... 360. So there is difference of 15 degrees between  two points. But X axis is drawn with 30 degree scale. Therefore it goes like 0, 30, 60, 90, ..., 180, ...360. Y axis is drawn with scale of 0.25 from 0 to 1.0 to make Y axis range 0, 0.25, 0.5, 1.

At the end of this example developed application creates the below chart.

Add hello-charts library to app by adding below line to dependencies block of build.gradle file of app module. Then sync the project by using Android Studio.

compile 'com.github.lecho:hellocharts-library:1.5.8@aar'


Project has one Activity file with the name MainActivity.java. It's layout resource file is activity_main.xml.

This is the content of activity_main.xml. It has RelativeLayout as root element and RelativeLayout contain TextView and chart definition.

<TextView 
 android:id="@+id/chartLbl" 
 android:gravity="center" 
 android:layout_width="match_parent" 
 android:layout_height="wrap_content" 
 android:text="|sin(x)|" 
 android:layout_alignParentTop="true"     
 android:layout_alignParentStart="true"     
 android:layout_alignParentLeft="true"     
 android:layout_margin="5dp" 
 android:textStyle="bold" />

<lecho.lib.hellocharts.view.LineChartView 
 android:id="@+id/chart"     
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:padding="10dp" 
 android:layout_below="@+id/chartLbl"/>

The element lecho.lib.hellocharts.view.LineChartView is xml definition of the line chart.

Now reference to this LineChartView can be made with findViewById(int) method. To hold reference to that view, field of type LineChartView has been defined in the MainActivity.java like this.
 
private LineChartView lineChartView;

Line chart has been created with below method. That is called in onCreate(Bundle) method.
 
public void drawSinAbsChart()

Method definition of  drawSinAbsChart()

public void drawSinAbsChart() {
    String decimalPattern = "#.##";
    DecimalFormat decimalFormat = new DecimalFormat(decimalPattern);

    lineChartView = (LineChartView) findViewById(R.id.chart);

    List<PointValue> values = new ArrayList<PointValue>();

    PointValue tempPointValue;
    for (float i = 0; i <= 360.0; i+= 15.0f) {
        tempPointValue = new PointValue(i, Math.abs((float)Math.sin(Math.toRadians(i))));
        tempPointValue.setLabel(decimalFormat
                   .format(Math.abs((float)Math.sin(Math.toRadians(i)))));
        values.add(tempPointValue);
    }

    Line line = new Line(values)
                   .setColor(Color.BLUE)
                   .setCubic(false)
                   .setHasPoints(true).setHasLabels(true);
    List<Line> lines = new ArrayList<Line>();
    lines.add(line);

    LineChartData data = new LineChartData();
    data.setLines(lines);

    List<AxisValue> axisValuesForX = new ArrayList<>();
    List<AxisValue> axisValuesForY = new ArrayList<>();
    AxisValue tempAxisValue;
    for (float i = 0; i <= 360.0f; i += 30.0f){
        tempAxisValue = new AxisValue(i);
        tempAxisValue.setLabel(i+"\u00b0");
        axisValuesForX.add(tempAxisValue);
    }

    for (float i = 0.0f; i <= 1.00f; i += 0.25f){
        tempAxisValue = new AxisValue(i);
        tempAxisValue.setLabel(""+i);
        axisValuesForY.add(tempAxisValue);
    }

    Axis xAxis = new Axis(axisValuesForX);
    Axis yAxis = new Axis(axisValuesForY);
    data.setAxisXBottom(xAxis);
    data.setAxisYLeft(yAxis);


    lineChartView.setLineChartData(data);


}

Code Explanation

    String decimalPattern = "#.##";
    DecimalFormat decimalFormat = new DecimalFormat(decimalPattern);

Values that are obtained must be shown only up to two decimal places in chart point labels. Object decimalFormat is created for that purpose.

    lineChartView = (LineChartView) findViewById(R.id.chart);

Above jave statement is to obtain the LineChartView object that is declared in the layout xml resource.

    List<PointValue> values = new ArrayList<PointValue>();

    PointValue tempPointValue;
    for (float i = 0; i <= 360.0; i+= 15.0f) {
        tempPointValue = new PointValue(i, Math.abs((float)Math.sin(Math.toRadians(i))));
        tempPointValue.setLabel(decimalFormat
                   .format(Math.abs((float)Math.sin(Math.toRadians(i)))));
        values.add(tempPointValue);
    }

Tha values that must be displayed in the line chart must be in the List of type List<PointValue>. That is doing here. That list contains points which are drawn in the chart. Point is represented with PointValue Class. for loop create those points and set it label that are shown at the points.

    Line line = new Line(values)
                   .setColor(Color.BLUE)
                   .setCubic(false)
                   .setHasPoints(true).setHasLabels(true);
    List<Line> lines = new ArrayList<Line>();
    lines.add(line);

    LineChartData data = new LineChartData();
    data.setLines(lines);

Line chart can  contain many lines, Above code shows how to create new line with the values which was generated function |sin(x)|. Method setColor() is used to define color of the line. This chart has straight line as setCubic() has been provided false value. If setHasPoints() called with argument false value points wouldn't be displayed.When setHasLabels() is provided with argument true value labels that was set during PointValue object are created is shown. The lines variable of type List<Line> holds all the lines that is drawn in the chart. This example chart has only one line so it has been added. Finally that lines object is added to LineChartData object with setLines().

    List<AxisValue> axisValuesForX = new ArrayList<>();
    List<AxisValue> axisValuesForY = new ArrayList<>();
    AxisValue tempAxisValue;
    for (float i = 0; i <= 360.0f; i += 30.0f){
        tempAxisValue = new AxisValue(i);
        tempAxisValue.setLabel(i+"\u00b0");
        axisValuesForX.add(tempAxisValue);
    }

    for (float i = 0.0f; i <= 1.00f; i += 0.25f){
        tempAxisValue = new AxisValue(i);
        tempAxisValue.setLabel(""+i);
        axisValuesForY.add(tempAxisValue);
    }

    Axis xAxis = new Axis(axisValuesForX);
    Axis yAxis = new Axis(axisValuesForY);
    data.setAxisXBottom(xAxis);
    data.setAxisYLeft(yAxis);

Java statements that are shown creating X and Y axis of the chart. First loop creates X axis which is started from 0 and goes upto 360 with increment 15.0 from previous x value. Values of axis is represented with object of type List<AxisValue> and AxisValue objects are used represent a location in the axis. AxisValue has setLabel() to display developer preferred label in the chart. In same way Y axis also has been created. After thata x & y axis is created as Axis objects. X axis is set to bottom with setAxisXBottom() and Y Axis is set to left with setAxisYLeft().

Chart data is provided to LineChartView with below statement.

    lineChartView.setLineChartData(data);

If axis values is cut off this link might be helpful. I had similar problem but I could resolve it without that link by adding 5dp padding around LineChartView.

Reference:
  • https://github.com/lecho/hellocharts-android

Saturday, June 4, 2016

Renaming Android Studio Project and Main Package

Content of this blog post has been tested with Android Studio 2.0.

Changing Project Name
  • Open Project Window (View → Tool Windows → Project or Alt + 1)
  • By default Project window shows the Android view change it to Project view with the drop down menu at top left. 


  •  Right click on project root → Show in Explorer.
  • Close Android Studio.
  • Go into project folder.
  • Change .iml file to new name that you want to have for the project.
  •  Change the project folder name to new name which is same name of .iml file.
  • Start Android Studio
  • Click on “Open an existing Android Studio project”
  • Find & select the renamed project, then “Ok”
Changing Package name
  • Right Click on package name (I tried this on main package)
  • Refactor
  • Rename
  • Rename Package
  • Type new name & click Refactor
  • Click on Do Refactor 
After doing this I have observed changing the main package name successfully renamed other two packages (androidTest & Test) during refactoring process. Although Generated files like AndroidManifest.xml also had correct values strings.xml file had old project name for the string element with attribute “app_name”.
Above experiment was done on a very small project.


Sunday, February 14, 2016

iOS Auto Layout Notes - 1

This post has written about 
  • Adding auto layout constraints to UI object by using interface builder
  • Changing auto layout constraints by using swift language
Auto layout constraints can be defined to work with different Size classes. Size classes that is applied to different devices and orientations can be change with the below Pop over in the interface builder.

Since UI components of this application is needed to be fit to all the UIs height and width size class of Any is selected here.

There is a UIImageView object on the UIViewController of this class. To center it horizontally on the screen select the UIImageView click on the align button to display Add New Alignment Constraints pop up.

On the pop up menu Select Horizontally in Container and then click on the button Add 1 Constraint.

UIImageView needs to be 10 point below from the top layout guide. And it need to have width and height of 200 points. To do that click on the pin button to show pop up that can be used to add constraints for above requirements.

Once the constraints were set by using pin pop up like above click on Add 3 Constraints to add them to UIImageView.

To see changes on the storyboard. Click on the Resolve Auto Layout Issues button that shows a   menu like below .Then click on Update Frames.

That will remove orange color lines if there are them and adjust UI dimensions to reflect constraints.

Change Auto layout Constraints with Swift Code

Create IBOutlet to UIImageView width and height constraints.

@IBOutlet weak var imageHeight: NSLayoutConstraint!
@IBOutlet weak var imageWidth: NSLayoutConstraint!


Write a method like below to change Auto layout constraints which is referred through outlets by using swift code.

func resizeImage(size: Int){
    imageHeight.constant = CGFloat(size)
    imageWidth.constant = CGFloat(size)
}


Value of instance of  NSLayoutConstraint can be changed by assigning new CGFloat value to that instance's constant property.

Sunday, February 7, 2016

How To Install Boost C++ Library On Ubuntu 14.04 LTS

This is how boost C++ library can be installed into a location that is needed to be put. Here I have installed into a folder in my home home folder. All the below command executed from a folder that contain boost_1_59_0.tar.bz2 file. Boost has been installed without ICU.

$ lsb_release -a

No LSB modules are available.
Distributor ID:    Ubuntu
Description:    Ubuntu 14.04.2 LTS
Release:    14.04
Codename:    trusty

$ python -V

Python 2.7.6

$ sudo apt-get install g++

$ sudo apt-get install python2.7-dev

$ sudo apt-get install libicu-dev

$ sudo apt-get install libbz2-dev

$ sudo apt-get install build-essential

$ sudo apt-get install autotools-dev

$ tar --bzip2 -xf boost_1_59_0.tar.bz2

$ cd boost_1_59_0/

$ ./bootstrap.sh --prefix=/home/nipun/BoostLibs --without-icu

$ ./b2 install --prefix=/home/nipun/BoostLibs

Saturday, July 25, 2015

Securing Google Cloud Endpoints API for Android App With HMAC

Google cloud endpoints can be secured by using Oauth protocol provided via Google accounts. Although that feature is provided by the Google cloud endpoints developers don't want to use Oauth sometimes. It's also possible to protect Google Cloud Endpoint APIs with the HMAC authentication. This blog post demonstrate how to protect APIs with HMAC. Example backend APIs have been written by using Java programming language.

Following implementation details will be more described in paragraphs below.
  • How to access HttpServletRequest instance within the API methods
  • How to calculate HMAC in java
  • How to read http authorization header by using  HttpServletRequest instance
  • How to set HMAC in authorization header by using Google Cloud Endpoint client library for Android

System Requirement

Android app send a name of a user. Server should reply with Hi, <name of user>. For example, if app send nipun it should reply with Hi, Nipun. Aforementioned requirement already implemented when Google Cloud Endpoint module is added with Android Studio. Codes from Reference [1] is on content of this post.

User Interface

Android client UI has a Button and a EditText. EditText has the id nameUiValue. nameUiValue has been assigned to
 
private EditText nameEditText;
 
When a user click on the button it calls the method.
 
public void sendName(View view)


Before securing the APIs Endpoint class and client AsyncTask class is show below.

Cloud


MyEndpoint.java

/*   For step-by-step instructions on connecting your Android application to this backend module,
   see "App Engine Java Endpoints Module" template documentation at 
   https://github.com/GoogleCloudPlatform/gradle-appengine-templates/tree/master/HelloEndpoints*/
package com.example.nipun.myapplication.backend;
import com.google.api.server.spi.config.Api; 
import com.google.api.server.spi.config.ApiMethod; 
import com.google.api.server.spi.config.ApiNamespace; 
 
import javax.inject.Named; 
import javax.servlet.http.HttpServletRequest;
/** * An endpoint class we are exposing */@Api(name = "myApi", version = "v1",
        namespace = @ApiNamespace(ownerDomain = "backend.myapplication.nipun.example.com",
                   ownerName = "backend.myapplication.nipun.example.com", packagePath = ""))
public class MyEndpoint {

    /**     * A simple endpoint method that takes a name and says Hi back     */

    @ApiMethod(name = "sayHi")
    public MyBean sayHi(HttpServletRequest request, @Named("name") String name) {
        MyBean response = new MyBean();        response.setData("Hi, " + name);
        return response;    }

}  

Android Client AsyncTask


class EndpointsAsyncTask extends AsyncTask<Pair<Context, String>, Void, String> {
    private MyApi myApiService = null;    private Context context;
    @Override    protected String doInBackground(Pair<Context, String>... params) {
        if(myApiService == null) {
            MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(), 
                new AndroidJsonFactory(), null)

                    .setRootUrl("http://10.0.2.2:8080/_ah/api/")
                    .setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
                        @Override
                        public void initialize(AbstractGoogleClientRequest<?> 
                                            abstractGoogleClientRequest) throws IOException {
                            abstractGoogleClientRequest.setDisableGZipContent(true);
                        }
                    });

            myApiService = builder.build();        }

        context = params[0].first;        String name = params[0].second;
        try {
            return myApiService.sayHi(name).execute().getData();        } catch (IOException e) {
            return e.getMessage();        }
    }

    @Override    protected void onPostExecute(String result) {
        Toast.makeText(context, result, Toast.LENGTH_LONG).show();    }
} 

Securing Google Cloud Endpoint With HMAC

How to access HttpServletRequest instance within the API methods


In order to get the HMAC value from http authorization header HttpServletRequest must be accessed from the API method. It can be done by using following way.

public MyBean sayHi(HttpServletRequest request, @Named("name") String name)

ApiMethod has included HttpServletRequest as an parameter.  

How to calculate HMAC in java


Hmac has been generated according to reference 3 and 4. A new hmac is calculated by using at the endpoint by using AuthManager.java class.

package com.example.nipun.myapplication.backend.auth;
import java.io.UnsupportedEncodingException;import java.security.InvalidKeyException;

import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;
/** * Created by nipun on 7/25/15. */public class AuthManager {
    private String KEY = "E34swDN1Fk1G44zmw9bL2N5B8R85w290";    private String ALGO = "HmacSHA1";
    public boolean authenticationSuccessful(String dataForHmac, String authHeader){

        if (authHeader == null)
            return false;
        String tempHmacParts[] = authHeader.split(" ");        if (tempHmacParts.length != 2)
            return false;
        tempHmacParts = tempHmacParts[1].split(":");
        if (tempHmacParts.length != 2)
            return false;
        if (tempHmacParts[1].equals(hmacDigest(dataForHmac, KEY, ALGO))){
            return true;        }else {
            return false;        }
    }

    /*    *    * This method is taken from 
    * http://www.supermind.org/blog/1102/generating-hmac-md5-sha1-sha256-etc-in-java 
    */
    private String hmacDigest(String msg, String keyString, String algo) {
        String digest = null;        try {
            SecretKeySpec key = new SecretKeySpec((keyString).getBytes("UTF-8"), algo);
            Mac mac = Mac.getInstance(algo);            mac.init(key);
            byte[] bytes = mac.doFinal(msg.getBytes("ASCII"));
            StringBuffer hash = new StringBuffer();
            for (int i = 0; i < bytes.length; i++) {
                String hex = Integer.toHexString(0xFF & bytes[i]);
                if (hex.length() == 1) {
                    hash.append('0');                }
                hash.append(hex);            }
            digest = hash.toString();        } catch (UnsupportedEncodingException e) {
        } catch (InvalidKeyException e) {
        } catch (NoSuchAlgorithmException e) {
        }
        return digest;    }


}

The method

private String hmacDigest(String msg, String keyString, String algo)

is used to calculate hmac. That method is used to check whether authentication is successful by using this method.

public boolean authenticationSuccessful(String dataForHmac, String authHeader)

Client has class HmacUtil.java to calculate hmac before send it to the server.

package com.blogspot.nipunswritings.hiname;
import java.io.UnsupportedEncodingException;import java.security.InvalidKeyException; 
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;
/** * Created by nipun on 7/25/15. */

public class HmacUtil {

    private static String KEY = "E34swDN1Fk1G44zmw9bL2N5B8R85w290";
    private static String ALGO = "HmacSHA1";

    /*    *    * This method is taken from 
    * http://www.supermind.org/blog/1102/generating-hmac-md5-sha1-sha256-etc-in-java 
    * but parameters have change here 
    * */
     public static String hmacDigest(String msg) {
        String digest = null;        try {
            SecretKeySpec key = new SecretKeySpec((KEY).getBytes("UTF-8"), ALGO);
            Mac mac = Mac.getInstance(ALGO);
            mac.init(key);
            byte[] bytes = mac.doFinal(msg.getBytes("ASCII"));
            StringBuffer hash = new StringBuffer(); 
            for (int i = 0; i < bytes.length; i++) {
                String hex = Integer.toHexString(0xFF & bytes[i]); 
                if (hex.length() == 1) {
                    hash.append('0');                }
                hash.append(hex);            }
            digest = hash.toString();        } catch (UnsupportedEncodingException e) {
        } catch (InvalidKeyException e) {
        } catch (NoSuchAlgorithmException e) {
        }
        return digest;    }

}

Android client use below method to calculate hmac

public static String hmacDigest(String msg) 

How to read http authorization header by using  HttpServletRequest instance


@ApiMethod(name = "sayHi")
public MyBean sayHi(HttpServletRequest request, @Named("name") String name) throws 
                                                                        HmacMismatchException{

    String authHeader = request.getHeader("Authorization"); 
    AuthManager authManager = new AuthManager(); 
    String digestData = request.getMethod()+"+/myApi/v1/sayHi/"+name;

    if (!authManager.authenticationSuccessful(digestData, authHeader)){
        throw new HmacMismatchException();    }

    MyBean response = new MyBean();    response.setData("Hi, " + name);
    return response;}

It has added new parameter with the type HttpServletRequest and it has name request. Developers can use getHeader() to get http header. After getting Authorization header data for hmac generation is assigned to digestData. Then it is passed with Authorization header value to 

public boolean authenticationSuccessful(String dataForHmac, String authHeader) 

of AuthManager. If the authentication is not successful Endpoint send HmacMismatchException to client. HmacMismatchException.java is shown below.

package com.example.nipun.myapplication.backend.auth;
/** * Created by nipun on 7/25/15. */

public class HmacMismatchException extends Exception {

    public HmacMismatchException(){
        super("Can't produce received hmac");    }
}

How to set HMAC to authorization header by using Google Cloud Endpoint client library for Android


Android client in this blog post send a string,a name, to endpoint. Android user interface use EditText and Button to get user data. When button is clicked EndpointsAsyncTask is executed. It's provided name of the user.

Below method is called when a user touch the button.

public void sendName(View view){
    String name = nameEditText.getText().toString();
    new EndpointsAsyncTask().execute(new Pair<Context, String>(this, name));
}

Code for  EndpointsAsyncTask with http headers setting

class EndpointsAsyncTask extends AsyncTask<Pair<Context, String>, Void, String> {
    private MyApi myApiService = null;    private Context context;
    @Override    protected String doInBackground(Pair<Context, String>... params) {

        context = params[0].first;        final String name = params[0].second;
        if(myApiService == null) {  
            MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(), 
                new AndroidJsonFactory(), null)

                    .setRootUrl("http://10.0.2.2:8080/_ah/api/")
                    .setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
                        @Override
                        public void initialize(AbstractGoogleClientRequest<?> 
                                           abstractGoogleClientRequest) throws IOException {
                            abstractGoogleClientRequest.setDisableGZipContent(true); 
                            HttpHeaders httpHeaders = 
                                         abstractGoogleClientRequest.getRequestHeaders(); 
                            httpHeaders.setAuthorization("hmac "
                                +"public:"+HmacUtil.hmacDigest("POST+/myApi/v1/sayHi/"+name));
                            abstractGoogleClientRequest.setRequestHeaders(httpHeaders); 
                        }
                    });
            myApiService = builder.build();        }

        try {
            return myApiService.sayHi(name).execute().getData();
        } catch (IOException e) {
            return e.getMessage();        }
    }

    @Override    protected void onPostExecute(String result) {
        Toast.makeText(context, result, Toast.LENGTH_LONG).show();    }
}

Code to set Authorization header is this.

public void initialize(AbstractGoogleClientRequest<?> 
                                  abstractGoogleClientRequest) throws IOException {
    abstractGoogleClientRequest.setDisableGZipContent(true); 
    HttpHeaders httpHeaders = abstractGoogleClientRequest.getRequestHeaders();


    httpHeaders.setAuthorization("hmac " 
                      +"public:"+HmacUtil.hmacDigest("POST+/myApi/v1/sayHi/"+name));
    abstractGoogleClientRequest.setRequestHeaders(httpHeaders);} 

References

  1.  https://github.com/GoogleCloudPlatform/gradle-appengine-templates/tree/master/HelloEndpoints
  2. http://stackoverflow.com/questions/15056830/getting-raw-http-data-headers-cookies-etc-in-google-cloud-endpoints
  3. http://www.supermind.org/blog/1102/generating-hmac-md5-sha1-sha256-etc-in-java
  4. http://restcookbook.com/Basics/loggingin/

Tuesday, July 21, 2015

Include HttpHeaders to Google Cloud API call request made from Android

When making Cloud Endpoint API call request from the Android client sometimes it's needed to add Http Headers to that request. This blog post say how to add Date http header to request that calls myApi.sayHi() method which is described here. Read the code of EndpointsAsyncTask class. The code where http headers must be set is shown below.



MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(),
                    new AndroidJsonFactory(), null)
                // options for running against local devappserver
                // - 10.0.2.2 is localhost's IP address in Android emulator
                // - turn off compression when running against local devappserver
                .setRootUrl("http://10.0.2.2:8080/_ah/api/")
                .setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
                    @Override
                    public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest) throws IOException {
                        abstractGoogleClientRequest.setDisableGZipContent(true);
                    }
                });
                // end options for devappserver

            myApiService = builder.build();



Now add the Date http header as below. The bold text are the code that is used to add http header to request.



                MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(),
                        new AndroidJsonFactory(), null)
                        // options for running against local devappserver
                        // - 10.0.2.2 is localhost's IP address in Android emulator
                        // - turn off compression when running against local devappserver
                        .setRootUrl("http://10.0.2.2:8080/_ah/api/")
                        .setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
                            @Override
                            public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest) throws IOException {
                                abstractGoogleClientRequest.setDisableGZipContent(true);


                                Calendar calendar = Calendar.getInstance();
                                SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");

                                HttpHeaders headers = abstractGoogleClientRequest.getRequestHeaders();                                Log.d(TAG, "Date: "+dateFormat.format(calendar.getTime()));
                                headers.setDate(dateFormat.format(calendar.getTime()));
                                abstractGoogleClientRequest.setRequestHeaders(headers);
                            }
                        });

                myApiService = builder.build();