NOTE:

NOTE: Of late, I have been getting requests for very trivial problems that many of you are facing in your day-to-day work. This blog is not to solve your "project" problems - surely not a "Support" site.
I just love to share my knowledge in my spare time and would appreciate any questions or feedback on the articles and code I have shared. I also do appreciate thought-provoking questions that would lead me to write more articles and share.
But please do not put your day-to-day trivial problems here. Even if you do, you most probably would not get a response here.
Thanks

Search This Blog

x

Thursday 29 October 2009

Location Manager | Android Developer Tutorial (Part 15)


Location-based service is another key functionality that gets used by mobile applications. IT is often combined with maps to give a good user experience. We have already see how to use the external Google Maps API in tutorial Part 14. Here I will build upon the same to show how changes in location can be displayed on the map.
The location services are provided in the android.location package.


In order to use location services, our activity needs to implement the LocationManager Interface.
What does a LocationManager provide?


It is through this interface that an application can access the system’s location services. These services basically allow the application to obtain periodic updates of the device’s geographical location. It also helps in firing an application specific intent when the device comes within the proximity of a specified location.
Since in my example I want to simulate a location change and make my activity respond to the same, I am implementing this interface.


In order to make it an effective application, I have shown my location (hard-coded) on the google map. Then, I have used the location manager to handle any change in the location. The change in location needs to be simulated on the emulator by connecting through telnet. How to simulate location change is given at the end of this tutorial.


Now, dive into the code.


NOTE: I am adding the LocationManager implementation to the same MapActivity class created in the earlier tutorial (Part 14) and hence will not be explaining anything related to the maps API here.


Step 1: Obtain the LocationManager instance:


LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 500.0f, this);


After getting the location manager, I am setting default GPS provider and asking to be notified if the location changes by more than 500 meters from the current location, the frequency of updation being 1 sec.


Step 2: Override the onLocationChanged() method in order to respond to changes in location.


      public void onLocationChanged(Location location) {
            if (location != null) {
                  double lat = location.getLatitude();
                  double lng = location.getLongitude();
                  String currentLocation = "The location is changed to Lat: " + lat + " Lng: " + lng;
                  myLoc.setText(currentLocation);
                  geoPoint = new GeoPoint((int) lat * 1000000, (int) lng * 1000000);
                  myMC.animateTo(geoPoint);
            }
      }


This method gets invoked when we change the location through the telnet connection to the emulator as described at the end of the tutorial. Based on the latitude and the longitude settings sent, the GeoPoint is changed to display the new location.


That is it. I have not overridden any of the other methods provided by the locationManager. Complete code is downloadable here.



How to simulate location change in the emulator?
Start the Emulator from eclipse
Start a command prompt
Start telnet
Then, type, o localhost 5554
This connects the telnet client to the android emulator (assuming emulator is running locally listening on port 5554. Else this connection fails)
Now type
geo fix 79.000000 13.000000 (or your latitude and longitude)
This sends the location change signal to the emulator.

Wednesday 28 October 2009

Google Maps on Android | Android Developer Tutorial (Part 14)


Maps-based and location-based services are compelling for mobile users. Hence let us explore the support for map services in the Android platform in this tutorial. In the next we will  build upon this and add location services too.


Map services are provided by an external library that includes the com.google.android.maps package. This library is not provided as part of the standard SDK. It is provided as a Google APIs add-on to the android SDK. For the convenience of developers, this add-on is provided as part of the SDK on the emulator.


Before I jump into the example, let me explain some fundamental concepts related to the Maps API.


NOTE: For using the Google Maps, you have to obtain a Maps API key. How to obtain the key is also described towards the end of this tutorial. This is Step 1.


Maps API add-on provides a MapActivity class that extends the Activity class of Android. This helps is managing the lifecycle of a MapView object that we will be using later. Our main class in the application will be extending the MapActivity class. This class can be treated as the default activity class whenever we deal with the Maps API.


MapView – This is a class that extends the View and the ViewGroup classes of Android. It provides the basic functionality expected on a Map like responding to key presses or touch and allowing zooming etc. It also provides a controller object that helps us manipulate the Map view programmatically. We will see how, in the example later.


Now that we have understood the basics of the Maps API, let us jump into the example.


Step 2: To begin with, when you create an android project in Eclipse, instead of choosing the target name as Android 1.5, you need to select the target as Google APIs. This ensures that the project has the map API external libraries along with android 1.5 SDK.


Step 3: The Activity class you create this time should not extend the standard “android.app.Activity” class but should extend the MapActivity class about which I explained earlier.


Step 4: Apart from this, you need to add the following tag in the AndroidManifext.xml in order to use the external library:


<uses-library android:name="com.google.android.maps" />


Step 5: Now let us declare the map view in main.xml in layout folder. To do so, add this element in order to display the map using MapView.


<com.google.android.maps.MapView
android:id="@+id/myGMap"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:enabled="true"
      android:clickable="true"
      android:apiKey="0YaGLMeMFKXrhzHL-uSYZSnqXqbGwE6kxF4VwFQ"
    />


Here the apikey should be what was generated by you in an earlier step 1.


 Step 6: In the activity class I set the geo point on the map and set the satellite view to false.


      myMapView = (MapView) findViewById(R.id.myGMap);
      geoPoint = new GeoPoint((int) (latitude * 1000000), (int) (longitude * 1000000));
      myMapView.setSatellite(false);


Step 7: Now you are almost ready to go. But we will try to do some programtic handling of the mapview. For that we need to get a handle to the MapController object. It is done this way:


      myMC = myMapView.getController();
      myMC.setCenter(geoPoint);
      myMC.setZoom(15);

I also set the zoom controls to be displayed with this code.


      myMapView.setBuiltInZoomControls(true);
      myMapView.displayZoomControls(true);


Step 8: Add the following permissions in the AndroidManifest.xml in order to access the maps over the internet:


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


You could execute your program now to view the map with the fixed geopoint. 


Step 9: One last step – let us add some actions to the key presses for zooming in, zooming out, viewing the satellite view, normal map view


      public boolean onKeyDown(int keyCode, KeyEvent event) {
            if (keyCode == KeyEvent.KEYCODE_I) {
                  myMapView.getController().setZoom(myMapView.getZoomLevel() + 1);
                  return true;
            } else if (keyCode == KeyEvent.KEYCODE_O) {
                  myMapView.getController().setZoom(myMapView.getZoomLevel() - 1);
                  return true;
            } else if (keyCode == KeyEvent.KEYCODE_S) {
                  myMapView.setSatellite(true);
                  return true;
            } else if (keyCode == KeyEvent.KEYCODE_M) {
                  myMapView.setSatellite(false);
                  return true;
            }
            return false;
      }


Now you can run the applications. The Google map will show up with a pointer to the geo location defined in the program. You can click on I, O, S and M for zooming in, zooming out, viewing the satellite map or the normal map respectively.


Interesting?


The complete code is downloadable here.



Obtaining a Maps API Key:


Step 1: Locate debug.keystore on your system. It is usually in the USER_HOME\Local Settings\Application Data\.android folder on windows.


Step 2: Use the keytool utility to generate certificate fingerprint (MD5). keytool utility that comes with the default JDK installation.


C:\>keytool -list -alias androiddebugkey -keys
tore .android\debug.keystore -storepass android -keypass android


It will getnerate a certificate fingerprint (MD5) in this format:


Certificate fingerprint (MD5): XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX


Step 3: Go to the page for obtaining the Maps API Key. Put your Certificate fingerprint (MD5) And get your API key for android Google Map application. On this page, paste the certificate fingerprint in the appropriate form field, and click the “Generate API Key” button. This will return a Maps API key string.


This key needs to be used along with the MapView element declared in the XML layout file as mentioned in the tutorial above.

Monday 26 October 2009

Simulate Location Change in Android Emulator

Start the Emulator
Start a command prompt
Start telnet
Then, type, o localhost 5554
This connects the telnet client to the android emulator (assuming emulator is running locally listening on port 5554. Else this connection fails)
Now type
geo fix 79.000000 13.000000 (or your latitude and longitude)
This sends the location change signal to the emulator.
NOTE: This is useful for applications built using Location APIs in Android and need to work with changes in location

Obtain Google Maps API key


Step 1: Locate debug.keystore on your system. It is usually in the USER_HOME\Local Settings\Application Data\.android folder on windows.


Step 2: Use the keytool utility to generate certificate fingerprint (MD5). keytool utility that comes with the default JDK installation.


C:\>keytool -list -alias androiddebugkey -keystore .android\debug.keystore -storepass android -keypass android


It will getnerate a certificate fingerprint (MD5) in this format:


Certificate fingerprint (MD5): XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX


Step 3: Go to the page for obtaining the Maps API Key. Put your Certificate fingerprint (MD5) And get your API key for android Google Map application. On this page, paste the certificate fingerprint in the appropriate form field, and click the “Generate API Key” button. This will return a Maps API key string. 


The key can be used in the Maps Application by pasting it in the MapView element in the XML layout file where appropriate.

Monday 12 October 2009

Shared Preferences | Android Developer Tutorial (Part 13)


We saw in an earlier tutorial (Part 12) how data can be stored in SQLDB. However, many applications may provide a way to capture user preferences on the settings of a specific application or an activity. For supporting this, Android provides a simple set of APIs.


Preferences are typically name value pairs. They can be stored as “Shared Preferences” across various activities in an application (note currently it cannot be shared across processes). Or it can be something that needs to be stored specific to an activity (which is not discussed here).


The context object lets you retrieve SharedPreferences through the method Context.getSharedPreferences().


In my example, I will set 2 preferences i.e. MyName and MyWallpaper in one activity i.e ManageSharedPref.java. Retrieve these values in the next activity – ViewSharedPrefs.java. The second activity displays my preferred name in a list view and also resets the android wallpaper to the image that I had set as a preferred wallpaper in the first activity. When you run this application, if you come back to the home, you will see the wall paper is reset.


Here is the code in ManageSharesPrefs:


SharedPreferences myPrefs = this.getSharedPreferences("myPrefs", MODE_WORLD_READABLE);
        SharedPreferences.Editor prefsEditor = myPrefs.edit();
        prefsEditor.putString(MY_NAME, "Sai");
        prefsEditor.putString(MY_WALLPAPER, "f664.PNG");
        prefsEditor.commit();
       
First, I obtain a SharedPreferences object making it readable by all. The first parameter is a name of a file that stores my preferences. This automatically creates the xml file if it does not exist and then stores in the same.


Next, I edit it. That creates an editor object, using which I input my preferences. Here, for the wall paper, I have put an image name. I also need to push the actual image file into the android storage which I do this way.


adb push <local> <remote>


In this case it is


adb push f664.PNG /data/misc/wallpaper/f664.PNG


This command creates a folder called wallpaper in /data/misc and copies the f664.PNG file from my current location to the android storage.


When I click the “View Shared Preferences” button, I am taken to the next activity. Here is the code in ViewSharedPrefs that gets executed:


        SharedPreferences myPrefs = this.getSharedPreferences("myPrefs", MODE_WORLD_READABLE);
        String prefName = myPrefs.getString(MY_NAME, "nothing");
        String wallPaper = myPrefs.getString(MY_WALLPAPER, null);
       
        if(wallPaper != null) {
            try {
                  Bitmap bm = BitmapFactory.decodeFile("/data/misc/wallpaper/"+wallPaper);
                  Log.d(getClass().getSimpleName(),"Wallpaper name is: "+ wallPaper);
                  setWallpaper(bm);
                  Toast.makeText(this, "Wall paper has been changed." +
                              "You may go to the home screen to view the same", Toast.LENGTH_LONG).show();
            } catch (FileNotFoundException fe){
                  Log.e(getClass().getSimpleName(),"File not found");
            } catch (IOException ie) {
                  Log.e(getClass().getSimpleName()," IO Exception");
            }
           
        }
        ArrayList<String> results = new ArrayList<String>();
        results.add("Your Preferred name is: " + prefName);
      this.setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,results));

There are 3 steps to understand here:


1.    Step 1: Retrieve the shared prefs data from the object.


        SharedPreferences myPrefs = this.getSharedPreferences("myPrefs", MODE_WORLD_READABLE);
        String prefName = myPrefs.getString(MY_NAME, "nothing");
        String wallPaper = myPrefs.getString(MY_WALLPAPER, null);

2.    Step 2: Display the name
        ArrayList<String> results = new ArrayList<String>();
        results.add("Your Preferred name is: " + prefName);
      this.setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,results));

3.    Step 3: Reset the wall paper.
        if(wallPaper != null) {
            try {
                  Bitmap bm = BitmapFactory.decodeFile("/data/misc/wallpaper/"+wallPaper);
                  Log.d(getClass().getSimpleName(),"Wallpaper name is: "+ wallPaper);
                  setWallpaper(bm);
                  Toast.makeText(this, "Wall paper has been changed." +
                              "You may go to the home screen to view the same", Toast.LENGTH_LONG).show();
            } catch (FileNotFoundException fe){
                  Log.e(getClass().getSimpleName(),"File not found");
            } catch (IOException ie) {
                  Log.e(getClass().getSimpleName()," IO Exception");
            }
           
        }
It is this simple. The complete code is available here.