Showing posts with label android. Show all posts
Showing posts with label android. Show all posts

Monday, April 9, 2012

Handle defaulthttpclient redirects manually

By default DefaultHttpClient will handle redirect automatically. Sometimes we need to handle this manually, mainly if we need to set some parameters with every request.


We can do it by the following steps.
  1. Set HANDLE_REDIRECTS parameter value to false , that means it  defines redirects should be handled manually
HttpParams params = httpClient.getParams();
HttpClientParams.setRedirecting(params, false);
  1. Then after executing our request, if it is not HttpStatus.SC_OK or when response codes between 300 and 399 ( redirect responses )
    • Gets the values of the response header with the name as "Location"
    • the last value will be the new url where it need to redirect 
    • then execute the new request using the  redirect  url by setting the needed parameters
if (responseCode != HttpStatus.SC_OK) {
   Header[] headers = httpResponse.getHeaders("Location");
   if (headers != null && headers.length != 0) {
       String newUrl = headers[headers.length - 1].getValue();
     //Execute again with newUrl by setting the needed paramters
   }
}


My complete doHttpRequest method

private void doHttpRequest(String url){
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost request = new HttpPost(url);

        request.setParams(getHttpParams()); 
//getHttpParams is used to get the HttpParams 
//by setting all the required parameters

//Set HANDLE_REDIRECTS to false , 
//defines redirects should be handled manually
HttpParams params = httpClient.getParams();
HttpClientParams.setRedirecting(params, false);

HttpResponse httpResponse = 
httpClient.execute(request);

int responseCode = 
 httpResponse.getStatusLine().getStatusCode();


if (responseCode != HttpStatus.SC_OK) {
Header[] headers = 
httpResponse.getHeaders("Location");
if (headers != null && headers.length != 0) {
  //Need to redirect 
 String newUrl = 
    headers[headers.length - 1].getValue();

doHttpRequest(newUrl);
//call the doHttpRequest 
//recursively with new url
}
} else {
handleResponse(httpResponse);
}
}


Hope this help.
And please feel free to point out my mistakes... 

Saturday, November 5, 2011

Simple Content Provider for db operations

At last I concluded, it is ContentProvider which we need to use for database operation ..
Content Providers  
Content providers store and retrieve data and make it accessible to all applications. They're the only way to share data across applications; 

  • Yes content providers are mainly aimed to share data amount different application
  • It can be also used inside our single application
  • There is no worries of closing and locking of db
  • It can be accessed from different activities,  services and Thread. Anywhere that have context object
  • I don't know is this a bad idea, I don't think so. Don't think it will reduce our data security. Our data can be accessed only with our AUTHORITY url
When a request is made via a ContentResolver the system inspects the authority of the given URI and passes the request to the content provider registered with the authority.
Now I'm trying to demonstrate the way how we can use ContentProvider in most simple way...
ContentProviderDb.java

public class ContentProviderDb extends ContentProvider{
 OurDatabaseHelper dbHelper ;
 public static final String AUTHORITY = "ourContentProviderAuthorities";//specific for our our app, will be specified in maninfed 
 public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
 
 @Override
 public boolean onCreate() {
  dbHelper = new OurDatabaseHelper(getContext());
  return true;
 }

 @Override
 public int delete(Uri uri, String where, String[] args) {
  String table = getTableName(uri);
     SQLiteDatabase dataBase=dbHelper.getWritableDatabase();
     return dataBase.delete(table, where, args);
 }

 @Override
 public String getType(Uri arg0) {
  // TODO Auto-generated method stub
  return null;
 }

 
 @Override
 public Uri insert(Uri uri, ContentValues initialValues) {
  String table = getTableName(uri);
  SQLiteDatabase database = dbHelper.getWritableDatabase();
  long value = database.insert(table, null, initialValues);
  return Uri.withAppendedPath(CONTENT_URI, String.valueOf(value));
 }

 @Override
 public Cursor query(Uri uri, String[] projection, String selection,
      String[] selectionArgs, String sortOrder) {
  String table =getTableName(uri);
  SQLiteDatabase database = dbHelper.getReadableDatabase();
  Cursor cursor =database.query(table,  projection, selection, selectionArgs, null, null, sortOrder);
     return cursor;
 }  

 @Override
 public int update(Uri uri, ContentValues values, String whereClause,
      String[] whereArgs) {
  String table = getTableName(uri);
  SQLiteDatabase database = dbHelper.getWritableDatabase();  
  return database.update(table, values, whereClause, whereArgs);
 }
 
 public static String getTableName(Uri uri){
  String value = uri.getPath();
  value = value.replace("/", "");//we need to remove '/'
  return value;
 }
}

Here OurDatabaseHelper is the database helper class (extends SQLiteOpenHelper )
getTableName is used to get the specific Table name

Don't forget to add this in your manifest.xml file
<provider android:authorities="ourContentProviderAuthorities"
 android:name=".ContentProviderDb">
We specify our AUTHORITY as android:authorities

So the db operation will be like this:

Uri contentUri = Uri.withAppendedPath(ContentProviderDb.CONTENT_URI, "TableName");
Using these contentUri we are specifying our table where we need to perform our operation

We can perform db operation using our context

context.getContentResolver().insert(.....);
context.getContentResolver().query(.....);
context.getContentResolver().delete(.....);
context.getContentResolver().update(.....);


And if you are inside an activity class

getContentResolver().insert(.....);
getContentResolver().query(.....);
getContentResolver().delete(.....);
getContentResolver().update(.....);

For an example an insert operation will look like this

ContentValues initialValues = new ContentValues();
initialValues.put("Column", "value");
Uri contentUri = Uri.withAppendedPath(ContentProviderDb.CONTENT_URI, "TableName");
Uri resultUri = context.getContentResolver().insert(contentUri, initialValues);

Hope this help.
And please feel free to point out my mistakes... 

Sunday, September 25, 2011

Sending Multiple file attached email in android

Sending Multiple file attached email in android  ,

public boolean sendEmailWithMultipleAttachments(Context context,
	String[] emailTo, String[] emailCC, String[] emailBCC,
	String subject, String emailBody, List filePaths) throws ActivityNotFoundException {
		
final Intent emailIntent = 
            new Intent(android.content.Intent.ACTION_SEND_MULTIPLE);
emailIntent.setType("message/rfc822");
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, emailTo);
emailIntent.putExtra(android.content.Intent.EXTRA_CC, emailCC);
emailIntent.putExtra(android.content.Intent.EXTRA_BCC, emailBCC);
emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
emailIntent.putExtra(Intent.EXTRA_TEXT, emailBody);

if (filePaths != null) {
         // has to be an ArrayList
	ArrayList uris = new ArrayList();
	// convert from paths to Android friendly Parcelable Uri's
	for (String file : filePaths) {
		File fileIn = new File(file);
			if (fileIn.exists()) {
				Uri u = Uri.fromFile(fileIn);
			        uris.add(u);
			}
		}
		emailIntent.putParcelableArrayListExtra
                                         (Intent.EXTRA_STREAM, uris);
	}
	context.startActivity(Intent.createChooser(emailIntent, "Sent mail"));
	return true;
	}

filePaths is list, which store the local path of file which we need to attach
eg
filePaths.add("/sdcard/test.pdf");

Get mime type of a file


In android to get mime type is very easy...

To find the mime type of a file, path

String extention =  path.substring(path.lastIndexOf(.) );
String mimeTypeMap =MimeTypeMap.getFileExtensionFromUrl(extention);
String mimeType = MimeTypeMap.getSingleton()
                        .getMimeTypeFromExtension(mimeTypeMap);

Saturday, April 16, 2011

Using Fragment of Android Compatibility Package

The Android 3.0 introduce a awesome feature Fragment.
It really helpful when we design for tablet. You can refer The Android 3.0 Fragment API   for more details
Here I'm going to explain how to use Fragment for lower version.
Now android had released a static library that exposes the same Fragments API, so that applications compatible with Android 1.6 or later can use fragments to create tablet-compatible user interfaces.

For this you need to do follow these steps
  • Add android-support-v4.jar to you project
    • You can found this jar at yoursdkpath/extras/android/compatibility/v4/
    • Copy this into your libs folder in the root of your project 
    • add this jar to your project build path
  • In order to use this you need to use FragmentActivity instead of Activity 
    • public class Home extends FragmentActivity
  • To get FragmentManager 
    • Need to use getSupportFragmentManager instead of getFragmentManage
The complete code will look like this

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
public class Home extends FragmentActivity{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
  Fragment productDetails = new MyFragment();
  fragmentTransaction.replace(R.id.mainFragement, productDetails);
  fragmentTransaction.commit();
    }
}
MyFragment.java

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class MyFragment extends Fragment{
 public MyFragment(){
  Log.i("MYEXPENSETRACKER","MyFragment ()");
 }
 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  TextView t = new TextView(getActivity());
  t.setText("From Fragement");
  return t;
 }
}

The main.xml I used

<?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"
    />
    
 <FrameLayout
  android:id="@+id/mainFragement"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">
 </FrameLayout>
</LinearLayout>

Hope it helped you..:)

Wednesday, April 13, 2011

Go back to previous activity

Its every common query how to go back to previous activity.
Most of us will finish activity or keep track of the activity stack and all.
But no need of this type of complex logic if you need just the same effect of user's back key press
You can use the android onBackPressed() method explicitly .

super.onBackPressed();

The default implementation simply finishes the current activity, but you can override this to do whatever you want.
The android implicitly call this method when the activity has detected the user's press of the back key.
So calling this explicitly will give the same effect 

Monday, March 28, 2011

In Android import xml into another xml

Its very common in the UI design that some common element appear many time.
Just like some common signature in all the activities (pages) and all.
Its common that we need to set some component as reusable component.

In this case we can use the <include /> tag. This element does exactly what its name suggest.
To use this is very simple
Declare the reusable component as one layout in the /res/layout, let say commonlayout.xml
Then where ever you need to refer this you can use the following code
<include android:id="@+id/id" layout="@layout/commonlayout"/>
Note that:
  • Here you can override all the layout parameters. This means that any android:layout_* attribute can be used with the <include /> tag
  •  If you want to override the layout dimensions, you must override both android:layout_height and android:layout_width you cannot override only the height or only the width. If you override only one, it will not take effect. (Other layout properties, such as weight, are still inherited from the source layout.)
Refer Creating Reusable UI Components



Monday, March 21, 2011

Pinch Zoom to view completely

Hope you have gone through my previous post Zooming a view completely 
Now to apply pinch zoom we need to override the OnTouchListener.
There are many blogs and code to do pinch zoom in image view me used that logic here
So my main activity class will be like this

public class PinchZoomLayout extends Activity {
 View mainView = null;

 // Remember some things for zooming
 PointF start = new PointF();
 PointF mid = new PointF();

 float oldDist = 1f;
 PointF oldDistPoint = new PointF();

 public static String TAG = "ZOOM";

 static final int NONE = 0;
 static final int DRAG = 1;
 static final int ZOOM = 2;
 int mode = NONE;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  mainView = (LinearLayout) findViewById(R.id.linearLayout);

  Button buttonZoomOut = (Button) findViewById(R.id.buttonZoomOut);
  Button buttonNormal = (Button) findViewById(R.id.buttonNormal);
  Button buttonZoomIn = (Button) findViewById(R.id.buttonZoomIn);

  buttonZoomOut.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    zoom(0.5f, 0.5f, new PointF(0, 0));
   }
  });
  buttonNormal.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    zoom(1f, 1f, new PointF(0, 0));
   }
  });
  buttonZoomIn.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    zoom(2f, 2f, new PointF(0, 0));
   }
  });

  mainView.setOnTouchListener(new OnTouchListener() {
   @Override
   public boolean onTouch(View v, MotionEvent event) {
    Log.d(TAG, "mode=DRAG");
    switch (event.getAction() & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN:
     start.set(event.getX(), event.getY());
     Log.d(TAG, "mode=DRAG");
     mode = DRAG;

     break;
    case MotionEvent.ACTION_POINTER_DOWN:
     oldDist = spacing(event);
     oldDistPoint = spacingPoint(event);
     Log.d(TAG, "oldDist=" + oldDist);
     if (oldDist > 10f) {
      midPoint(mid, event);
      mode = ZOOM;
      Log.d(TAG, "mode=ZOOM");
     }
     System.out.println("current time :" + System.currentTimeMillis());
     break;// return !gestureDetector.onTouchEvent(event);
    case MotionEvent.ACTION_UP:
    case MotionEvent.ACTION_POINTER_UP:
     Log.d(TAG, "mode=NONE");
     mode = NONE;
     break;
    case MotionEvent.ACTION_MOVE:
     if (mode == DRAG) {

     } else if (mode == ZOOM) {
      PointF newDist = spacingPoint(event);
      float newD = spacing(event);
      Log.e(TAG, "newDist=" + newDist);
      float[] old = new float[9];
      float[] newm = new float[9];
      Log.e(TAG, "x=" + old[0] + ":&:" + old[2]);
      Log.e(TAG, "y=" + old[4] + ":&:" + old[5]);
      float scale = newD / oldDist;
      float scalex = newDist.x / oldDistPoint.x;
      float scaley = newDist.y / oldDistPoint.y;
      zoom(scale, scale, start);
     }
     break;
    }
    return true;
   }
  });
 }

 /** 
  * zooming is done from here 
  */
 public void zoom(Float scaleX, Float scaleY, PointF pivot) {
  mainView.setPivotX(pivot.x);
  mainView.setPivotY(pivot.y);
  mainView.setScaleX(scaleX);
  mainView.setScaleY(scaleY);
 }

 /**
  * space between the first two fingers
  */
 private float spacing(MotionEvent event) {
  // ...
  float x = event.getX(0) - event.getX(1);
  float y = event.getY(0) - event.getY(1);
  return FloatMath.sqrt(x * x + y * y);
 }

 private PointF spacingPoint(MotionEvent event) {
  PointF f = new PointF();
  f.x = event.getX(0) - event.getX(1);
  f.y = event.getY(0) - event.getY(1);
  return f;
 }

 /**
  * the mid point of the first two fingers
  */
 private void midPoint(PointF point, MotionEvent event) {
  // ...
  float x = event.getX(0) + event.getX(1);
  float y = event.getY(0) + event.getY(1);
  point.set(x / 2, y / 2);
 }
}
 
But this zoom is not much smooth :(.

Zooming a view completely

Here I'm discussing how to zoom a complete view with different UI controls in it.
For this i used setScaleX and setScaleY.

mainView.setScaleX(scaleX);
mainView.setScaleY(scaleY);
 
This will Scale the the view in X and Y axis. A value of scale 1 means that no scaling is applied.
In order to work this correctly it need to specify the pivot point correctly. We can set our pivot point using setPivotX and setPivotY.

mainView.setPivotX(pivot.x);
mainView.setPivotY(pivot.y);
 
My complete code 

Main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:id="@+id/linearLayout"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent">
 <LinearLayout
  android:layout_width="wrap_content"
  android:orientation="horizontal"
  android:layout_height="wrap_content"
  android:id="@+id/linearLayout1">
  <Button
   android:text="Zoom In"
   android:id="@+id/buttonZoomIn"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content" />
  <Button
   android:text="Normal"
   android:id="@+id/buttonNormal"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content" />
  <Button
   android:text="Zoom Out"
   android:id="@+id/buttonZoomOut"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content" />
 </LinearLayout>
 <TextView
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text="@string/hello" />
 <ProgressBar
  android:id="@+id/progressBar"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" />
 <ImageView
  android:id="@+id/imageView"
  android:src="@drawable/honeycombdroid"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" />
 <LinearLayout
  android:layout_width="200dp"
  android:orientation="vertical"
  android:layout_height="wrap_content"
  android:id="@+id/linearLayout1">
  <EditText
   android:id="@+id/editText1"
   android:layout_height="wrap_content"
   android:text="EditText"
   android:layout_width="match_parent"></EditText>
  <EditText
   android:id="@+id/editText1"
   android:layout_height="wrap_content"
   android:text="EditText"
   android:layout_width="match_parent"></EditText>
  <Button
   android:text="Button"
   android:id="@+id/button2"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"></Button>
 </LinearLayout>
</LinearLayout>
 

Here me only use that three buttons
buttonZoomIn , buttonNormal and buttonZoomOut
Then My main activity class

public class ZoomLayout extends Activity {
 View mainView = null;
 
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  mainView =(LinearLayout)findViewById(R.id.linearLayout);
  
  Button buttonZoomOut = (Button)findViewById(R.id.buttonZoomOut);
  Button buttonNormal = (Button)findViewById(R.id.buttonNormal);
  Button buttonZoomIn = (Button)findViewById(R.id.buttonZoomIn);
  
  buttonZoomOut.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    zoom(0.5f,0.5f,new PointF(0,0));    
   }
  });
  buttonNormal.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    zoom(1f,1f,new PointF(0,0));  
   }
  });
  buttonZoomIn.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
    zoom(2f,2f,new PointF(0,0));   
   }
  });
 }
 
 /** zooming is done from here */
 public void zoom(Float scaleX,Float scaleY,PointF pivot){
  mainView.setPivotX(pivot.x);
  mainView.setPivotY(pivot.y);  
  mainView.setScaleX(scaleX);
  mainView.setScaleY(scaleY);  
 } 
}
buttonZoomOut
Here zoom is the main function for zooming

Friday, March 18, 2011

Load Image from server using thread

This is a project where I implemented how to load image form server
Here we have a image URL and need to load that image to a image view

In the layout xml I defined a web view

main.xml

<?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" />
 <ProgressBar    
   android:id="@+id/progressBar"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content" />
 <ImageView
   android:id="@+id/imageView"
   android:visibility="gone"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
 
</LinearLayout>

Then in my activity i have used a thread (ImageDownlaodThread) to load the image from server. Where the function LoadImageFromWebOperations will read to image to InputStream, this is later converted to Drawable by Drawable.createFromStream

Using the Handler, when the thread convert to drawable it will be set to the image view


Then my main activity ImageDownload.java


import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;

public class ImageDownload extends Activity {
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  ImageView mainImageView = (ImageView) findViewById(R.id.imageView);
  ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
  String imageurl = "http://developer.android.com/assets/images/home/honeycomb-android.png";
  
  ImageDownloadMessageHandler imageDownloadMessageHandler1= new ImageDownloadMessageHandler(progressBar, mainImageView);
  ImageDownlaodThread imageDownlaodThread = new ImageDownlaodThread(imageDownloadMessageHandler1,imageurl);
  imageDownlaodThread.start();
  
 }
 
 class ImageDownlaodThread extends Thread {
  ImageDownloadMessageHandler imageDownloadMessageHandler;
  String imageUrl;

  public ImageDownlaodThread(ImageDownloadMessageHandler imageDownloadMessageHandler, String imageUrl) {
   this.imageDownloadMessageHandler = imageDownloadMessageHandler;
   this.imageUrl = imageUrl;
  }

  @Override
  public void run() {
   Drawable drawable = LoadImageFromWebOperations(imageUrl);
   Message message = imageDownloadMessageHandler.obtainMessage(1, drawable);
   imageDownloadMessageHandler.sendMessage(message);
   System.out.println("Message sent");
  }

 }

 class ImageDownloadMessageHandler extends Handler {
  ProgressBar progressBar;
  View imageTextView;

  public ImageDownloadMessageHandler(ProgressBar progressBar, View imageTextView) {
   this.progressBar = progressBar;
   this.imageTextView = imageTextView;
  }

  @Override
  public void handleMessage(Message message) {
   progressBar.setVisibility(View.GONE);
   imageTextView.setBackgroundDrawable(((Drawable) message.obj));
   imageTextView.setVisibility(View.VISIBLE);
  }

 }

 Drawable LoadImageFromWebOperations(String url) {
  Drawable d = null;
  InputStream is = null;
  try {
   is = (InputStream) new URL(url).getContent();
   d = Drawable.createFromStream(is, "src name");
  } catch (MalformedURLException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
  return d;
 }

}