Saturday, December 17, 2011

Android: Debugging your application on real hardware (phone/tablet) on Ubuntu 10.10

If you own an Android smartphone and want to debug your application on your smartphone instead of emulator, you need to declare your application debuggable and setup your device.

To declare your application debuggable, add android:debuggable="true" to  element in your application's AndroidManifest.xml

To setup your device, connect it to your computer with a usb cable and run following command:
adnan@adnan-laptop:~$ adb devices
List of devices attached
emulator-5554 device
???????????? no permissions
if the output contains a line with many question marks (?), as in the above example, then Ubuntu was not able to identify your device. In this case create the file /etc/udev/rules.d/51-android.rules and add following line to it:
SUBSYSTEM=="usb", SYSFS{idVendor}=="0bb4", MODE="0666"
Here the 0bb4 is the vendor id for HTC (Check the list of vendor ids at the end of this post for vendor id of your device) Now unplug and replug the usb cable connecting your device and again  run "adb device":
adnan@adnan-laptop:rules.d$ adb devices
List of devices attached
emulator-5554 device
SH1A6TR23522 device
Your device is ready now and can be used for debugging an application but before trying to install and debug your application on this device, make sure that you have selected the following options on your device:
Settings->Applications->Unknown sources
Settings->Applications->Development->USB debugging
Now when your run your app from Eclipse, you will be presented with a dialog of available emulators and devices. To run your app on device instead of emulator select the device from this dialog and your app will be installed and run on the device.



Vendor IDs:

CompanyUSB Vendor ID
Acer0502
ASUS0B05
Dell413C
Foxconn0489
Garmin-Asus091E
Google18D1
Hisense109B
HTC0BB4
Huawei12D1
K-Touch24E3
KT Tech2116
Kyocera0482
Lenevo17EF
LG1004
Motorola22B8
NEC0409
Nook2080
Nvidia0955
OTGV2257
Pantech10A9
Pegatron1D4D
Philips0471
PMC-Sierra04DA
Qualcomm05C6
SK Telesys1F53
Samsung04E8
Sharp04DD
Sony Ericsson0FCE
Toshiba0930
ZTE19D2

Wednesday, August 31, 2011

Android: How to start MusicPlayer without specifying any music file

Recently I needed to launch standard MusicPlayer from withing my app but without specifying any media file. The requirement was to show the MusicPlayer but not to play anything by default. User can then browse their music file and play any music they want, just as they would do if they launched the music player from home screen.

There are many resources on the web which discuss how to play media using media player. To do this you simply create an intent and add the media files URI to it as data and set the action to Intent.ACTION_VIEW. This will launch the player and play the specified media file. But if you skip adding media file to the intent, Android complains that no app can handle this intent.

So to open the player without media file, I looked at the code of Music Widget in Android source. The intent being used there to launch the player is created as follows
intent = new Intent(context, MusicBrowserActivity.class);
But this doesn't work if I use it as it is because this class, MusicBrowserActivity, can not be resolved. I know that the package for this class is com.android.music but I cant import this package. After trying a lot of things, I was finally able to do this using the following code.
intent = new Intent();
ComponentName comp = new ComponentName("com.android.music", "com.android.music.MusicBrowserActivity");
intent.setComponent(comp);
Hope this helps.

Wednesday, July 6, 2011

Android: How to install and uninstall an apk to Android Emulator from Ubuntu


Android emulator that is installed with the SDK does not have Android Market installed. So you can not install apps from the market. But if you can find the .apk file for the app that you are looking for you can still install it.
Recently I needed to install Zxing Barcode Scanner app to emulator so that I can use barcode scanning in my app. Zxing's website provides the apk for most recent Barcode Scanner. So I downloaded BarcodeScanner3.6.apk from project website and placed it in my Downloads folder. Then from command line I used the following command to install the apk to the emulator.
adb install ~/Downloads/BarcodeScanner3.6.apk
This installed Barcode Scanner in the emulator. Please note that this command requires a running emulator because if emulator is not running adb command can not make a connection to it.

You can also remove an installed app from emulator using adb uninstall command but this requires a little more work. To uninstall an app you need the package name for that app. If you have the source code available then you can open the AndroidManifest.xml file and see its package attribute. But if you dont have the source then you will need to do an extra step. From command line issue the following command:
adb shell
this will open a shell/terminal interface to the running emulator. Now issue the following command
cd data/app
this will change the current directory to app directory which is where the user installed apps are found. Use ls command to see all the files in this directory. In my case, as I have only installed Barcode Scanner, I see only one file i.e com.google.zxing.client.android-1.apk. Removing -1.apk from the file name will give you the package name. So to uninstall this app use the follwoing command:
adb uninstall com.google.zxing.client.android

Monday, May 23, 2011

DON'T hide pointers

I have seen alot of code where typedefs are used to create pointer types like:

typedef unsigned char *Message;
Some people might think that this is a very good thing to do or that it serves some (obscure) purpose but in my opinion such typedefs are plain wrong and evil. They cause alot of errors. Why would a sane person want to hide the fact that a variable of type Message is actually a pointer? It serves no pupose, is usually longer to type and creates disparity between declaration and use of a variable which makes code harder to understand for a new commer and a nightmare to maintain.

Sunday, May 22, 2011

Android: Display a Title on a Location Marker (an OverlayItem) in Android MapView

I recently needed to display a title over a location marker in Android MapView. I was realy surprised to find out that there is no direct functionality available for doing this. Although the second argument in OverlayItem's constructor is Title and one would think that there must be some way to display this text as title over the marker but strangely there isnt. Anyway, if you are trying to do the same thing and wondering how to do this, here is an Overlay class which will do this for you. It will display the title text over the marker in MapView:


package com.labs;

import java.util.ArrayList;

import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;

public class ResoucesOverlay extends ItemizedOverlay
{

    public ResoucesOverlay(Drawable defaultMarker)
    {
        /*Calling boundCenterBottom() on defaultMarker makes the marker image connect
          at its Bottom center to the latitude and longitude of this Overlay Item*/
        super(boundCenterBottom(defaultMarker));

        markerHeight = ((BitmapDrawable) defaultMarker).getBitmap().getHeight();

        /* This call to populate is important. Although this does not appear in the MapView tutorial
         * on Google's Android developer site, the mapview some times crashes without this call.
         */
        populate();
    }

    @Override
    protected OverlayItem createItem(int i)
    {
        return mOverlays.get(i);
    }

    @Override
    public int size()
    {
        return mOverlays.size();
    }

    @Override
    public void draw(android.graphics.Canvas canvas, MapView mapView,
            boolean shadow)
    {
        super.draw(canvas, mapView, shadow);

        // go through all OverlayItems and draw title for each of them
        for (OverlayItem item:mOverlays)
        {
            /* Converts latitude & longitude of this overlay item to coordinates on screen.
             * As we have called boundCenterBottom() in constructor, so these coordinates
             * will be of the bottom center position of the displayed marker.
             */
            GeoPoint point = item.getPoint();
            Point markerBottomCenterCoords = new Point();
            mapView.getProjection().toPixels(point, markerBottomCenterCoords);

            /* Find the width and height of the title*/
            TextPaint paintText = new TextPaint();
            Paint paintRect = new Paint();

            Rect rect = new Rect();
            paintText.setTextSize(FONT_SIZE);
            paintText.getTextBounds(item.getTitle(), 0, item.getTitle().length(), rect);

            rect.inset(-TITLE_MARGIN, -TITLE_MARGIN);
            rect.offsetTo(markerBottomCenterCoords.x - rect.width()/2, markerBottomCenterCoords.y - markerHeight - rect.height());

            paintText.setTextAlign(Paint.Align.CENTER);
            paintText.setTextSize(FONT_SIZE);
            paintText.setARGB(255, 255, 255, 255);
            paintRect.setARGB(130, 0, 0, 0);

            canvas.drawRoundRect( new RectF(rect), 2, 2, paintRect);
            canvas.drawText(item.getTitle(), rect.left + rect.width() / 2,
                    rect.bottom - TITLE_MARGIN, paintText);
        }
    }

    public void addOverlay(int latitude, int longitude, String title,
            String snippet)
    {
        OverlayItem item;

        GeoPoint geopoint = new GeoPoint(latitude, longitude);
        item = new OverlayItem(geopoint, title, snippet);
        mOverlays.add(item);
        populate();

    }

    public void addOverlay(OverlayItem overlayItem)
    {
        mOverlays.add(overlayItem);
        populate();
    }

    private int markerHeight;
    private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();

    private static final int FONT_SIZE = 12;
    private static final int TITLE_MARGIN = 3;
}
The result will look like following: