Wednesday, October 31, 2012

Shadow effect & Glow Effect on TextView

Shadow Effect on TextView or Button.

style.xml

 Apply this style on textview

Output:-



OuterGlow effect on view:-

Just change shadowDx & shadowDy as 0 & increase shadowRadius


OutPut:-


Tuesday, October 30, 2012

Draw Route between two point on google map in android





Call below RetreiveFeedTask.class like this..
String url = "http://routes.cloudmade.com/A6421860EBB04234AB5EF2D049F2CD8F/api/0.3/"
                + mLatitude_Current+ ","
                + mLongitude_Current+","
                + mLatitude_Place+ ","
                + mLongitude_Place + "/car.gpx";
  new RetreiveFeedTask(ActivityMapDrawPath.this, MapView, MapView.getOverlays(), mGeoPoint_Current).execute(url);


 RetreiveFeedTask.class 

import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.os.AsyncTask;
import android.widget.Toast;
import androidexperts.app.gujrattourism.parser.ParserRouteDetails;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;

public class RetreiveFeedTask extends AsyncTask {

    private ProgressDialog dialog;
    Activity mActivity;
    ArrayList itemsList;
    public ParserRouteDetails mXMLGetterSetter;
    MapView mMapView;
    List mListOverlay;
    MapOverlay mapOverlay;
    GeoPoint mGeoPoint_Current;

    public RetreiveFeedTask(Activity mActivity,MapView mMapView,List mListOverlay,GeoPoint mGeoPoint_Current) {
        this.mActivity = mActivity;
        this.mMapView = mMapView;
        this.mListOverlay = mListOverlay;
        this.mGeoPoint_Current = mGeoPoint_Current;
        dialog = new ProgressDialog(mActivity);
    }

    protected Void doInBackground(String... urls) {
        try {

            SAXParserFactory spf = SAXParserFactory.newInstance();
            SAXParser sp = spf.newSAXParser();
            XMLReader xr = sp.getXMLReader();

            XMLParserHandler myXMLHandler = new XMLParserHandler();
            xr.setContentHandler(myXMLHandler);

            URL url = new URL(urls[0]);

            itemsList = myXMLHandler.getItemsArrayList();

            xr.parse(new InputSource(url.openStream()));

            return null;
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

        this.dialog.setMessage("Loading...");
        this.dialog.show();

    }

    protected void onPostExecute(Void feed) {
      
        mMapView.invalidate();
        if (dialog.isShowing())
            dialog.dismiss();
        if(itemsList.size() > 0){
            mapOverlay = new MapOverlay(mGeoPoint_Current);
            mListOverlay.add(mapOverlay);
        }else{
            Toast.makeText(mActivity, "Path not Found......", Toast.LENGTH_SHORT).show();

        }
    }
    public class MapOverlay extends com.google.android.maps.Overlay {

        int check_id;
        public MapOverlay(GeoPoint mGeoPoint) {
          
        }

        @Override
        public boolean draw(final Canvas canvas, MapView mapView, boolean shadow, long when) {

            Point mpoint = new Point();
            Point mpoint1 = new Point();

            GeoPoint firstGeoPoint = null;
            GeoPoint secondGeoPoint = null;
            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
          
//            if(itemsList.size() > 0){

                for (int i = 0; i < itemsList.size(); i++) {

                    mXMLGetterSetter = itemsList.get(i);

                    if (i < (itemsList.size() - 1)) {

                        firstGeoPoint = new GeoPoint(
                        (int)(Double.parseDouble(itemsList.get(i).getLatitude())*1E6),
                        (int)(Double.parseDouble(itemsList.get(i).getLongitude())*1E6));
                        secondGeoPoint = new GeoPoint(
                        (int)(Double.parseDouble(itemsList.get(i+1).getLatitude())*1E6),
                       (int)(Double.parseDouble(itemsList.get(i+1).getLongitude())*1E6));

                        paint.setDither(true);
                        paint.setColor(Color.parseColor("#562302"));
                        paint.setStyle(Paint.Style.FILL_AND_STROKE);
                        paint.setStrokeJoin(Paint.Join.ROUND);
                        paint.setStrokeWidth(100);
                        paint.setStrokeCap(Paint.Cap.ROUND);
                        Path path = new Path();
                        paint.setStyle(Paint.Style.STROKE);
                        paint.setStrokeWidth(7f);

                        mapView.getProjection().toPixels(firstGeoPoint, mpoint);
                        mapView.getProjection().toPixels(secondGeoPoint, mpoint1);

                        path.moveTo(mpoint1.x, mpoint1.y);
                        path.lineTo(mpoint.x, mpoint.y);
                        canvas.drawPath(path, paint);
                    }
                }
//            }else{
//                Toast.makeText(mActivity, "Path not Found......", Toast.LENGTH_SHORT).show();
//            }
            return false;
        }
    }

}

Monday, October 29, 2012

Get Angle from using SensorManager In Android

private float[] mGravity;
    private float[] mMagnetic;
  
    private float getDirection()
    {
      
        float[] temp = new float[9];
        float[] R = new float[9];
        //Load rotation matrix into R
        SensorManager.getRotationMatrix(temp, null,
                mGravity, mMagnetic);
      
        //Remap to camera's point-of-view
        SensorManager.remapCoordinateSystem(temp,
                SensorManager.AXIS_X,
                SensorManager.AXIS_Z, R);
      
        //Return the orientation values
        float[] values = new float[3];
        SensorManager.getOrientation(R, values);
      
        //Convert to degrees
        for (int i=0; i < values.length; i++) {
            Double degrees = (values[i] * 180) / Math.PI;
            values[i] = degrees.floatValue();
        }

        return values[0];
      
    }
  
    @Override
    public void onSensorChanged(SensorEvent event) {
        switch(event.sensor.getType()) {
              
        case Sensor.TYPE_ACCELEROMETER:
            mGravity = event.values.clone();
            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            mMagnetic = event.values.clone();
            break;
        default:
            return;
        }
        if(mGravity != null && mMagnetic != null) {
            getDirection();
        }
    }

Friday, October 26, 2012

Play audio file (.mp3) from asset folder in android.

import java.io.IOException;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;

public class AudioPlayer {
  
    String fileName;
    Context contex;
    MediaPlayer mp;

    //Constructor
    public AudioPlayer(String name, Context context) {
        fileName = name;
        contex = context;
        playAudio();
    }

    //Play Audio
    public void playAudio() {
        mp = new MediaPlayer();
        try {
            AssetFileDescriptor descriptor = contex.getAssets()
                    .openFd(fileName);
            mp.setDataSource(descriptor.getFileDescriptor(),
                    descriptor.getStartOffset(), descriptor.getLength());
            descriptor.close();
            mp.prepare();
            mp.setLooping(true);
            mp.start();
            mp.setVolume(3, 3);

        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //Stop Audio
    public void stop() {
        mp.stop();
    }
}


Call this class from any activity like as new AudioPlayer(file_name, mContext);

Programatically Hide/Show Android Soft Keyboard

InputMethodManager imm = (InputMethodManager)getSystemService(Service.INPUT_METHOD_SERVICE);
for hide keyboard
 imm.hideSoftInputFromWindow(ed.getWindowToken(), 0); 
for show keyboard
 imm.showSoftInput(ed, 0);
for focus on EditText
 ed.requestFocus();

Changes in Menifest.xml

<activity android:name=".Activity" android:configChanges="keyboard|orientation"></activity>
 
 For more information check this Question

Monday, October 22, 2012

Set Map Center according to multiple GeoPoint (Display all pin on screen))

public static void setCenterGeoPoint(GeoPoint[] mGeoPoint ,
                                                              MapController mapController)
{
        GeoPoint mGeoPointCenter;
        int maxLatitude = 0;
        int minLatitude = 0;
        int maxLongitude = 0;
        int minLongitude = 0;
      
        try {
            if(mGeoPoint.length!=0)
            {
                for (GeoPoint item : mGeoPoint)
                { // item Contain list of Geopints
                    int lat = item.getLatitudeE6();
                    int lon = item.getLongitudeE6();

                    maxLatitude = Math.max(lat, maxLatitude);
                    minLatitude = Math.min(lat, minLatitude);
                    maxLongitude = Math.max(lon, maxLongitude);
                    minLongitude = Math.min(lon, minLongitude);
                }
            }
          

            mapController.zoomToSpan(Math.abs(maxLatitude - minLatitude)/2,
                    Math.abs(maxLongitude - minLongitude)/2);

            mGeoPointCenter = new GeoPoint(
                    (maxLatitude + minLatitude) ,(maxLongitude + minLongitude));

            mapController.animateTo(mGeoPointCenter);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

    }

Check Application is running in front ?

public static boolean isApplicationInFront(Context mContext)
{
        ActivityManager  am= (ActivityManager)
             mContext.getSystemService(Context.ACTIVITY_SERVICE);
        ArrayList rti = new ArrayList();
        rti=(ArrayList)am.getRunningTasks(2);
        String currenact = rti.get(0).topActivity.getPackageName().toString();
      
        if(currenact.equals(mContext.getPackageName().toString()))
            return true;
      
        return false;
}

Calculate Distance between two location (GeoPoint)

public double CalculationByDistance(Location Start, Location End)
{
        double Radius = 6371;
        double lat1 = Start.getLatitude();
        double lat2 = End.getLatitude();
        double lon1 = Start.getLongitude();
        double lon2 = End.getLongitude();
        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
                + Math.cos(Math.toRadians(lat1))
                * Math.cos(Math.toRadians(lat2)) * Math.sin(dLon / 2)
                * Math.sin(dLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        double km = Radius * c;
        return km * 1000;
}

Check Internet is Available in Android Device

public boolean check_Internet(Context mContext)
{
        ConnectivityManager mConnectivityManager =
                  (ConnectivityManager) mContext
                               .getSystemService(Context.CONNECTIVITY_SERVICE);

        NetworkInfo mNetworkInfo =  mConnectivityManager
                                                            .getActiveNetworkInfo();

        if (mNetworkInfo != null &&  mNetworkInfo.isConnectedOrConnecting())
            return true;
        else
            return false;
}

Thursday, June 14, 2012

Contact List :- GetContact List from default contact database in Android

public ArrayList<String> getPhoneNumber(Activity mActivity)
{
        ArrayList<String> numbers=null;
        numbers= new ArrayList<String>();
        Cursor c =  mActivity.managedQuery(ContactsContract.Contacts.CONTENT_URI,  null, null, null, null);
        for(int i=0;i<c.getcount();i++)
        {
            c.moveToPosition(i);
            String id = c.getString(c.getColumnIndexOrThrow(ContactsContract.Contacts._ID));
            String hasPhone = c.getString(c.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
            if (hasPhone.equalsIgnoreCase("1"))
            {
                Cursor phones = mActivity.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                                                            null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ id,null, null);
                if(phones.getCount()>0)
                {
                     phones.moveToFirst();
                     String cNumber = phones.getString(phones.getColumnIndex("data1"));
                     numbers.add(cNumber);
                }
            }
        }
        return numbers;
    }


Note:
Add Permission in Menifest.xml
<'uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>

Search Address :- Get Geopoint from location name.

public static GeoPoint searchAddress(Context mContext,String mAddress)
    {
        GeoPoint mGeoPoint=null;
        Geocoder coder = new Geocoder(mContext);
        List<Address> address;
        try
        {
            address = coder.getFromLocationName(mAddress,5);
            if(address==null)
            {
                return null;
            }
            for(int i=0;i<1;i++)
            {
                Address location = address.get(i);
                mGeoPoint=new GeoPoint((int)(location.getLatitude()*1E6), (int)(location.getLongitude()*1E6));
            }
        }
        catch(Exception e)
        {
            return null;
        }
        return mGeoPoint;
    }


Note:
Add Permission in Menifest.xml
<'uses-permission android:name="android.permission.INTERNET"/>

Custom Camera Application

Preview.class
package com.example;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;


class Preview extends SurfaceView implements SurfaceHolder.Callback {
    private static final String TAG = "Preview";

    SurfaceHolder mHolder;
    public Camera camera;
   
    Preview(Context context) {
        super(context);
       
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, acquire the camera and tell it where
        // to draw.
        camera = Camera.open();
        try {
            camera.setPreviewDisplay(holder);
           
           
            camera.setPreviewCallback(new PreviewCallback() {

                public void onPreviewFrame(byte[] data, Camera arg1) {
                    FileOutputStream outStream = null;
                    try {
                        outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));   
                        outStream.write(data);
                        outStream.close();
                        Log.d(TAG, "onPreviewFrame - wrote bytes: " + data.length);
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                    }
                        Preview.this.invalidate();
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface will be destroyed when we return, so stop the preview.
        // Because the CameraDevice object is not a shared resource, it's very
        // important to release it when the activity is paused.
        camera.stopPreview();
        camera = null;
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // Now that the size is known, set up the camera parameters and begin
        // the preview.
        Camera.Parameters parameters = camera.getParameters();
//        parameters.setPreviewSize(w, h);
        camera.setParameters(parameters);
        camera.startPreview();
    }

    @Override
    public void draw(Canvas canvas) {
            super.draw(canvas);
            Paint p= new Paint(Color.RED);
            Log.d(TAG,"draw");
            canvas.drawText("PREVIEW", canvas.getWidth()/2, canvas.getHeight()/2, p );
    }
}


CameraDemo.class

package com.example;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.content.Intent;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;

public class CameraDemo extends Activity {
    private static final String TAG = "CameraDemo";
    Camera camera;
    Preview preview;
    Button buttonClick;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        preview = new Preview(this);
        ((FrameLayout) findViewById(R.id.preview)).addView(preview);

        buttonClick = (Button) findViewById(R.id.buttonClick);
        buttonClick.setOnClickListener( new OnClickListener() {
            public void onClick(View v) {
                preview.camera.takePicture(shutterCallback, rawCallback, jpegCallback);
            }
        });

        Log.d(TAG, "onCreate'd");
    }


    ShutterCallback shutterCallback = new ShutterCallback() {
        public void onShutter() {
            Log.d(TAG, "onShutter'd");
        }
    };

    /** Handles data for raw picture */
    PictureCallback rawCallback = new PictureCallback() {
        public void onPictureTaken(byte[] data, Camera camera) {
            Log.d(TAG, "onPictureTaken - raw");
        }
    };

    /** Handles data for jpeg picture */
    PictureCallback jpegCallback = new PictureCallback() {
        public void onPictureTaken(byte[] data, Camera camera) {
            FileOutputStream outStream = null;
            long time = 0;
            try {
                // write to local sandbox file system
//                outStream = CameraDemo.this.openFileOutput(String.format("%d.jpg", System.currentTimeMillis()), 0);   
                // Or write to sdcard
                time =  System.currentTimeMillis();
                outStream = new FileOutputStream(String.format("/sdcard/%d.jpg",time));   
                outStream.write(data);
                outStream.close();
                Log.d(TAG, "onPictureTaken - wrote bytes: " + data.length);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
               
               

            }
            Log.d(TAG, "onPictureTaken - jpeg");
        }
    };

}

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" android:id="@+id/layout">
 <TextView android:layout_width="fill_parent"
  android:layout_height="wrap_content" android:text="Camera Demo"
  android:textSize="24sp" />

 <FrameLayout android:id="@+id/preview"
  android:layout_weight="1" android:layout_width="fill_parent"
  android:layout_height="fill_parent">
 </FrameLayout>

 <Button android:layout_width="wrap_content"
  android:layout_height="wrap_content" android:id="@+id/buttonClick"
  android:text="Click" android:layout_gravity="center"></Button>

</LinearLayout>
And finally remember to add android:name="android.permission.CAMERA" to your AndroidManifest.xml file.

Thursday, February 2, 2012

Pinch Zoom on ImageView in Android

package com.apps.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PointF;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.SimpleOnGestureListener;

public class ZoomableImageView extends View {
    private static final String TAG = "ZoomableImageView";      
  
    private Bitmap imgBitmap = null;
  
    private int containerWidth;
    private int containerHeight;
      
    Paint background;  
  
    //Matrices will be used to move and zoom image
    Matrix matrix = new Matrix();
    Matrix savedMatrix = new Matrix();
  
    PointF start = new PointF();      
  
    float currentScale;
    float curX;
    float curY;
  
    //We can be in one of these 3 states
    static final int NONE = 0;
    static final int DRAG = 1;
    static final int ZOOM = 2;
    int mode = NONE;
  
    //For animating stuff  
    float targetX;
    float targetY;
    float targetScale;
    float targetScaleX;
    float targetScaleY;
    float scaleChange;
    float targetRatio;
    float transitionalRatio;
  
    float easing = 0.2f;  
    boolean isAnimating = false;
  
    float scaleDampingFactor = 0.5f;
  
    //For pinch and zoom
    float oldDist = 1f;  
    PointF mid = new PointF();
  
    private Handler mHandler = new Handler();      
  
    float minScale;
    float maxScale = 8.0f;
  
    float wpRadius = 25.0f;
    float wpInnerRadius = 20.0f;
  
    float screenDensity;
  
    private GestureDetector gestureDetector;
  
    public static final int DEFAULT_SCALE_FIT_INSIDE = 0;
    public static final int DEFAULT_SCALE_ORIGINAL = 1;
  
    private int defaultScale;
  
    public int getDefaultScale() {
        return defaultScale;
    }

    public void setDefaultScale(int defaultScale) {
        this.defaultScale = defaultScale;
    }

    public ZoomableImageView(Context context) {
        super(context);      
        setFocusable(true);
        setFocusableInTouchMode(true);
      
        screenDensity = context.getResources().getDisplayMetrics().density;
                      
        initPaints();
        gestureDetector = new GestureDetector(new MyGestureDetector());      
    }
  
    public ZoomableImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
      
        screenDensity = context.getResources().getDisplayMetrics().density;      
        initPaints();
        gestureDetector = new GestureDetector(new MyGestureDetector());
      
        defaultScale = ZoomableImageView.DEFAULT_SCALE_FIT_INSIDE;
    }
  
    private void initPaints() {
        background = new Paint();
    }
  
    @Override
    protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
        super.onSizeChanged(width, height, oldWidth, oldHeight);
          
        //Reset the width and height. Will draw bitmap and change
        containerWidth = width;
        containerHeight = height;
      
        if(imgBitmap != null) {
            int imgHeight = imgBitmap.getHeight();
            int imgWidth = imgBitmap.getWidth();
          
            float scale;
            int initX = 0;
            int initY = 0;          
          
            if(defaultScale == ZoomableImageView.DEFAULT_SCALE_FIT_INSIDE) {              
                if(imgWidth > containerWidth) {          
                    scale = (float)containerWidth / imgWidth;          
                    float newHeight = imgHeight * scale;          
                    initY = (containerHeight - (int)newHeight)/2;
                  
                    matrix.setScale(scale, scale);
                    matrix.postTranslate(0, initY);
                }
                else {          
                    scale = (float)containerHeight / imgHeight;
                    float newWidth = imgWidth * scale;
                    initX = (containerWidth - (int)newWidth)/2;
                  
                    matrix.setScale(scale, scale);
                    matrix.postTranslate(initX, 0);
                }
              
                curX = initX;
                curY = initY;
              
                currentScale = scale;
                minScale = scale;
            }
            else {
                if(imgWidth > containerWidth) {                                  
                    initY = (containerHeight - (int)imgHeight)/2;                  
                    matrix.postTranslate(0, initY);
                }
                else {                              
                    initX = (containerWidth - (int)imgWidth)/2;                  
                    matrix.postTranslate(initX, 0);
                }
              
                curX = initX;
                curY = initY;
              
                currentScale = 1.0f;
                minScale = 1.0f;              
            }
          
                                  
            invalidate();          
        }
    }
  
    @Override
    protected void onDraw(Canvas canvas) {              
        if(imgBitmap != null && canvas != null)
        {                                          
            canvas.drawBitmap(imgBitmap, matrix, background);                                                  
        }
    }
  
    //Checks and sets the target image x and y co-ordinates if out of bounds
    private void checkImageConstraints() {
        if(imgBitmap == null) {
            return;
        }
      
        float[] mvals = new float[9];
        matrix.getValues(mvals);
      
        currentScale = mvals[0];
              
        if(currentScale < minScale) {                              
            float deltaScale = minScale / currentScale;                  
            float px = containerWidth/2;
            float py = containerHeight/2;          
            matrix.postScale(deltaScale, deltaScale, px, py);
            invalidate();
        }      
      
        matrix.getValues(mvals);
        currentScale = mvals[0];
        curX = mvals[2];
        curY = mvals[5];
              
        int rangeLimitX = containerWidth - (int)(imgBitmap.getWidth() * currentScale);
        int rangeLimitY = containerHeight - (int)(imgBitmap.getHeight() * currentScale);
      
      
        boolean toMoveX = false;
        boolean toMoveY = false;  
      
        if(rangeLimitX < 0) {
            if(curX > 0) {
                targetX = 0;
                toMoveX = true;
            }
            else if(curX < rangeLimitX) {
                targetX = rangeLimitX;
                toMoveX = true;
            }
        }
        else {
            targetX = rangeLimitX / 2;
            toMoveX = true;
        }
      
        if(rangeLimitY < 0) {
            if(curY > 0) {
                targetY = 0;
                toMoveY = true;
            }
            else if(curY < rangeLimitY) {
                targetY = rangeLimitY;
                toMoveY = true;
            }
        }
        else {
            targetY = rangeLimitY / 2;
            toMoveY = true;
        }
      
        if(toMoveX == true || toMoveY == true) {
            if(toMoveY == false) {
                targetY = curY;
            }
            if(toMoveX == false) {
                targetX = curX;
            }          
          
            //Disable touch event actions
            isAnimating = true;
            //Initialize timer          
            mHandler.removeCallbacks(mUpdateImagePositionTask);
            mHandler.postDelayed(mUpdateImagePositionTask, 100);
        }
    }      
  
  
    @Override
    public boolean onTouchEvent(MotionEvent event) {      
        if(gestureDetector.onTouchEvent(event)) {
            return true;
        }
      
        if(isAnimating == true) {
            return true;
        }
      
        //Handle touch events here      
        float[] mvals = new float[9];
        switch(event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
            if(isAnimating == false) {
                savedMatrix.set(matrix);
                start.set(event.getX(), event.getY());          
                mode = DRAG;              
            }
        break;
      
        case MotionEvent.ACTION_POINTER_DOWN:
            oldDist = spacing(event);          
            if(oldDist > 10f) {
                savedMatrix.set(matrix);
                midPoint(mid, event);
                mode = ZOOM;
            }
        break;
      
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_POINTER_UP:
            mode = NONE;
          
            matrix.getValues(mvals);
            curX = mvals[2];
            curY = mvals[5];
            currentScale = mvals[0];
          
            if(isAnimating == false) {                                      
                checkImageConstraints();
            }
        break;
          
        case MotionEvent.ACTION_MOVE:          
            if(mode == DRAG && isAnimating == false) {
                matrix.set(savedMatrix);
                float diffX = event.getX() - start.x;
                float diffY = event.getY() - start.y;
              
                matrix.postTranslate(diffX, diffY);
                              
                matrix.getValues(mvals);
                curX = mvals[2];
                curY = mvals[5];
                currentScale = mvals[0];
            }
            else if(mode == ZOOM && isAnimating == false) {
                float newDist = spacing(event);              
                if(newDist > 10f) {
                    matrix.set(savedMatrix);
                    float scale = newDist / oldDist;                  
                    matrix.getValues(mvals);
                    currentScale = mvals[0];
                                      
                    if(currentScale * scale <= minScale) {
                        matrix.postScale(minScale/currentScale, minScale/currentScale, mid.x, mid.y);
                    }                  
                    else if(currentScale * scale >= maxScale) {
                        matrix.postScale(maxScale/currentScale, maxScale/currentScale, mid.x, mid.y);
                    }
                    else {
                        matrix.postScale(scale, scale, mid.x, mid.y);
                    }
                                                              
                  
                    matrix.getValues(mvals);
                    curX = mvals[2];
                    curY = mvals[5];
                    currentScale = mvals[0];                                      
                }
            }
              
        break;                              
        }
      
        //Calculate the transformations and then invalidate
        invalidate();
        return true;
    }
  
    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 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);
    }
  
    public void setImageBitmap(Bitmap b) {      
        if(b != null) {
            imgBitmap = b;              
          
            containerWidth = getWidth();
            containerHeight = getHeight();
                      
            int imgHeight = imgBitmap.getHeight();
            int imgWidth = imgBitmap.getWidth();
          
            float scale;
            int initX = 0;
            int initY = 0;
          
            matrix.reset();
          
            if(defaultScale == ZoomableImageView.DEFAULT_SCALE_FIT_INSIDE) {              
                if(imgWidth > containerWidth) {          
                    scale = (float)containerWidth / imgWidth;          
                    float newHeight = imgHeight * scale;          
                    initY = (containerHeight - (int)newHeight)/2;
                  
                    matrix.setScale(scale, scale);
                    matrix.postTranslate(0, initY);
                }
                else {          
                    scale = (float)containerHeight / imgHeight;
                    float newWidth = imgWidth * scale;
                    initX = (containerWidth - (int)newWidth)/2;
                  
                    matrix.setScale(scale, scale);
                    matrix.postTranslate(initX, 0);
                }
              
                curX = initX;
                curY = initY;
              
                currentScale = scale;
                minScale = scale;
            }
            else {
                if(imgWidth > containerWidth) {
                    initX = 0;
                    if(imgHeight > containerHeight) {                      
                        initY = 0;
                    }
                    else {                      
                        initY = (containerHeight - (int)imgHeight)/2;
                    }
                                      
                    matrix.postTranslate(0, initY);
                }
                else {                              
                    initX = (containerWidth - (int)imgWidth)/2;
                    if(imgHeight > containerHeight) {
                        initY = 0;
                    }
                    else {
                        initY = (containerHeight - (int)imgHeight)/2;
                    }
                    matrix.postTranslate(initX, 0);
                }
              
                curX = initX;
                curY = initY;
              
                currentScale = 1.0f;
                minScale = 1.0f;              
            }
          
            invalidate();          
        }
        else {
            Log.d(TAG, "bitmap is null");
        }
    }
  
    public Bitmap getPhotoBitmap() {      
        return imgBitmap;
    }
  
  
    private Runnable mUpdateImagePositionTask = new Runnable() {
        public void run() {      
            float[] mvals;
          
            if(Math.abs(targetX - curX) < 5 && Math.abs(targetY - curY) < 5) {
                isAnimating = false;
                mHandler.removeCallbacks(mUpdateImagePositionTask);
              
                mvals = new float[9];
                matrix.getValues(mvals);
              
                currentScale = mvals[0];
                curX = mvals[2];
                curY = mvals[5];
              
                //Set the image parameters and invalidate display
                float diffX = (targetX - curX);
                float diffY = (targetY - curY);
                              
                matrix.postTranslate(diffX, diffY);
            }
            else {
                isAnimating = true;
                mvals = new float[9];
                matrix.getValues(mvals);
              
                currentScale = mvals[0];
                curX = mvals[2];
                curY = mvals[5];
              
                //Set the image parameters and invalidate display
                float diffX = (targetX - curX) * 0.3f;
                float diffY = (targetY - curY) * 0.3f;
                              
                matrix.postTranslate(diffX, diffY);              
                mHandler.postDelayed(this, 25);              
            }
          
            invalidate();          
        }
    };
  
    private Runnable mUpdateImageScale = new Runnable() {
        public void run() {          
            float transitionalRatio = targetScale / currentScale;          
            float dx;
            if(Math.abs(transitionalRatio - 1) > 0.05) {
                isAnimating = true;              
                if(targetScale > currentScale) {                                      
                    dx = transitionalRatio - 1;
                    scaleChange = 1 + dx * 0.2f;
                  
                    currentScale *= scaleChange;
                  
                    if(currentScale > targetScale) {
                        currentScale = currentScale / scaleChange;
                        scaleChange = 1;
                    }
                }
                else {                                  
                    dx = 1 - transitionalRatio;                  
                    scaleChange = 1 - dx * 0.5f;
                    currentScale *= scaleChange;
                  
                    if(currentScale < targetScale) {
                        currentScale = currentScale / scaleChange;
                        scaleChange = 1;
                    }
                }
                                              
              
                if(scaleChange != 1) {
                    matrix.postScale(scaleChange, scaleChange, targetScaleX, targetScaleY);              
                    mHandler.postDelayed(mUpdateImageScale, 15);
                    invalidate();
                }
                else {
                    isAnimating = false;
                    scaleChange = 1;                  
                    matrix.postScale(targetScale/currentScale, targetScale/currentScale, targetScaleX, targetScaleY);
                    currentScale = targetScale;
                    mHandler.removeCallbacks(mUpdateImageScale);
                    invalidate();
                    checkImageConstraints();
                }              
            }
            else {
                isAnimating = false;
                scaleChange = 1;              
                matrix.postScale(targetScale/currentScale, targetScale/currentScale, targetScaleX, targetScaleY);
                currentScale = targetScale;
                mHandler.removeCallbacks(mUpdateImageScale);
                invalidate();
                checkImageConstraints();
            }                              
        }
    };
  
   /** Show an event in the LogCat view, for debugging */
   private void dumpEvent(MotionEvent event) {
      String names[] = { "DOWN", "UP", "MOVE", "CANCEL", "OUTSIDE", "POINTER_DOWN", "POINTER_UP", "7?", "8?", "9?" };
      StringBuilder sb = new StringBuilder();
      int action = event.getAction();
      int actionCode = action & MotionEvent.ACTION_MASK;
      sb.append("event ACTION_").append(names[actionCode]);
      if (actionCode == MotionEvent.ACTION_POINTER_DOWN || actionCode == MotionEvent.ACTION_POINTER_UP) {
         sb.append("(pid ").append(action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
         sb.append(")");
      }
      sb.append("[");
    
      for (int i = 0; i < event.getPointerCount(); i++) {
         sb.append("#").append(i);
         sb.append("(pid ").append(event.getPointerId(i));
         sb.append(")=").append((int) event.getX(i));
         sb.append(",").append((int) event.getY(i));
         if (i + 1 < event.getPointerCount())
            sb.append(";");
      }
      sb.append("]");
   }

   class MyGestureDetector extends SimpleOnGestureListener {
        @Override
        public boolean onDoubleTap(MotionEvent event) {          
            if(isAnimating == true) {
                return true;
            }
          
            scaleChange = 1;
            isAnimating = true;
            targetScaleX = event.getX();
            targetScaleY = event.getY();
          
            if(Math.abs(currentScale - maxScale) > 0.1) {          
                targetScale = maxScale;
            }
            else {
                targetScale = minScale;
            }
            targetRatio = targetScale / currentScale;
            mHandler.removeCallbacks(mUpdateImageScale);
            mHandler.post(mUpdateImageScale);          
            return true;
        }
      
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            return super.onFling(e1, e2, velocityX, velocityY);
        }
      
        @Override
        public boolean onDown(MotionEvent e) {
            return false;
        }
    }
}