Saturday 29 December 2012

Canvas in Android


CANVAS

The Android framework APIs provides a set 2D drawing APIs that allow you to render your own custom graphics onto a canvas or to modify existing Views to customize their look and feel. When drawing 2D graphics, you'll typically do so in one of two ways:
a.     Draw your graphics or animations into a View object from your layout. In this manner, the drawing of your graphics is handled by the system's normal View hierarchy drawing process — you simply define the graphics to go inside the View.
b.    Draw your graphics directly to a Canvas. This way, you personally call the appropriate class's onDraw() method (passing it your Canvas), or one of the Canvas draw...() methods (likedrawPicture()). In doing so, you are also in control of any animation.

Drawing to a Canvas, is better when your application needs to regularly re-draw itself. Applications such as video games should be drawing to the Canvas on its own.

Drawing With Canvas:
When you're writing an application in which you would like to perform specialized drawing and/or control the animation of graphics, you should do so by drawing through a Canvas. A Canvas works for you as a pretense, or interface, to the actual surface upon which your graphics will be drawn. It holds all of your "draw" calls. Via the Canvas, your drawing is actually performed upon an underlying Bitmap , which is placed into the window. However, if you need to create a new Canvas, then you must define the Bitmap upon which drawing will actually be performed. The Bitmap is always required for a Canvas. You can set up a new Canvas like this:
Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
Now your Canvas will draw onto the defined Bitmap.
On a View:
If your application does not require a significant amount of processing or frame-rate speed (perhaps for a chess game, a snake game, or another slowly-animated application), then you should consider creating a custom View component and drawing with a Canvas in View.onDraw(). The most convenient aspect of doing so is that the Android framework will provide you with a pre-defined Canvas to which you will place your drawing calls.
To start, extend the View class (or descendant thereof) and define the onDraw() callback method. This method will be called by the Android framework to request that your View draw itself. This is where you will perform all your calls to draw through the Canvus, which is passed to you through the onDraw() callback.

On a SurfaceView:

The SurfaceView is a special subclass of View that offers a dedicated drawing surface within the View hierarchy. The aim is to offer this drawing surface to an application's secondary thread, so that the application isn't required to wait until the system's View hierarchy is ready to draw. Instead, a secondary thread that has reference to a SurfaceView can draw to its own Canvas at its own pace.

Thursday 20 December 2012

Nine-patch Image in Android


Nine-patch

A NinePatchDrawable graphic is a stretchable bitmap image, which Android will automatically resize to accommodate the contents of the View in which you have placed it as the background. An example use of a NinePatch is the backgrounds used by standard Android buttons — buttons must stretch to accommodate strings of various lengths. A NinePatch drawable is a standard PNG image that includes an extra 1-pixel-wide border. It must be saved with the extension .9.png, and saved into the res/drawable/ directory of your project.

The border is used to define the stretchable and static areas of the image. You indicate a stretchable section by drawing one (or more) 1-pixel-wide black line(s) in the left and top part of the border (the other border pixels should be fully transparent or white). You can have as many stretchable sections as you want: their relative size stays the same, so the largest sections always remain the largest.

You can also define an optional drawable section of the image (effectively, the padding lines) by drawing a line on the right and bottom lines. If a View object sets the NinePatch as its background and then specifies the View's text, it will stretch itself so that all the text fits inside only the area designated by the right and bottom lines (if included). If the padding lines are not included, Android uses the left and top lines to define this drawable area.


The difference between the different lines, the left and top lines define which pixels of the image are allowed to be replicated in order to stretch the image. The bottom and right lines define the relative area within the image that the contents of the View are allowed to lie within.

Monday 10 December 2012

Find Current Location using GPS in Android


        An Android Application GPS Locator

         (Find Current Location using GPS)


This article is targeted to a beginner who wants to implement GPS functionality and work with Google Maps API as well. Before going to the progrmming, you need to know about API Key and Key Store File.

Google Maps API key and KeyStore File

The first and foremost thing is getting a Google Maps API key. Getting one is relatively easy but it requires our application to be signed with a certificate and notify Google about Hash (MD5) fingerprint of the certificate.


Generating MD5 Key and Registering it in MAPS API
We can create a new certificate by using keytool.exe, found in bin directory of JDK installation path (C:\Program Files\Java\jdk1.7.0_01\bin).


Steps to get MD5 Key:
1. Go to your android location(C:\Documents and Settings\Tara Roy\.android) where you have set your Work Space.
2. Copy "debug.keystore" & put this file in C:\debug.keystore
3. Go 2 your command prompt(cmd)
4. Type CD C:\Documents and Settings\Tara Roy
5. Next Type like this in cmd. C:\> keytool -list -v -keystore C:\debug.keystore
6. Put password ""android""
7. You will get like this...



9. Put Your MD5 Key( 28:89:52:AA:BD:53:01:90:32:F7:93:27:34:85:2F:AF ).
10. Register after giving your mail-id.
11. Success(Page will look like this)

Thank you for signing up for an Android Maps API key!
Your key is:
0uG1kA1mLxMHCVq8ArHf3eYNX8isA19dNZXSYHg
This key will work for all apps signed with your certificate whose fingerprint is:
FC:7A:5D:8D:E2:83:E9:68:31:CF:06:50:57:5E:EC:ED
Here is a sample xml layout to get you started on your way to mapping glory:
              <com.google.android.maps.MapView
                 android:layout_width="fill_parent"
                 android:layout_height="fill_parent"
                 android:apiKey="0uG1kA1mLxMHCVq8ArHf3eYNX8isA19dNZXSYHg"
                 />
           
        

Creating Application
Next:  Create a new Android Project and provide the details as below,…. 




Click Finish and the project is created. Create a Run Configuration for the project to launch an AVD targeted to Google APIs.


Try running the project with the specified configuration and it should show something like:


Before you can start using MapView control from Google APIs, you need to add the Google Maps External Library (com.google.android.map) to the library. For adding a library to the project use uses-library tag. This tag needs to be added to AndroidManifest.xml. Apart from the library, you need to add relevant permissions as well. For adding permissions, we use uses-permission tag. For our application, we will add the following permissions:
·         android.permission.ACCESS_COARSE_LOCATION: Allows application to access coarse location (Cell ID, Wi-Fi etc.)
·         android.permission.ACCESS_FINE_LOCATION: Allows application to access GPS location.
·         android.permission.INTERNET: Allows application to open network sockets.

 AndroidManifest.xml  will Look Like This:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.VertexVerveInc.GPSLocator"
    android:versionCode="1"
    android:versionName="1.0">
   
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 
  <uses-permission android:name="android.permission.INTERNET" />
 
  <application android:icon="@drawable/icon" android:label="@string/app_name">
    <uses-library android:name="com.google.android.maps" />
    <activity android:name=".GPSLocatorActivity"
          android:label="@string/app_name">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
  </application>
</manifest>

Add MapView control to main.xml under res/layout. The resultant code should look like:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
   
    <com.google.android.maps.MapView
              xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/present_mapview"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:clickable="true"
              android:enabled="true"
              android:apiKey="0uG1kA1mLxMHCVq8ArHf3eYNX8isA19dNZXSYHg"
    />
    </LinearLayout>

In order to display Google Map view, we need to update our Activity class (GPSLocatorActivity). This class should extend MapActivity class in place of  Activity  class. We also need to importcom.google.android.maps.MapActivity package to support  MapActivity class. We also need to overrideisRouteDisplayed method of MapActivity class. This is fairly easy, just return false from the method. After all these modifications, GPSLocatorActivity.java should look like:
import com.google.android.maps.MapActivity;
import android.os.Bundle;
 
public class GPSLocatorActivity extends MapActivity 
{
  
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
  }
  
  @Override
  protected boolean isRouteDisplayed() {
    return false;
  }
}

Out put will look like this:

Change Map view and Zoom level

We can select, if we want to show Satellite, Traffic or Street view in maps. This is simply achieved by calling setSatellite,setStreetView and setTraffic methods. Another thing to do before we move further is zoom the map a bit. Why? Because the map view shown in the above output doesn't serve any purpose. In order to set zoom level of Map, we need an instance of MapController and we can call its setZoom method. So, let's update the onCreate method ofGPSLocatorActivity class to incorporate all these changes.
mapView = (MapView) findViewById(R.id.mapView);
  
  // enable Street view by default
  mapView.setStreetView(true);
  
  // enable to show Satellite view
  // mapView.setSatellite(true);
  
  // enable to show Traffic on map
  // mapView.setTraffic(true);
  
  mapView.setBuiltInZoomControls(true);
  
  mapController = mapView.getController();
  mapController.setZoom(16); 




GPS Location Mapping

Android provides location based services through LocationManager (package android.Location) class. This class provides periodical updates about the location of the device. In order to user  LocationManager, we need to get a reference of LocationManager class by calling  getSystemService method. Later on, we need to register for location updates by calling  requestLocationUpdates method.
We need to create a class implementing abstract LocationListener class. This class will be registered with Location Manager to receive updates of location. We need to override all four methods of this class, namelyonLocationChanged,  onProviderDisabled/Enabled, and onStatusChanged. As we are just interested in getting location updates, we will modify the code of onLocationChanged to navigate to the new location received in the map view. This is achieved by calling animateTo method of MapController.
The Coding is changed and it will look like this:
public void onCreate(Bundle savedInstanceState) {
  ...
  
  locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);  
  
  locationListener = new GPSLocationListener();
  
  locationManager.requestLocationUpdates(
    LocationManager.GPS_PROVIDER, 
    0, 
    0, 
    locationListener);
  
  ...
}
 
private class GPSLocationListener implements LocationListener 
{
  @Override
  public void onLocationChanged(Location location) {
    if (location != null) {
      GeoPoint point = new GeoPoint(
          (int) (location.getLatitude() * 1E6), 
          (int) (location.getLongitude() * 1E6));
      
      Toast.makeText(getBaseContext(), 
          "Latitude: " + location.getLatitude() + 
          " Longitude: " + location.getLongitude(), 
          Toast.LENGTH_SHORT).show();
      
      mapController.animateTo(point);
      mapController.setZoom(16);
      mapView.invalidate();
    }
  }
 
  ...
}

The Out put will look like this:




Find Address for GPS Location

We can find information about an address if we know its latitude and longitude. For this purpose, we use Geocoderclass and the process is known as Geocoding. We will call getFromLocation method of the class and will pass the point as a parameter. This method returns a List of Address which contains information about address of the specified location. We can combine the information to find the complete information about the point. For this purpose, we will add a method  ConvertPointToLocation to GPSLocationListener class. ConvertPointToLocation returns astring object containing address of the location.
Code will Look Like This:
  class GPSLocationListener implements LocationListener {
  @Override
  public void onLocationChanged(Location location) {
    if (location != null) {
      ...
      String address = ConvertPointToLocation(point);
      Toast.makeText(getBaseContext(), address, Toast.LENGTH_SHORT).show();
      ...
    }
  }
 
  public String ConvertPointToLocation(GeoPoint point) {  
    String address = "";
    Geocoder geoCoder = new Geocoder(
        getBaseContext(), Locale.getDefault());
    try {
      List<Address> addresses = geoCoder.getFromLocation(
        point.getLatitudeE6()  / 1E6,
        point.getLongitudeE6() / 1E6, 1);

      if (addresses.size() > 0) {
        for (int index = 0;
            index < addresses.get(0).getMaxAddressLineIndex(); index++)
          address += addresses.get(0).getAddressLine(index) + " ";
      }
    }
    catch (IOException e) {       
      e.printStackTrace();
    }  
   
    return address;
  }




Add a Location Marker

A lot many times, we want to add a marker (image) to the location because the small circle (shown in maps by default) is sometimes useless. In order to add a marker, add a drawable resource to the project. We can import any image (which we want to use) to our project (simple drag and drop also works). Add the image to res/drawable folder.
In order to add a location marker to the map, we need to create a class which extends Overlay (com.google.android.maps package) class. We need to override draw method of the class and do some custom painting. The MapOverlay class looks like:
 class GPSLocationListener implements LocationListener
{
  @Override
  public void onLocationChanged(Location location) {
    ...
             
      mapController.animateTo(point);
      mapController.setZoom(16);
     
      // add marker
      MapOverlay mapOverlay = new MapOverlay();
      mapOverlay.setPointToDraw(point);
      List<Overlay> listOfOverlays = mapView.getOverlays();
      listOfOverlays.clear();
      listOfOverlays.add(mapOverlay);
     
      String address = ConvertPointToLocation(point);
      Toast.makeText(getBaseContext(), address, Toast.LENGTH_SHORT).show();

      ...
}

class MapOverlay extends Overlay
{
  private GeoPoint pointToDraw;

  public void setPointToDraw(GeoPoint point) {
    pointToDraw = point;
  }

  public GeoPoint getPointToDraw() {
    return pointToDraw;
  }
 
  @Override
  public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
    super.draw(canvas, mapView, shadow);          

    // convert point to pixels
    Point screenPts = new Point();
    mapView.getProjection().toPixels(pointToDraw, screenPts);

    // add marker
    Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.red);
    canvas.drawBitmap(bmp, screenPts.x, screenPts.y - 24, null);   
    return true;
  }
}