Friday, 27 December 2013

Flickr API in Android


What is Flickr?

Flickr is the best online photo management and sharing application in the world. On Flickr, members upload photos, share them securely, supplement their photos with metadata like license information, geo-location, people, tags, etc., and interact with their family, friends, contacts or anyone in the community. Practically all the features on Flickr's various platforms -- web, mobile and desktop -- are accompanied by a longstanding API program. Since 2005, developers have collaborated on top of Flickr's APIs to build fun, creative, and gorgeous experiences around photos that extend beyond Flickr.
Overview
The Flickr API consists of a set of callable methods, and some API endpoints.
To perform an action using the Flickr API, you need to select a calling convention, send a request to its endpoint specifying a method and some arguments, and will receive a formatted response.
  • All request formats, listed on the API index page, take a list of named parameters.
  • The REQUIRED parameter method is used to specify the calling method.
  • The REQUIRED parameter api_key is used to specify your API Key.
  • The optional parameter format is used to specify a response format.
  • The arguments, responses and error codes for each method are listed on the method's spec page. Methods are lists on the API index page.
Note: The Flickr API exposes identifiers for users, photos, photosets and other uniquely identifiable objects. These IDs should always be treated as opaque strings, rather than integers of any specific type. The format of the IDs can change over time, so relying on the current format may cause you problems in the future.

Endpoints

https://api.flickr.com/services
http://api.flickr.com/services
Note : The Flickr API expects all data to be UTF-8 encoded.Checks are made for valid UTF-8 sequences. If an invalid sequence is found, the data is presumed to be ISO-8859-1 and converted accordingly to UTF-8.Sending data in any other encoding will result in garbage into Flickr. It won't be dangerous garbage (we will always store valid UTF-8) but it will still be garbage.

User Authentication

Many of Flickr’s API methods require the user to be signed in. In the past we were using our own authentication API, but now, users should only be authenticated using the OAuth specification which is the industry standard. By using the OAuth standard you will provide in your applications a secure way for people to sign-in into their Flickr accounts with all the different account types Flickr is supporting (Yahoo! ID, Google ID, Facebook). Flickr’s OAuth flows work for web-applications, desktop apps and mobile applications as well.


Using OAuth with Flickr

What is OAuth?

OAuth is an open, simple, and secure protocol that enables applications to authenticate users and interact with Flickr on their behalf. The end user's information is securely transferred without revealing the identity of the user. At Flickr, we use OAuth to verify that an application trying to interact with Flickr on your behalf is doing so only with the permissions you have granted it.
The simplest way to get started with OAuth is to use a library with your programming language. To find a library for your programming language, visit the OAuth Code page.
The OAuth flow has 3 steps:


Below is the Flickr OAuth Authorization Flow




Flickr provides different methods for authenticating your application depending on your deployment environment. For each method/environment, Flickr needs to know different information.

Web application and Callback URL

To use web authentication:
  1. Direct the user to a Flickr page; the exact URL is created using the API.
  2. The user will authorize your application on Flickr; or Flickr will remember an old authorization.
  3. Flickr redirects the user to your callback URL; the frob is sent as a GET attribute.

Flickr provide Flickr Services for outside developers to access Flickr photos using Flickr APIs. It's a example to query Flick using Flickr API. In order to make it simple, only ONE photo per page is request.


Signing Requests

First, you must create a base string from your request. The base string is constructed by concatenating the HTTP verb, the request URL, and all request parameters sorted by name, using lexicograhpical byte value ordering, separated by an '&'.
Use the base string as the text and the key is the concatenated values of the Consumer Secret and Token Secret, separated by an '&'.
  1. For example, using the following URL:
http://www.flickr.com/services/oauth/request_token
?oauth_nonce=89601180
&oauth_timestamp=1305583298
&oauth_consumer_key=653e7a6ecc1d528c516cc8f92cf98611
&oauth_signature_method=HMAC-SHA1
&oauth_version=1.0
&oauth_callback=http%3A%2F%2Fwww.example.com

Would have a base string that looks like the following:

GET&http%3A%2F%2Fwww.flickr.com%2Fservices%2Foauth%2Frequest_token&oauth_callback%3Dhttp%253A%252F%252Fwww.example.com%26oauth_consumer_key%3D653e7a6ecc1d528c516cc8f92cf98611%26oauth_nonce%3D95613465%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1305586162%26oauth_version%3D1.0
Which would generate the following signature:


7w18YS2bONDPL%2FzgyzP5XTr5af4%3D
Getting a Request Token


Request Token URL:

http://www.flickr.com/services/oauth/request_token

The first step to obtaining authorization for a user is to get a Request Token using your Consumer Key. This is a temporary token that will be used to authenticate the user to your application. This token, along with a token secret, will later be exchanged for an Access Token.

The following is an example URL request for a request token:

http://www.flickr.com/services/oauth/request_token
?oauth_nonce=95613465
&oauth_timestamp=1305586162
&oauth_consumer_key=653e7a6ecc1d528c516cc8f92cf98611
&oauth_signature_method=HMAC-SHA1
&oauth_version=1.0
&oauth_signature=7w18YS2bONDPL%2FzgyzP5XTr5af4%3D
&oauth_callback=http%3A%2F%2Fwww.example.com

Flickr returns a response similar to the following:


oauth_callback_confirmed=true
&oauth_token=72157626737672178-022bbd2f4c2f3432
&oauth_token_secret=fccb68c4e6103197


Getting the User Authorization

User Authorization URL:

http://www.flickr.com/services/oauth/authorize

After getting the Request Token, your application needs to present the Flickr authorization page to the user, where they will be asked to give permission to your application to access their data.
Additionally, you can pass the optional
After authorization is complete, Flickr will redirect the user back to your application using the oauth_callback specified with your Request Token.

The following is an example authorization URL:

http://www.flickr.com/services/oauth/authorize
?oauth_token=72157626737672178-022bbd2f4c2f3432

The following is an example callback after authorization:


http://www.example.com/
?oauth_token=72157626737672178-022bbd2f4c2f3432
&oauth_verifier=5d1b96a26b494074


Exchanging the Request Token for an Access Token

Access Token URL:

http://www.flickr.com/services/oauth/access_token

After the user authorizes your application, you can exchange the approved Request Token for an Access Token. This Access Token should be stored by your application, and used to make authorized requests to Flickr.

The following is an example of a request for an Access Token:

http://www.flickr.com/services/oauth/access_token
?oauth_nonce=37026218
&oauth_timestamp=1305586309
&oauth_verifier=5d1b96a26b494074
&oauth_consumer_key=653e7a6ecc1d528c516cc8f92cf98611
&oauth_signature_method=HMAC-SHA1
&oauth_version=1.0
&oauth_token=72157626737672178-022bbd2f4c2f3432
&oauth_signature=UD9TGXzrvLIb0Ar5ynqvzatM58U%3D

Flickr returns a response similar to the following:


fullname=Jamal%20Fanaian
&oauth_token=72157626318069415-087bfc7b5816092c
&oauth_token_secret=a202d1f853ec69de
&user_nsid=21207597%40N07
&username=jamalfanaian


Calling the Flickr API with OAuth

After an Access Token has been granted to your application, you can make authenticated requests to the Flickr API. Flickr requires HMAC-SHA1 encryption because all requests are being made insecurely using HTTP.

The following is an example of a request made to the flickr.test.login API:

http://api.flickr.com/services/rest
?nojsoncallback=1 &oauth_nonce=84354935
&format=json
&oauth_consumer_key=653e7a6ecc1d528c516cc8f92cf98611
&oauth_timestamp=1305583871
&oauth_signature_method=HMAC-SHA1
&oauth_version=1.0
&oauth_token=72157626318069415-087bfc7b5816092c
&oauth_signature=dh3pEH0Xk1qILr82HyhOsxRv1XA%3D
&method=flickr.test.login

Flickr returns a response similar to the following:

{"user":{"id":"21207597@N07", "username":{"_content":"jamalfanaian"}}, "stat":"ok"}
The URL is:
FlickrQuery_url = "http://api.flickr.com/services/rest/?method=flickr.photos.search&per_page=1&nojsoncallback=1&format=json&tags=<search>&api_key=<API KEY>

where:
<search> - is the search word, (don't insert SPACE in this exercise!)
<API KEY> -  is your API Key


In order to access Flickr API, you have to apply your own API key at www.flickr.com/services/apps/create/apply/?.

The example access the API via HttpClient, using HttpGet() method.


public class AndroidFlickrActivity extends Activity {
String FlickrQuery_url = "http://api.flickr.com/services/rest/?method=flickr.photos.search";
String FlickrQuery_per_page = "&per_page=1";
String FlickrQuery_nojsoncallback = "&nojsoncallback=1";
String FlickrQuery_format = "&format=json";
String FlickrQuery_tag = "&tags=";
String FlickrQuery_key = "&api_key=";

// Apply your Flickr API:
// www.flickr.com/services/apps/create/apply/?
String FlickrApiKey = "2155e9406043b7494453105eec99ae37";
EditText searchText;
   Button searchButton;
   TextView textQueryResult, textJsonResult;
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);
       searchText = (EditText)findViewById(R.id.searchtext);
       searchButton = (Button)findViewById(R.id.searchbutton);
       textQueryResult = (TextView)findViewById(R.id.queryresult);
       textJsonResult = (TextView)findViewById(R.id.jsonresult);
       searchButton.setOnClickListener(searchButtonOnClickListener);

   }
   private Button.OnClickListener searchButtonOnClickListener
           = new Button.OnClickListener(){
          public void onClick(View arg0) {
            String searchQ = searchText.getText().toString();
            String searchResult = QueryFlickr(searchQ);
            textQueryResult.setText(searchResult);
           String jsonResult = ParseJSON(searchResult);
           textJsonResult.setText(jsonResult);

     }};
   private String QueryFlickr(String q){
            String qResult = null;
    String qString =FlickrQuery_url + FlickrQuery_per_page+ FlickrQuery_nojsoncallback+ FlickrQuery_format+ FlickrQuery_tag + q + FlickrQuery_key + FlickrApiKey;
    HttpClient httpClient = new DefaultHttpClient();
      HttpGet httpGet = new HttpGet(qString);
       try {
          HttpEntity httpEntity = httpClient.execute(httpGet).getEntity();
  if (httpEntity != null){
   InputStream inputStream = httpEntity.getContent();
   Reader in = new InputStreamReader(inputStream);
   BufferedReader bufferedreader = new BufferedReader(in);
   StringBuilder stringBuilder = new StringBuilder();
   String stringReadLine = null;
   while ((stringReadLine = bufferedreader.readLine()) != null)                     {
    stringBuilder.append(stringReadLine + "\n");
    }
   qResult = stringBuilder.toString();
  }
 } catch (ClientProtocolException e) {
  e.printStackTrace();

 } catch (IOException e) {
  e.printStackTrace();
 }
       return qResult;
    }

   private String ParseJSON(String json){

    String jResult = null;
    try {

  JSONObject JsonObject = new JSONObject(json);
  JSONObject Json_photos = JsonObject.getJSONObject("photos");
  JSONArray JsonArray_photo = Json_photos.getJSONArray("photo");
  //We have only one photo in this exercise
  JSONObject FlickrPhoto = JsonArray_photo.getJSONObject(0);
  jResult = "\nid: " + FlickrPhoto.getString("id") + "\n"

    + "owner: " + FlickrPhoto.getString("owner") + "\n"
    + "secret: " + FlickrPhoto.getString("secret") + "\n"
    + "server: " + FlickrPhoto.getString("server") + "\n"
    + "farm: " + FlickrPhoto.getString("farm") + "\n"
    + "title: " + FlickrPhoto.getString("title") + "\n";
 } catch (JSONException e) {
  e.printStackTrace();

 }
    return jResult;
  }
}

Here is the layout code:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 >
<TextView
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="@string/hello"
 />
<EditText
 android:id="@+id/searchtext"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 />
<Button
 android:id="@+id/searchbutton"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="Search"
 />
<TextView
 android:id="@+id/queryresult"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 />
</LinearLayout>

You need to grant permission of "android.permission.INTERNET".


Output:







References:

  • http://www.flickr.com/services/developer/ 
  • http://android-er.blogspot.in/2011/07/access-flickr-api-using-httpclient.html 
  • https://code.google.com/p/flickrj-android/ 
  • http://www.flickr.com/services/developer/api/ 
  • http://www.flickr.com/groups/api/discuss/72157624166264367/ 
  • https://code.google.com/p/flickr-viewer-for-honeycomb/source/checkout 
  • https://github.com/luminousman/Flickr 
  • http://blog.theunical.com/java/flickr-example-to-upload-photos-using-java/ 

Monday, 2 December 2013

How to make Text flow around images in TextView(api8) like webpage?

Hello Friends,

Today i am going to show you how the Text in TextView flow around the Image in Android.
This example will help you use the space under the picture, which is usually empty.
Starting from api 8 (Android 2.2) has a new interface LeadingMarginSpan2, which lets you create text indent for the first N rows. The picture created indented 50 pixels for the first 3 rows.

First of create an application in android and create the layout as below:

main.xml
 <?xml version="1.0" encoding="UTF-8"?>  
 <RelativeLayout  
 xmlns:android="http://schemas.android.com/apk/res/android"  
  android:layout_width="match_parent"  
  android:layout_height="wrap_content"  
  android:padding="5dp">  
  <TextView  
  android:textSize="18.0sp"  
  android:id="@+id/message_view"  
  android:layout_width="match_parent"  
  android:layout_height="wrap_content"  
  android:text="@string/text" />  
  <ImageView  
  android:layout_width="wrap_content"  
  android:layout_height="wrap_content"  
  android:id="@+id/icon" />  
 </RelativeLayout>  

After creating the layout in your MainActivity.java file create a class MyLeadingMarginSpan2 which extends a LeadingMarginSpan2 interface as below:
 class MyLeadingMarginSpan2 implements LeadingMarginSpan2 {  
     private int margin;  
     private int lines;  
     MyLeadingMarginSpan2(int lines, int margin) {  
       this.margin = margin;  
       this.lines = lines;  
     }  
    /*Returns the value to which must be added indentation*/  
     @Override  
     public int getLeadingMargin(boolean first) {  
       if (first) {  
        / *This * indentation is applied to the number of          rows returned * getLeadingMarginLineCount ()*/   
       return margin;  
       }  
      else  
      {  
     //Offset for all other Layout layout ) { }  
     /*Returns * the number of rows which should be applied *     indent returned by getLeadingMargin (true)   
     * Note:* Indent only applies to N lines of the first paragraph.*/   
       return 0;  
       }  
     }  
     @Override  
     public void drawLeadingMargin(Canvas c, Paint p, int x, int dir,  
         int top, int baseline, int bottom, CharSequence text,   
         int start, int end, boolean first, Layout layout) {}  
   @Override  
     public int getLeadingMarginLineCount() {  
       return lines;  
     }  
   };  

In OnCreate, create an object SpannableString and apply a new style.
 @Override  
 Public void onCreate ( Bundle savedInstanceState )   
 {  
     super . onCreate ( savedInstanceState ) ;  
     setContentView ( R. layout . main ) ;   
   String text = getString ( R. string . text ) ;   
   // Get the icon and its width  
   Drawable DICON = getResources ( ).getDrawable(R.drawable.icon);   
   int = leftMargin DICON. getIntrinsicWidth ( ) + 10 ;   
   //Set the icon in R.id.icon   
    ImageView icon =(ImageView)findViewById(R.ID.icon ) ;  
    icon.setBackgroundDrawable (DICON) ;  
   SpannableString SS = New SpannableString (text);   
   //Expose the indent for the first three rows  
    SS.setSpan(New MyLeadingMarginSpan2(3,leftMargin),0,SS.length(),0);  
    TextView MessageView = ( TextView ) findViewById ( R. ID . message_view ) ;  
     MessageView. setText ( SS ) ;   
 }  

Output:





Monday, 25 November 2013

Different ways to handle Click Events in Android

Android: OnClickListener Ways

Overview:

            Android provides Delegate Event Model to handle the click events in different ways.  An Android View in an App will fire an event in response to user or code interaction. The application will not respond to the event unless it is listening for it. To detect the event a class that implements a listener is instantiated and assigned to the View.

          

                There are pros and cons for each method and experienced developers will advocate a particular method over others. But not one of the methods can be regarded as the must do way. Developers need to be familiar with the different ways to code event handlers, they they will come across the different methods in tutorials, samples and online snippets.

             In Event Delegation Model when a View fires an event an Application will not respond to it unless it is listening for it. To detect the event a class that implements a listener is instantiated and assigned to the View. 

       Take for example the onClick event, the most widely used event in Android Apps. Nearly every View that can be added to an App screen will fire the event when the user stabs it with their finger (on touch screens) or presses the trackpad/trackball when the View has focus. This event is listened to by a class implementing the OnClickListener interface. 

The class instance is then assigned to the required View using the View's setOnClickListener method. 

There are different ways of handling the Click event in android.

  1. Member Class
  2. Interface Type
  3. Anonymous Inner Class (Inline method)
  4. Implementation in Activity
  5. Attribute in View Layout for OnClick Events

Below are the implementation ways:

           1. Member Class

         A class called HandleClick implementing OnClickListener is declared as a member of the Activity (MainActivity). This is useful when several listeners require similar processing than can be handled by a single class.

public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //attach an instance of HandleClick to the Button
        findViewById(R.id.button1).setOnClickListener(new HandleClick());
    }    
    private class HandleClick implements OnClickListener{
        public void onClick(View arg0) {
     Button btn = (Button)arg0; //cast view to a button
     // get a reference to the TextView
     TextView tv = (TextView) findViewById(R.id.textview1);
     // update the TextView text
     tv.setText("You have pressed " + btn.getText());
 }
    }
}

    2. Interface Type 
            
              In Java an Interface can be used as a type, a variable is declared as an OnClickListener and assigned using new OnClickListener(){...}, behind the scenes Java is creating an object (an Anonymous Class) that implements OnClickListener. This has similar benefits to the first method.

public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //use the handleClick variable to attach the event listener
        findViewById(R.id.button1).setOnClickListener(handleClick);
    }    
    private OnClickListener handleClick = new OnClickListener(){
        public void onClick(View arg0) {
     Button btn = (Button)arg0;
     TextView tv = (TextView) findViewById(R.id.textview1);
     tv.setText("You have pressed " + btn.getText());
 }
    };
}

  3. Anonymous Inner Class (Inline method)

           Declaring the OnClickListener within the call to the setOnClickListener method is common. This method is useful when each listener does not have functionality that could be shared with other listeners. Some novice developers find this type of code difficult to understand. This method is very quick but does leave a bit of a mess. I Would only recommend using this for small blocks of code.Again behind the scenes for new OnClickListener(){...} . Java is creating an object that implements the interface.

public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        findViewById(R.id.button1).setOnClickListener(new OnClickListener(){
            public void onClick(View arg0) {
      Button btn = (Button)arg0;
      TextView tv = (TextView) findViewById(R.id.textview1);
      tv.setText("You have pressed " + btn.getText());
         }
        });
    }     
}


4. Implementation in Activity

        The Activity itself can implement the OnClickListener. Since the Activity object (MainActivity) already exists this saves a small amount of memory by not requiring another object to host the onClickmethod. It does make public a method that is unlikely to be used elsewhere. Implementing multiple events will make the declaration of main long.

public class MainActivity extends Activity implements OnClickListener{
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        findViewById(R.id.button1).setOnClickListener(this);
    }    
    public void onClick(View arg0) {
 Button btn = (Button)arg0;
 TextView tv = (TextView) findViewById(R.id.textview1);
 tv.setText("You have pressed " + btn.getText());
    }
}


5. Attribute in View Layout for OnClick Events

            In Android 1.6 and later (API level 4 and upwards) the name of a method defined in the Activity can be assigned to the android:onClick attribute in a layout file. This can save writing a lot of boilerplate code.

public class MainActivity extends Activity{
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }    
    public void HandleClick(View arg0) {
 Button btn = (Button)arg0;
        TextView tv = (TextView) findViewById(R.id.textview1);
 tv.setText("You have pressed " + btn.getText());
    }
}


In the layout file the Button would be declared with the android:onClick attribute.

<Button android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button 1"
        android:onClick="HandleClick"/>


    The first four methods of handling events can be used with other event types (onLongClick, onKey, onTouch, onCreateContextMenu, onFocusChange). The fifth method only applies to the onClick event. The layout file below declares an additional two buttons and using the android:onClick attribute no additional code is required than that defined above, i.e. no additional findViewById and setOnClickListener for each button is required.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
  <TextView android:id="@+id/textview1"
            android:layout_width="fill_parent" 
            android:layout_height="wrap_content" 
            android:text="Click a button."
            android:textSize="20dp"/>
  <LinearLayout android:orientation="horizontal"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content">
    <Button android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button 1"
            android:onClick="HandleClick"/>             
    <Button android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button 2"
            android:onClick="HandleClick"/>
    <Button android:id="@+id/button3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Button 3"
            android:onClick="HandleClick"/>
  </LinearLayout>      
</LinearLayout>


Conclusion

Deciding which technique to use to wire up a listener will depend on the functionality required, how much code is reusable across Views and how easy the code would be to understand by future maintainers. Ideally the code should be sufficient and easy to view.

    One method not shown here is similar to the first method. In the first method it would be possible to save the listener class in a different class file as a public class. Then instances of that public class could be used by other Activities, passing the Activity's context in via the constructor. However, Activities should try and stay self contained in case they are killed by Android. Sharing listeners across Activities is against the ideals of the Android platform and could lead to unnecessary complexity passing references between the public classes.

Monday, 18 November 2013

Drag and Drop Feature in Android 3.0

Overview


QuickView (Highlighting Features)
  • Allow users to move data within your Activity layout using graphical gestures.
  • Supports operations besides data movement.
  • Only works within a single application.
  • Requires API 11.
            A drag and drop operation starts when the user makes some gesture that you recognize as a signal to start dragging data. In response, your application tells the system that the drag is starting. The system calls back to your application to get a representation of the data being dragged. As the user's finger moves this representation (a "drag shadow") over the current layout, the system sends drag events to the drag event listener objects and drag event callback methods associated with the View objects in the layout. Once the user releases the drag shadow, the system ends the drag operation.
You create a drag event listener object ("listeners") from a class that implements View.OnDragListener. You set the drag event listener object for a View with the View object'ssetOnDragListener() method. Each View object also has aonDragEvent() callback method.
When you start a drag, you include both the data you are moving and metadata describing this data as part of the call to the system. During the drag, the system sends drag events to the drag event listeners or callback methods of each View in the layout. The listeners or callback methods can use the metadata to decide if they want to accept the data when it is dropped.


The Drag/Drop process


There are basically four steps or states in the drag and drop process:

Started
      In response to the user's gesture to begin a drag, your application calls startDrag() to tell the system to start a drag. The arguments startDrag() provide the data to be dragged, metadata for this data, and a callback for drawing the drag shadow.The system first responds by calling back to your application to get a drag shadow. It then displays the drag shadow on the device.

        Next, the system sends a drag event with action type ACTION_DRAG_STARTED to the drag event listeners for all the View objects in the current layout. To continue to receive drag events, including a possible drop event, a drag event listener must return true. This registers the listener with the system. Only registered listeners continue to receive drag events. At this point, listeners can also change the appearance of their View object to show that the listener can accept a drop event.

Continuing
           The user continues the drag. As the drag shadow intersects the bounding box of a View object, the system sends one or more drag events to the View object's drag event listener (if it is registered to receive events). The listener may choose to alter its View object's appearance in response to the event. For example, if the event indicates that the drag shadow has entered the bounding box of the View (action type ACTION_DRAG_ENTERED), the listener can react by highlighting its View.



Dropped
            The user releases the drag shadow within the bounding box of a View that can accept the data. The system sends the View object's listener a drag event with action type ACTION_DROP. The drag event contains the data that was passed to the system in the call to startDrag() that started the operation. The listener is expected to return boolean true to the system if code for accepting the drop succeeds.


Note: This step only occurs if the user drops the drag shadow within the bounding box of a View whose listener is registered to receive drag events. If the user releases the drag shadow in any other situation, noACTION_DROP drag event is sent.

Ended
          After the user releases the drag shadow, and after the system sends out (if necessary) a drag event with action type ACTION_DROP, the system sends out a drag event with action type ACTION_DRAG_ENDEDto indicate that the drag operation is over. This is done regardless of where the user released the drag shadow. The event is sent to every listener that is registered to receive drag events, even if the listener received the ACTION_DROP event.

Technical Points:
          While the view is getting dragged on screen, system generates DragEvents which can be intercepted by application by setting View.setOnDragListener().


          OnDragListener interface has callback method public boolean onDrag(View view, DragEvent dragEvent) which will get called whenever any view is dragged or dropped.The DragEvent parameter provides getAction() which tells the application which type of action has occurred.


Following types of action can be identified.

DragEvent.ACTION_DRAG_STARTED – Drag event has started.
DragEvent.ACTION_DRAG_ENTERED – Drag has brought the drop shadow in view bounds.
DragEvent.ACTION_DRAG_EXITED – Drag has taken the drop shadow out of view bounds.
DragEvent.ACTION_DRAG_LOCATION – Drag is happening and drop shadow is inside view bounds.
DragEvent.ACTION_DROP – Drop has happened inside view bounds.
DragEvent.ACTION_DRAG_ENDED – Drop has happened outside view bounds.

Create and Design the App


Create a new Android project in Eclipse. Enter the application settings of your choice, being sure to create a blank Activity and layout for it.First of all create a layout file for the activity as below:

activity_drag_drop.xml
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
   android:layout_width="fill_parent"  
   android:layout_height="wrap_content"  
   android:orientation="vertical"  
   android:padding="10dp"  
   android:paddingLeft="50dp"  
   android:paddingRight="50dp" >  
   <TextView  
     android:layout_width="fill_parent"  
     android:layout_height="wrap_content"  
     android:gravity="center"  
     android:paddingBottom="10dp"  
     android:text="Place these foods in your order of preference." />  
   <TextView  
     android:id="@+id/option_1"  
     android:layout_width="fill_parent"  
     android:layout_height="wrap_content"  
     android:layout_margin="5dp"  
     android:background="@drawable/option"  
     android:gravity="center"  
     android:text="Apple"  
     android:textStyle="bold" />  
   <TextView  
     android:id="@+id/option_2"  
     android:layout_width="fill_parent"  
     android:layout_height="wrap_content"  
     android:layout_margin="5dp"  
     android:background="@drawable/option"  
     android:gravity="center"  
     android:text="Cake"  
     android:textStyle="bold" />  
   <TextView  
     android:id="@+id/option_3"  
     android:layout_width="fill_parent"  
     android:layout_height="wrap_content"  
     android:layout_margin="5dp"  
     android:background="@drawable/option"  
     android:gravity="center"  
     android:text="Orange"  
     android:textStyle="bold" />  
   <TextView  
     android:id="@+id/choice_1"  
     android:layout_width="fill_parent"  
     android:layout_height="wrap_content"  
     android:layout_margin="5dp"  
     android:background="@drawable/choice"  
     android:gravity="center"  
     android:text="Most Favourite" />  
   <TextView  
     android:id="@+id/choice_2"  
     android:layout_width="fill_parent"  
     android:layout_height="wrap_content"  
     android:layout_margin="5dp"  
     android:background="@drawable/choice"  
     android:gravity="center"  
     android:text="---" />  
   <TextView  
     android:id="@+id/choice_3"  
     android:layout_width="fill_parent"  
     android:layout_height="wrap_content"  
     android:layout_margin="5dp"  
     android:background="@drawable/choice"  
     android:gravity="center"  
     android:text="Not Favourite" />  
 </LinearLayout>  

Below are the xml's of choice & options which are used to set in TextView. Put it in “res/drawables” folder

option.xml
 <?xml version="1.0" encoding="utf-8"?>  
 <shape xmlns:android="http://schemas.android.com/apk/res/android"  
   android:dither="true" >  
   <solid android:color="#ff00ccff" />  
   <corners android:radius="2dp" />  
   <stroke  
     android:width="2dp"  
     android:color="#ff0099cc" />  
   <padding  
     android:bottom="5dp"  
     android:left="10dp"  
     android:right="10dp"  
     android:top="5dp" />  
 </shape>  

choice.xml
 <?xml version="1.0" encoding="utf-8"?>  
 <shape xmlns:android="http://schemas.android.com/apk/res/android"  
 android:dither="true" >  
    <solid android:color="#ffffff99" />  
    <corners android:radius="2dp" />  
    <stroke  
      android:dashGap="4dp"  
      android:dashWidth="2dp"  
      android:width="2dp"  
      android:color="#ffffff00" />  
   <padding  
     android:bottom="5dp"  
     android:left="5dp"  
     android:right="5dp"  
     android:top="5dp" />  
 </shape>  

Here is the activity code DragDropActivity.java
 import android.os.Bundle;  
 import android.app.Activity;  
 import android.content.ClipData;  
 import android.graphics.Typeface;  
 import android.view.DragEvent;  
 import android.view.MotionEvent;  
 import android.view.View;  
 import android.view.View.DragShadowBuilder;  
 import android.view.View.OnDragListener;  
 import android.view.View.OnTouchListener;  
 import android.widget.TextView;  
 public class DragDropActivity extends Activity {  
  //text views being dragged and dropped onto  
  private TextView option1, option2, option3, choice1, choice2, choice3;  
  @Override  
  protected void onCreate(Bundle savedInstanceState) {  
  super.onCreate(savedInstanceState);  
  setContentView(R.layout.activity_drag_drop);  
  //get both sets of text views  
  //views to drag  
  option1 = (TextView)findViewById(R.id.option_1);  
  option2 = (TextView)findViewById(R.id.option_2);  
  option3 = (TextView)findViewById(R.id.option_3);  
  //views to drop onto  
  choice1 = (TextView)findViewById(R.id.choice_1);  
  choice2 = (TextView)findViewById(R.id.choice_2);  
  choice3 = (TextView)findViewById(R.id.choice_3);  
  //set touch listeners  
  option1.setOnTouchListener(new ChoiceTouchListener());  
  option2.setOnTouchListener(new ChoiceTouchListener());  
  option3.setOnTouchListener(new ChoiceTouchListener());  
  //set drag listeners  
  choice1.setOnDragListener(new ChoiceDragListener());  
  choice2.setOnDragListener(new ChoiceDragListener());  
  choice3.setOnDragListener(new ChoiceDragListener());  
  }  
  /**  
  * ChoiceTouchListener will handle touch events on draggable views  
  *  
  */  
  private final class ChoiceTouchListener implements OnTouchListener {  
  public boolean onTouch(View view, MotionEvent motionEvent) {  
   if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {  
   /*  
    * Drag details: we only need default behavior  
    * - clip data could be set to pass data as part of drag  
    * - shadow can be tailored  
    */  
   ClipData data = ClipData.newPlainText("", "");  
   DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);  
   //start dragging the item touched  
   view.startDrag(data, shadowBuilder, view, 0);  
   return true;  
   } else {  
   return false;  
   }  
  }  
  }   
  /**  
  * DragListener will handle dragged views being dropped on the drop area  
  * - only the drop action will have processing added to it as we are not  
  * - amending the default behavior for other parts of the drag process  
  *  
  */  
  private class ChoiceDragListener implements OnDragListener {  
  @Override  
  public boolean onDrag(View v, DragEvent event) {  
   switch (event.getAction()) {  
   case DragEvent.ACTION_DRAG_STARTED:  
   //no action necessary  
   break;  
   case DragEvent.ACTION_DRAG_ENTERED:  
   //no action necessary  
   break;  
   case DragEvent.ACTION_DRAG_EXITED:      
   //no action necessary  
   break;  
   case DragEvent.ACTION_DROP:  
   //handle the dragged view being dropped over a drop view  
   View view = (View) event.getLocalState();  
   //stop displaying the view where it was before it was dragged  
   view.setVisibility(View.INVISIBLE);  
   //view dragged item is being dropped on  
   TextView dropTarget = (TextView) v;  
   //view being dragged and dropped  
   TextView dropped = (TextView) view;  
   //update the text in the target view to reflect the data being dropped  
   dropTarget.setText(dropped.getText());  
   //make it bold to highlight the fact that an item has been dropped  
   dropTarget.setTypeface(Typeface.DEFAULT_BOLD);  
   //if an item has already been dropped here, there will be a tag  
   Object tag = dropTarget.getTag();  
   //if there is already an item here, set it back visible in its original place  
   if(tag!=null)  
   {  
    //the tag is the view id already dropped here  
    int existingID = (Integer)tag;  
    //set the original view visible again  
    findViewById(existingID).setVisibility(View.VISIBLE);  
   }  
   //set the tag in the target view being dropped on - to the ID of the view being dropped  
   dropTarget.setTag(dropped.getId());  
   break;  
   case DragEvent.ACTION_DRAG_ENDED:  
   //no action necessary  
   break;  
   default:  
   break;  
   }  
   return true;  
  }  
  }   
 }  


Output:






Thanks.
Enjoy.