Archive
Android – disappearing emulator ? Restart adb server
A screen shot illustrating a running emulator that does not appear in the list of attached devices
An emulator within the devices window
To solve this, you should take the following steps:
# Device is running but not showing up [497][nicholasdunn: /Users/nicholasdunn]$ adb devices List of devices attached # Kill and restart [498][nicholasdunn: /Users/nicholasdunn]$ adb kill-server [499][nicholasdunn: /Users/nicholasdunn]$ adb start-server * daemon not running. starting it now * * daemon started successfully * # Device appears, but is listed as offline [500][nicholasdunn: /Users/nicholasdunn]$ adb devices List of devices attached emulator-5554 offline # One more invocation of adb devices should get it recognized [501][nicholasdunn: /Users/nicholasdunn]$ adb devices List of devices attached emulator-5554 device
If this happens to you frequently (it does to me), you can create an alias within your .bash_profile file (~/.bash_profile):
alias adb-restart='adb kill-server; adb start-server; adb devices; adb devices'
Reload your .bash_profile file:
source ~/.bash_profile
You can then invoke it from the terminal by typing adb-restart. Sometimes one invocation of adb devices is enough to have the emulator show up as a device; others requires two. Not sure why that is. To be safe I’m including two in the script.
Eclipse + Android + SVN = fail
If you are developing a project in SVN (I’m sorry for your predicament) and using Eclipse, please heed my advice. Otherwise you could unintentionally delete your source directory during a routine cleanup.
Now, how could you possibly do that? you might wonder. Are you incompetent? Well, maybe, but not in this case. The situation was this: I was about to make a commit of some changes to the code and did a svn status before committing to ensure that everything was as I wanted it to be. I noticed that there were dozens of files in the bin directory that either had question marks next to them (.class files) or showed up with exclamation points next to them (indicating that SVN thought they’d gone missing). Given that the binary class files do not belong in version control, I went ahead and did a svn rm -rf bin (recursively delete all the files under bin). I went ahead and finished the commit. Later I went to make another commit and I got an error telling me that the src folder didn’t exist in the svn repository. Horrified, I my unix history and then the svn commit log:
529 svn rm –force bin/
530 svn ci -m “Bin should not be under version control.”
Revision 249
Author: ndunn
Date: Mon Jul 26 14:52:14 2010 UTC (62 minutes, 34 seconds ago)
Log Message:
Bin should not be under version control.
trunk/projname/src/ deleted
Um. What? I’m pretty sure bin != src. Well. You’d think that. But if you’re using Eclipse and haven’t dived in four menus deep, you’d be wrong.
You see, for some reason Eclipse copies all the files from the src folder into the bin folder when you build the project. Why it does that, I’m not sure. I’d love to know why. Regardless of the reason, all of the files in the src are copied. Including… the hidden .svn folders. These folders are how subversion keeps track of the changes to your files. The problem is, since the .svn folders were copied, and bin was deleted, it was exactly the same to svn as if I had deleted src. Which is why my src folder disappeared.
How do you work around this? Well, I mentioned earlier that by default eclipse copies all of the files from src to bin. You can add filters so that certain files/extensions are ignored, if you know where to look. In Eclipse, go to Preferences -> Java -> Building -> Output Folder and make sure that *.svn is on the line for filtered resources. It will prompt you to rebuild your project. Once it does so, you will not have this potential mistake looming over your head.
Finally, here’s the svn command you need to revert a folder if you accidentally delete it and check the deletion into source control. Let’s assume you deleted the folder in revision n. Then you want to fetch the status of that folder at n – 1
n = 249
svn copy -r248 -m "Restore deleted trunk/src" svn+ssh://username@company/path/to/trunk/src@248 svn+ssh://username@company/path/to/trunk/src
Thanks to the android developers group for helping me figure out what was going on; see here for details.
I have submitted a bug / feature enhancement request to the Eclipse developers so that the default behavior is a bit more sane. You can find that bug report here. The commenters mention that installing the svn plugin for Eclipse fixes the problem, but I don’t think I or anyone else should have to install something just to have sensible behavior.
The StackOverflow post giving a shorter synopsis of the problem can be found here.
Conclusion:
Lots of Android developers use Eclipse to develop their projects due to the plugin support available. I’d wager a fair number of them use SVN as well for their source control. They should be very wary about the default behavior of Eclipse, and ensure that they filter to remove .svn files from being copied over to their src folder. Take it from me – it’s not a good feeling seeing a commit message with your name on it deleting the src folder. Or you could use git and not have to worry about any of these problems…
Android: Principle of least surprise violation in GPS emulation
Some of the most viewed posts on this blog have been about Android development, namely some workarounds for bizarre bugs that Google *still* has not fixed, months later. I haven’t touched Android in a few months, but recently have started to dive back in. Here’s yet another instance where an Android related piece of software performs completely counter-intuitively.
When developing an Android application, I often use the emulator rather than an actual hardware device. In order to test GPS related functionality, you can either send simulated GPS events through the Dalvik Debug Monitor Service (DDMS) via Eclipse or through the Android terminal via telnet. I’ll detail surprising bugs/defects in both ways.
DDMS
The DDMS Eclipse view is available after installing the ADT plugin, and it’s absolutely crucial in order to see logging messages produced from your application (“LogCat”). It also allows you to send GPS coordinates, as the following screenshot shows.
Unfortunately there is a bug in this software that drove me up the wall, and I never would have figured it out myself. I was running into the problem where the first GPS coordinate sent would be received by the emulator, but all subsequent ones would not. It turns out the problem has to do with locales and decimals being treated as commas, or vice versa. See the following Google bug report for more details. The bug has been open over a year; fortunately it looks like it’s slated to be fixed in the next SDK release.
Telnet
If you telnet into your emulator instance, you have access to the Android console environment.
telnet localhost 5554
Android Console: type ‘help’ for a list of commands
OK
One of the commands you can send is fix, which send a latitude longitude pair to the emulator. Well, that’s what I assumed it did. After wondering why all my locations were were coming out incorrectly, I read the documentation a little more carefully.
fix <longitude> <latitude> [<altitude>] | Send a simple GPS fix to the emulator instance. | Specify longitude and latitude in decimal degrees. Specify altitude in meters. |
There is a VERY strong convention to specify latitude before longitude. (“latitude and longitude” returns 4,240,000 results as opposed to 542,000 for “longitude and latitude”) Having this command take arguments in the opposite order is very surprising and counter-intuitive. I notice that the DDMS screen has it longitude, latitude as well, but even within the Android APIs, you specify the latitude first!
I realize I should have read the documentation first, but it still is a flaw that the software behaves in unexpected manners (it violates the Principle of Least Surprise/Astonishment), and inconsistent with how API calls in the rest of the OS work. If someone has an explanation for why it’s written this way, I’d love to hear it.
Edit: Later I learned that KML has the same convention, longitude followed by latitude. This corresponds with the x,y ordering conventional in math, so it’s perhaps not so surprising after all. This ordering problem is fairly minor in the grand scheme of things, and reflects more on my own inexperience with geospatial APIs than any fault of Android itself.
Android: Dialog box tutorial
Hi folks,
There’s a lot that’s been written about the evils of dialog boxes , those little boxes that pop up to ask you how whether you’re sure you want to do action X, or provide some information Y. The real issue with most of these dialog boxes is that they block the user interface, stealing the attention of the user, and disallowing him to deal with what he was doing until he deals with this interruption.
I agree that they are overused and often can be eliminated entirely. For instance, instead of popping up a dialog box asking whether you’re sure you want to delete something, just do the deletion and provide a mechanism for them to undo their mistake. Gmail does this well; the problem is that in general it’s much more difficult to provide an undo mechanism than it is to shove a dialog in the user’s face, make him choose an option he might not fully understand, and then absolve oneself of the consequences when he deletes something he didn’t intend to.
Philosophical debate aside, it’s still useful to be able to use a dialog box in a pinch. I will step through the code to illustrate how to do so in Android.
Android provides a useful Builder implementation for Dialogs. I’ll write a post about the niceness of the Builder design pattern eventually, but suffice to say, they allow a nice mechanism for specifying optional arguments rather than having dozens of overloaded constructors that take in various arguments. When all the arguments have been provided to the Builder through a series of chained method invocations, you convert the Builder object into the object it creates through a final create() command.
The class used to create dialog windows is AlertDialog while the builder object I mentioned earlier is AlertDialog.Builder . Because the dialog will be displayed on the screen, we need to provide the builder object with the Context in which it should render itself.
AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setCancelable(true); builder.setIcon(R.drawable.dialog_question); builder.setTitle("Title"); builder.setInverseBackgroundForced(true); builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.setNegativeButton("No", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); AlertDialog alert = builder.create(); alert.show();
This is the basic code you need to create a dialog box that pops up, has yes and no option, and dismisses itself gracefully when either of those two options are clicked.
Now, if you’re used to Java’s swing dialog boxes, you might be surprised to see the listeners attached to the buttons in the setNegativeButton and setPositiveButton methods In Swing, the dialog blocks all other tasks until the dialog is dismissed; as such it’s sufficient to check the return code of the dialog, and then take action based on that value. That doesn’t fit into the Android paradigm, however, because at all times the app must be responsive and able to be interrupted by an incoming phone call or text message, for instance. Thus the need for the asynchronous button listeners.
This complicates things somewhat; how do I perform business logic within the context of the dialog? How do I get handles to the object or objects on which I need to perform actions? Unlike some other languages, one cannot pass methods as objects in Java. As such, we should use a Function Object to the dialog, said object encapsulating the business logic that must happen when a button is pressed.
I choose to implement my function object with the Command design pattern; the source of my Command interface is as follows:
/** * Functor object that allows us to execute arbitrary code. * * This is used in conjunction with dialog boxes to allow us to execute any * actions we like when a button is pressed in a dialog box (dialog boxes * are no longer blocking, meaning we need to register listeners for the various * buttons of the dialog instead of waiting for the result) * * @author NDUNN * */ public interface Command { public void execute(); public static final Command NO_OP = new Command() { public void execute() {} }; }
I provide a wrapper around the Command object in order to make the API easier to make the dialog boxes.
public static class CommandWrapper implements DialogInterface.OnClickListener { private Command command; public CommandWrapper(Command command) { this.command = command; } @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); command.execute(); } }
Combining this with a variation of the earlier code, we have a general purpose method that returns a Dialog confirming whether we want to delete something.
private static final CommandWrapper DISMISS = new CommandWrapper(Command.NO_OP); public static AlertDialog createDeletionDialog(final Context context, final String name, final Command deleteCommand) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setCancelable(true); builder.setIcon(R.drawable.dialog_question); builder.setTitle("Are you sure you want to delete \"" + name + "\"?"); builder.setInverseBackgroundForced(true); builder.setPositiveButton("Yes", new CommandWrapper(deleteCommand)); builder.setNegativeButton("No", DISMISS); return builder.create(); }
Here is this method used in context:
// When the delete button is clicked, a dialog pops up confirming deleteButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Command delete = new Command() { public void execute() { deleteFromDatabase(personID); } }; AlertDialog deletionDialog = DialogUtils.createDeletionDialog(ShowPlaceActivity.this, personName, delete); deletionDialog.show(); } });
In conclusion, you’ve seen how Android provides a nice Builder interface for creating dialogs, and how these dialogs differ from those of Java. Furthermore, you’ve seen how the Command design pattern can encapsulate business logic and be executed the instant a button is pressed.
Android – ItemizedOverlay + ArrayIndexOutOfBoundsException / NullPointerException workarounds
There’s some gotchas to be aware of when using the ItemizedOverlay class Google provides.
Here’s the situation (a fairly common one): You have a dynamic list of Icons you wish to display on a map. The list can grow and shrink. You might think the following would work:
public class CustomItemizedOverlay extends ItemizedOverlay { private ArrayList mOverlays = new ArrayList(); public CustomItemizedOverlay(Drawable defaultMarker, Context mContext, MapView view) { super(boundCenterBottom(defaultMarker)); } @Override protected COINOverlayItem createItem(int i) { return mOverlays.get(i); } @Override public int size() { return mOverlays.size(); } public void addOverlay(COINOverlayItem overlay) { mOverlays.add(overlay); populate(); } public void clear() { mOverlays.clear(); populate(); } }
Seems like a reasonable assumption, doesn’t it? If you try to use this class, you will immediately see a problem – if you do not add any items to the list before it is displayed, you will get a NullPointerException. This is well documented in two separate threads; Google has marked the issue as Won’tFix. The workaround is to call populate() within the constructor. OK, that’s fine. Our new constructor looks like this:
public CustomItemizedOverlay(Drawable defaultMarker, Context mContext, MapView view) { super(boundCenterBottom(defaultMarker)); // Workaround for null pointer exception with empty list // <a href="http://osdir.com/ml/AndroidDevelopers/2009-08/msg01605.html">http://osdir.com/ml/AndroidDevelopers/2009-08/msg01605.html</a> // <a href="http://code.google.com/p/android/issues/detail?id=2035">http://code.google.com/p/android/issues/detail?id=2035</a> populate(); }
You’re not out of the woods yet, though. Say you have clicked on one of the icons on the map. Now say you somehow change your list of icons, e.g. by clearing all of them off the map. Click on the same point where the icon USED to be, and you’ll be faced with a nasty stack trace:
10-19 11:02:48.009: ERROR/AndroidRuntime(1375): java.lang.ArrayIndexOutOfBoundsException 10-19 11:02:48.009: ERROR/AndroidRuntime(1375): at com.google.android.maps.ItemizedOverlay.maskHelper(ItemizedOverlay.java:562) 10-19 11:02:48.009: ERROR/AndroidRuntime(1375): at com.google.android.maps.ItemizedOverlay.setFocus(ItemizedOverlay.java:365) 10-19 11:02:48.009: ERROR/AndroidRuntime(1375): at com.google.android.maps.ItemizedOverlay.focus(ItemizedOverlay.java:539) 10-19 11:02:48.009: ERROR/AndroidRuntime(1375): at com.google.android.maps.ItemizedOverlay.onTap(ItemizedOverlay.java:455) 10-19 11:02:48.009: ERROR/AndroidRuntime(1375): at org.mitre.coin.map.COINItemizedOverlay.onTap(COINItemizedOverlay.java:63) 10-19 11:02:48.009: ERROR/AndroidRuntime(1375): at com.google.android.maps.OverlayBundle.onTap(OverlayBundle.java:83) 10-19 11:02:48.009: ERROR/AndroidRuntime(1375): at com.google.android.maps.MapView$1.onSingleTapUp(MapView.java:346) 10-19 11:02:48.009: ERROR/AndroidRuntime(1375): at android.view.GestureDetector.onTouchEvent(GestureDetector.java:503) 10-19 11:02:48.009: ERROR/AndroidRuntime(1375): at com.google.android.maps.MapView.onTouchEvent(MapView.java:623) 10-19 11:02:48.009: ERROR/AndroidRuntime(1375): at org.mitre.coin.view.ModifiedMapView.onTouchEvent(ModifiedMapView.java:26) 10-19 11:02:48.009: ERROR/AndroidRuntime(1375): at android.view.View.dispatchTouchEvent(View.java:3368)
The source is closed, so you have no idea what is throwing the ArrayIndexOutOfBounds; it’s in code you didn’t write. Once again, there’s a workaround for it, but it’s certainly not intuitive, nor is it mentioned in the documentation. You must called setLastFocusedIndex(-1);
whenever you structurally modify the list, but before you call populate()
. The issue is documented in more detail here.
The skeleton now looks like the following:
public class CustomItemizedOverlay extends ItemizedOverlay { private ArrayList mOverlays = new ArrayList(); public CustomItemizedOverlay(Drawable defaultMarker, Context mContext, MapView view) { super(boundCenterBottom(defaultMarker)); // Workaround for bug that Google refuses to fix: // <a href="http://osdir.com/ml/AndroidDevelopers/2009-08/msg01605.html">http://osdir.com/ml/AndroidDevelopers/2009-08/msg01605.html</a> // <a href="http://code.google.com/p/android/issues/detail?id=2035">http://code.google.com/p/android/issues/detail?id=2035</a> populate(); } @Override protected COINOverlayItem createItem(int i) { return mOverlays.get(i); } @Override public int size() { return mOverlays.size(); } public void addOverlay(COINOverlayItem overlay) { mOverlays.add(overlay); setLastFocusedIndex(-1); populate(); } public void clear() { mOverlays.clear(); mapView.removeAllViews(); numItems = 0; // Workaround for another issue with this class: // <a href="http://groups.google.com/group/android-developers/browse_thread/thread/38b11314e34714c3">http://groups.google.com/group/android-developers/browse_thread/thread/38b11314e34714c3</a> setLastFocusedIndex(-1); populate(); } }
Hopefully this pops up in Google and saves some people some trouble.
Android – OverlayItem.setMarker(Drawable icon)
I’ve been developing in Android for a little over two months off and on and am finding certain things I really love and certain things I hate. This is one of the things I hate.
Android provides a nice class to manage drawing OverlayItems to a map called ItemizedOverlay; for instance you might want to display all the people in your contact list on a map. Well, you’d probably want to display a different icon for each person, right? OK, examine the API.
setMarker
public void setMarker(android.graphics.drawable.Drawable marker)Sets the marker to be used when drawing this item on the map. Setting the marker to null will cause the default marker to be drawn (the marker is null by default, so you can just skip this, instead). The marker may be drawn using any combination of the null,
R.attr.state_pressed
,R.attr.state_selected
andR.attr.state_focused
attributes.
OK, that looks perfect. Go ahead and give each OverlayItem the Drawable icon you want to use. Look at the map and… wait a minute. Nothing shows up. Why is that? It works when you haven’t specified the marker…
Well, what this method fails to inform you is that you must define the bounds of a Drawable object before you use it on a map. The definition of Drawable says
The setBounds(Rect) method must be called to tell the Drawable where it is drawn and how large it should be. All Drawables should respect the requested size, often simply by scaling their imagery. A client can find the preferred size for some Drawables with the getIntrinsicHeight() and getIntrinsicWidth() methods.
So to solve the problem we must do the following:
Drawable icon = getResources().getDrawable(someicon); icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); personItem.setMarker(icon);
I wish that an icon defaulted to having its drawable bounds be the rectangle (0, 0, width, height), but you must explicitly define these bounds.