Thursday, September 6, 2012

Google Now Cards Layout

If you are a fan of Google's android applications, you must haven't missed cards animation that Google Now brings in on Android 4.1, Jelly Bean.

Google Now Cards Layout on Jellybean

Lets see how to create these smooth animations.

You can browse the source here : https://github.com/shardul/Android/tree/master/NowLayout

Step 1 : Animations and Styles

There are two animations of similar sliding transition, differing slightly for alternating cards (technically Views). One rotating in from left and other for right. 

slide_up_left.xml


<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator" >

    <translate
        android:duration="@integer/config_slide_time"
        android:fromYDelta="100%p"
        android:toYDelta="0" />

    <alpha
        android:duration="@integer/config_slide_time"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />

    <rotate
        android:duration="@integer/config_slide_time"
        android:fromDegrees="25"
        android:pivotX="0"
        android:pivotY="0"
        android:toDegrees="0" />

</set>

slide_up_right.xml


<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator" >

    <translate
        android:duration="@integer/config_slide_time"
        android:fromYDelta="100%p"
        android:toYDelta="0" />

    <alpha
        android:duration="@integer/config_slide_time"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />

    <rotate
        android:duration="@integer/config_slide_time"
        android:fromDegrees="-25"
        android:pivotX="100%"
        android:pivotY="0"
        android:toDegrees="0" />

</set>

These animations will create alternate card animations.

NowLayout.java


package com.shardul.nowlayout;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.AnimationUtils;
import android.widget.LinearLayout;

public class NowLayout extends LinearLayout implements OnGlobalLayoutListener {

 public NowLayout(Context context, AttributeSet attrs) {
  super(context, attrs);
  initLayoutObserver();

 }

 public NowLayout(Context context) {
  super(context);
  initLayoutObserver();
 }

 private void initLayoutObserver() {
        // force vertical orientation and add observer
                setOrientation(LinearLayout.VERTICAL);
  getViewTreeObserver().addOnGlobalLayoutListener(this);
 }

 @Override
 public void onGlobalLayout() {
  getViewTreeObserver().removeGlobalOnLayoutListener(this);

  final int heightPx =getContext().getResources().
                getDisplayMetrics().heightPixels;

  boolean inversed = false;
  final int childCount = getChildCount();

 for (int i = 0; i < childCount; i++) {
  View child = getChildAt(i);

  int[] location = new int[2];

  child.getLocationOnScreen(location);

  if (location[1] > heightPx) {
   break;
  }

  if (!inversed) {
   child.startAnimation(
                        AnimationUtils.loadAnimation(getContext(),
      R.anim.slide_up_left));
   } else {
   child.startAnimation(
                        AnimationUtils.loadAnimation(getContext(),
      R.anim.slide_up_right));
   }

   inversed = !inversed;
  }

 }

}


This is where all the magic will happen. To create alternating animations we can definitely grab each child and start respective animation in activity but a better approach would be to create custom layout and handle animation there which is a better approach to take.

Integrating 


Now we have to make use of NowLayout in our activity.

main.xml


<ScrollView 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:fillViewport="true" >

    <com.shardul.nowlayout.NowLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#e3e3e3"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/txtView"
            style="@style/nowCardStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello_world"
            tools:context=".MainActivity" />

        <TextView
            android:id="@+id/txtView"
            style="@style/nowCardStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello_world"
            tools:context=".MainActivity" />

        <TextView
            android:id="@+id/txtView"
            style="@style/nowCardStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello_world"
            tools:context=".MainActivity" />

        <TextView
            android:id="@+id/txtView"
            style="@style/nowCardStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello_world"
            tools:context=".MainActivity" />

        <TextView
            android:id="@+id/txtView"
            style="@style/nowCardStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello_world"
            tools:context=".MainActivity" />
    </com.shardul.nowlayout.NowLayout>

</ScrollView>

MainActivity.java


package com.shardul.nowlayout;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
 }

}

And there you have it. Run the app and see sliding cards similar to Google Now app.

Make sure you share with your friends if you like what you created.

You can also learn about Creating Chrome Style Help Popups on Android.

Wednesday, September 5, 2012

SOAP Calls With SOAPIntentService

WikiSOAP, originally defined as Simple Object Access Protocol, is a protocol specification for exchanging structured information in the implementation of Web Services in computer networks. It relies on Extensible Markup Language (XML) for its message format, and usually relies on otherApplication Layer protocols, most notably Hypertext Transfer Protocol (HTTP) and Simple Mail Transfer Protocol (SMTP), for message negotiation and transmission.

Being a developer, various server interaction methodologies come across you. SOAP being one of them when high security and reliability of transmission is concerned during server communication. Though it adds overhead (large payloads) it largely being used for enterprise level apps.

By default, SOAP isn't bundled with Android (unlike JSON). We have external libraries available which can be used to achieve this task.

One of these is kSoap2, official project http://code.google.com/p/ksoap2-android/

Lets talk about SOAPIntentService


Android Docs : IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.

This "work queue processor" pattern is commonly used to offload tasks from an application's main thread. The IntentService class exists to simplify this pattern and take care of the mechanics. To use it, extend IntentService and implement onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.

All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.

SOAPIntentService working

SOAP Intent Service, accepts a call and executes it on another thread, and responds back to caller via 
Broadcast Receiver

It's also designed to cache on failure when POST is set as request type.

You can acquire source from here : https://github.com/shardul/Android/tree/master/SoapIntentService

Usage


// initialise request helper with appropriate parameters from wsdl definition
SOAPRequestHelper soapRequestHelper = new SOAPRequestHelper(namespace,
    action, methodName, url);

// set properties for request using SOAPNameValuePair instances
SOAPNameValuePair[] props = new SOAPNameValuePair[2];
props[0]=new SOAPNameValuePair("param1","value1");
props[1]=new SOAPNameValuePair("param2","value2");

soapRequestHelper.setProperties(props);


// optionally set headers for request using SOAPNameValuePair instances

SOAPNameValuePair[] headers = new SOAPNameValuePair[2];
headers[0]=new SOAPNameValuePair("header1","headervalue1");
headers[1]=new SOAPNameValuePair("header2","headervalue2");

soapRequestHelper.setHeaders(headers);


//perform a call to SOAPIntentService using

soapRequestHelper.performSOAPRequest(this, responseReceiver);


responseReceiver defined above is a BroadcastReceiver and is an optional parameter. It should only be used when caller do bothers about the response. responseReceiver will be internally registered thus it should accompany a context.unregisterReceiver(responseReceiver) when service call is dealt with.

Heres how responseReceiver code definition should look like


private class ResponseReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
       // initialise response received
 SOAPResponseHelper soapResponseHelper = new SOAPResponseHelper(
    intent);

        //check if theres an exception
 if (!soapResponseHelper.isException()) {
  responseMap = soapResponseHelper.getResponseMap();
  showDialog(DIALOG_RESPONSE);
 } else {
 Toast.makeText(SoapIntentActivityActivity.this,
 soapResponseHelper.getException().toString(),Toast.LENGTH_LONG).show();
 }
 }

}

Additionally caching can be enabled on the call by setting requestType as post of SOAPRequetHelper class


soapRequestHelper.setRequestType(SOAPRequestHelper.REQUEST_TYPE_POST)

And don't forget to include internet permission in your AndroidManifest.xml


<uses-permission android:name="android.permission.INTERNET" />


For further implementation details, you can browse sample code here.

https://github.com/shardul/Android/blob/master/SoapIntentService/src/com/shardul/android/soapservice/activities/SoapIntentActivityActivity.java

Feel free to email me or post comments regarding implementation and enhancements.