Wednesday, April 28, 2010

LIRR Android App

I have released an app for Android that allows you to quickly access the Long Island Rail Road schedules. You can drill down by branch or alphabetically, or you can pick a station from the map. It also lets you pick the last viewed station, with the direction of travel and day of week.

NOTICE: I AM NOT AFFILIATED WITH THE MTA (METROPOLITAN TRANSPORTATION AUTHORITY), WHICH OPERATES THE LONG ISLAND RAIL ROAD.

Click here or scan this bar code with your phone to see the app in the Market:



Here are two screenshots:



















Tuesday, April 7, 2009

Android's Image ContentProvider and Directories

One of the things to which I didn't find and easy answer on Google is how to work with the Images ContentProvider per directory. It's easy to reference all images the ContentProvider knows, but here's how to work with images in a specific directory.

Saving an image file and updating the ContentProvider
When you save an image file to the SD card, it will not automatically show in the 'Pictures' app. To have it appear there, you have to notify the ContentProvider that is responsible for images that a new image file has been created. Here's how it's done:


private void downloadImage(String imageUrl) throws InterruptedException {
InputStream inputStream = null;
OutputStream outStream = null;
try {
URL url = new URL(imageUrl);
inputStream = url.openStream();
String filepath = getFilePath(imageUrl);
String filename = getFileName(imageUrl);
File imageDirectory = new File(filepath);
File file = new File(filepath + filename);
if (file.exists() == false) {
String path = imageDirectory.toString().toLowerCase();
String name = imageDirectory.getName().toLowerCase();
ContentValues values = new ContentValues(7);
values.put(Images.Media.TITLE, filename);
values.put(Images.Media.DISPLAY_NAME, filename);
values.put(Images.Media.DATE_TAKEN, new Date().getTime());
values.put(Images.Media.MIME_TYPE, "image/jpeg");
values.put(Images.ImageColumns.BUCKET_ID, path.hashCode());
values.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, name);
values.put("_data", filepath + filename);
ContentResolver contentResolver = getApplicationContext().getContentResolver();
Uri uri = contentResolver.insert(Images.Media.EXTERNAL_CONTENT_URI, values);
outStream = contentResolver.openOutputStream(uri);
byte[] buffer = new byte[1024];
int count;
while ((count = inputStream.read(buffer)) != -1) {
if (Thread.interrupted() == true) {
String functionName = Thread.currentThread().getStackTrace()[2].getMethodName() + "()";
throw new InterruptedException("The function " + functionName + " was interrupted.");
}
outStream.write(buffer, 0, count);
}
}
}
catch (IOException e) {
}
finally {
if (inputStream != null) {
try {
inputStream.close();
}
catch (IOException e) {
}
}
if (outStream != null) {
try {
outStream.close();
}
catch (IOException e) {
}
}
}
}


The magic piece here is that the ContentProvider is aware of each image file's directory through the BUCKET_ID field. We create a File object that points to the desired directory and we populate the BUCKET_ID with the hashCode() value of the path returned by the toString() function of the File object. Also note, that you have to drop this path to lowercase before obtaining the hashCode().

Choosing an image from one directory
If in your app, you need the user to pick an image from a directory, you can launch the 'Pictures' app to provide that functionality for you. You can start the 'Pictures' app using an 'android.intent.action.PICK' Intent. This will easily let you choose an image from all images across the SD card, but if you need to limit it to a single directory, you again have to work with the BUCKET_ID. Here's the code:

final int CHOOSE_AN_IMAGE_REQUEST = 2910;
String directory = "/sdcard/someDirectory/";
Uri uri = Images.Media.INTERNAL_CONTENT_URI.buildUpon().appendQueryParameter("bucketId", getBucketId(directory)).build();
Intent intent = getIntent();
intent.setData(uri);
intent.setAction(Intent.ACTION_PICK);
startActivityForResult(Intent.createChooser(intent, "Choose a Viewer"), CHOOSE_AN_IMAGE_REQUEST);


public static String getBucketId(String bucketName) {
bucketName = bucketName.toLowerCase();
if (bucketName.charAt(bucketName.length() - 1) == '/') {
bucketName = bucketName.substring(0, bucketName.length() - 1);
}
return Integer.toString(bucketName.hashCode());
}


Once the user chooses an image, your Activity's onActivityResult() function will be called. You can get the chosen image's uri in the following way:


protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == CHOOSE_AN_IMAGE_REQUEST) {
Uri chosenImageUri = data.getData();
...
}
}
}

Monday, April 6, 2009

Android's StateListDrawable and RadioButton Example

A radio button on the Android platform is drawn based on a label and a set of images contained in a StateListDrawable. You can create an image radio button by setting the text label to empty and setting your own images. There is no need to override the class or implement your own.

You can create your own radio buttons either via xml declaration or via code. You can see this in the Android source code but I will describe both methods in the rest of this post.

In the Android source code, you want to have a look at the following files:
StateListDrawable.java
DrawableContainer.java

RadioButton.java
CompoundButton.java

btn_radio.xml


XML DECLARATION:
When you declare your radio button, add the tag android:button="@drawable/resize_button". In your res/drawable/ directory, you must now have a resize_button.xml file that looks like this:

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_checked="true"
android:state_window_focused="false"
android:drawable="@drawable/resize_button_on" />
<item
android:state_checked="false"
android:state_window_focused="false"
android:drawable="@drawable/resize_button_off" />
<item
android:state_checked="true"
android:state_pressed="true"
android:drawable="@drawable/resize_button_on_pressed" />
<item
android:state_checked="false"
android:state_pressed="true"
android:drawable="@drawable/resize_button_off_pressed" />
<item
android:state_checked="true"
android:state_focused="true"
android:drawable="@drawable/resize_button_on_selected" />
<item
android:state_checked="false"
android:state_focused="true"
android:drawable="@drawable/resize_button_off_selected" />
<item
android:state_checked="true"
android:drawable="@drawable/resize_button_on" />
<item
android:state_checked="false"
android:drawable="@drawable/resize_button_off" />
</selector>


The order of these items seems to matter, but I haven't had the time to delve into the details. It looks like it's caused by the matching algorithm that picks a drawable from the list based on the current state. You'll notice that each image that represents a radio button state has one or more state values associated with it. The radio button class sets the state flags and the Drawable picks the best matching image to display.

By declaring the xml code just shown, I now have a graphical resize radio button that can be checked off. It won't have a label and it will have it's own icon with the usual radio button states.

VIA CODE:

 StateListDrawable drawables = new StateListDrawable();
int stateChecked = android.R.attr.state_checked;
int stateFocused = android.R.attr.state_focused;
int statePressed = android.R.attr.state_pressed;
int stateWindowFocused = android.R.attr.state_window_focused;
drawables.addState(new int[]{ stateChecked, -stateWindowFocused}, getButtonWithThumbnail(R.drawable.button_on , thumbnailBitmap));
drawables.addState(new int[]{-stateChecked, -stateWindowFocused}, getButtonWithThumbnail(R.drawable.button_off , thumbnailBitmap));
drawables.addState(new int[]{ stateChecked, statePressed }, getButtonWithThumbnail(R.drawable.button_on_pressed , thumbnailBitmap));
drawables.addState(new int[]{-stateChecked, statePressed }, getButtonWithThumbnail(R.drawable.button_off_pressed , thumbnailBitmap));
drawables.addState(new int[]{ stateChecked, stateFocused }, getButtonWithThumbnail(R.drawable.button_on_selected , thumbnailBitmap));
drawables.addState(new int[]{-stateChecked, stateFocused }, getButtonWithThumbnail(R.drawable.button_off_selected, thumbnailBitmap));
drawables.addState(new int[]{ stateChecked }, getButtonWithThumbnail(R.drawable.button_on , thumbnailBitmap));
drawables.addState(new int[]{-stateChecked }, getButtonWithThumbnail(R.drawable.button_off , thumbnailBitmap));
thumbnailBitmap.recycle();
thumbnailBitmap = null;
thumbnailButton.setButtonDrawable(drawables);
thumbnailButton.setId(viewId);
layerThumbnails.addView(thumbnailButton);
layerThumbnails.check(thumbnailButton.getId());


The selector tag in the xml file corresponds to the StateListDrawable class. Items are added with addState(). Here, I've copied the basic button drawables from android's jar file, such as R.drawable.button_off and R.drawable.button_off_pressed. I created my own function, getButtonWithThumbnail(), that takes a bitmap and combines it with the basic button image to create a custom radio button on the fly.

Notice that the true and false values of the states are specified in code using positive and negative values of the android.R.attr.state_<*> integer variables and the order in which the images are added to the drawable is the same as in the xml declaration earlier. Finally, I add the StateListDrawable to my radio button, give it an id, add it to a radio group, and simulate a click on the button by calling the check() function on the button's radio group.

Thursday, January 8, 2009

Write Your Cover Letter As If You Are Writing To Your Best Friend

Many job seekers write stiff cover letters and resumes that sound fake, copied, and trite. They read like every other cover letter that has crossed a human resources manager's desk. They all look the same to that manager, and none of them will get noticed. You hear the same advise everywhere: make your cover letter stand out! I couldn't agree more!

My one piece of advise is to write your cover letter as if your best friend is the HR manager who will be reading it!

This technique will ensure that you don't use trite phrases, that you keep it as short as possible, and that you will not embellish your resume and cover letter. After all, your best friend is very familiar with you so you wouldn't be able to lie. A suggestion derived from this idea is that you should address the person by first name only with no last name if you know the name of the cover letter's first reader. This will make you sound friendlier and closer. If you don't know the name of your first reader, you might consider foregoing the "Dear Sir/Madam" salutation, which sounds very distant and uninvited, so that you won't put the reader on the defensive from the first line. So allow me to provide some examples:

- You won't be using words like "furthermore" that create a structured, stiff read. When was the last time you told your best friend "furthermore"?
- You won't use stiff phrases like "I became versed in the dynamics between customers, consultants, developers, and the final product."
- You won't use phrases like "I am painstakingly detail oriented." Sure, I believe you, even though no one else would.
- You won't use half the page to repeat the jobs you've had and the skills you possess, all of which is already on the resume.
- You won't close with phrases like "I believe I have the experience and passion for which you are looking, so I have enclosed my résumé." A simple "I have enclosed my résumé" will do and will get the point across.

Is this technique going to help, hurt, or have no effect? Some companies will find your style too casual while others might find it too formal. This can work to your advantage as a filter for the type of company that will reply to you. Ideally, you know what kind of job you want and you seek it until you find it instead of just applying to anything and everything that sounds plausible and taking the first offer that is good enough. If you know you want to work in a relaxed environment, you should write in a more casual style, ensuring that stiff companies will not bother contacting you. But my main interest in a more casual format is that it will give your cover letter the much coveted ability to stand out. Until everybody starts doing the same, that is.

Saturday, August 9, 2008

Communication between Views in the Eclipse IDE

One of the head-scratchers that come up after a bit of programming for Eclipse using SWT or programming your own app using Eclipse as a backbone is that you have to communicate between views. I recently bumped into this while developing my own software, so I thought I'd share how it's done very simply without singletons or any other gimmicks.

public class InfoView extends ViewPart {
private TransactionsView transactionsView;
public void createPartControl(Composite parent) {
getSite().getWorkbenchWindow().getPartService().addPartListener(partListener);
}
private IPartListener partListener = new IPartListener() {
public void partOpened(IWorkbenchPart part) {
if (part instanceof TransactionsView) {
transactionsView = (TransactionsView)part;
}
}
}
private void myOwnFunction() {
if (transactionsView != null) {
transactionsView.getTransactions();
}
}
}

That's all there is to it. When your view is created in createPartControl() tell Eclipse to add a listener that gets notified whenever a part-related event occurs and you'll know when the TransactionsView is opened. Some other part events you can listen to are:

public void partClosed(IWorkbenchPart part){}
public void partActivated(IWorkbenchPart part) {}
public void partBroughtToTop(IWorkbenchPart part) {}
public void partDeactivated(IWorkbenchPart part) {}

You'll have to make sure InfoView gets added to the perspective before TransactionsView otherwise the TransactionsView will be created before you add the listener and you won't get the notification.

Keywords for beloved Google:
eclipse swt
communicate betweeen views
call functions in another view
reference to another view
access another view's members
access another view's variables

Tuesday, May 6, 2008

Disassembling the Canon Powershot A650 Digital Camera

My Christmas present to myself in 2007 was the Canon Powershot A650 digital camera. I like this particular line of cameras, the A620, 640, 650. Mainly because of the AA batteries. I use rechargable batteries and they last much much longer than other cameras' custom lithium ion batteries do. But that's besides the point. The point is that I dropped the camera three days before my trip to St. Maarten (or Martin, if you like the French more). I dropped this camera once before and the only damage was a little dent in one of the corners. The second time around though, I ruined it. The lens did not have the full range of motion anymore and the camera refused to work because of the lens. Looking around on the web, I find that the lens is the weak point when dropping a camera. (To make sure this is indeed the case, when I have a bit more money to waste, I'll buy a statistically significant number of cameras and drop them.)

Seeing the camera is busted and I have nothing further to lose, I took it apart.

The process is pretty straightforward. I looked at the parts of the camera and how they come together, took the screws out, wiggled it to see what else is still holding it together, unplugged a few connectors, and got to the lens. The tricky part is making sure you remove as few screws as necessary so that it's won't be any more complicated than it needs to be.

Turns out the flimsy plastic that is used to guide the lens broke when I dropped the camera. I glued the piece and put the camera back together. Keeping track of the screws is difficult and I am sure I used the wrong screws in some places but I did put the camera back together. Except for two screws that were left over. Nonetheless, the camera looked solid, so I ignored the two screws.

I held my breath and powered the camera. The only problem was that even though the lens moved fine, it made a terrible noise. Also, I soon found out that the camera did not focus well in video mode anymore.

The LCD started going white a few days later. St. Maarten has a world-famous airport with a runway that ends right next to a beach, so planes land very very low--to everybody's delight. To make it even more exciting, they also land 747's on this runway! I looked up the flight schedules hoping a 747 would land during the four days I was in St. Maarten and sure enough there was one scheduled for the second day. There I was on the beach with my girlfriend admiring all the small and medium planes landing that afternoon as the weather alternated between sunshine and small showers when the big one finally showed up on the horizon! Everybody scrambled for what they considered the best photo spot and got ready. Literally three seconds before I wanted to press the shutter, the LCD went white! I fumbled with it for a second, gave up, looked through the viewfinder that was half blocked by the filter adapter and instinctively pressed the shutter three times as the plane approached the beach and passed over it. I followed it with my gaze as it landed and slowed down to taxiing speed. I got back to my camera and realized it's time to go St. Maarten's famous shopping strip and buy a new camera--pronto! Later, I found the LCD worked when undocked a bit but whenever I clicked it into the holder, the LCD turned white. For all the bad timing, I did get the shot! http://www.panoramio.com/photo/8273379. Then I got a replacement camera.


I took the camera apart a second time after I returned home from vacation. This time I managed to break one of the two ribbon cables that go into the lens assembly. Fate sealed! I reassembled the camera and this time I found myself holding ten screws I forgot to put back in, but the camera was still holding together well!

What follows is my guide in words and pictures to taking this camera apart. Read it over before starting the disassembly.

Tools needed:
- Set of small screwdrivers. The screws have Philips heads. A thin flathead screwdriver is useful for prying apart the plastic latches in the camera.
- Can of compressed air.

Take off the filter adapter silver ring around the lens by pressing the button next to it. Look at the camera from every angle and take out all the screws you can find. You should come up with a system to track where each screw came from because the screws that you will remove have several types of threads and several lengths. For each screws or group of screws, I ripped a small piece of paper and wrote on it where the screws belong. I formed it into a "container" by creasing it with my thumbs and my index fingers. The problem is that halfway through, you don't know how to name the locations anymore. Probably the easiest thing is to print the images on this site and number the screw holes in the pictures as you remove each screw. This will also make sure you put all the screws back in when you re-assemble the camera.





Next, pry off the back half of the case. Notice it's held in place by three latches, so you have to raise the top a little:


This is how the back looks without the case:


and the front (without the lens assembly):


Next, remove the piece that has the shutter and the zoom controls. The main obstacle is the latch and the ribbon cable:




To remove the LCD, unscrew the two screws shown below and unplug the yellow and the blue connectors:


While you're at it, also remove the ribbon cable that you see in the corner next to the yellow and the blue connectors.

To remove the LCD, there's also this screw and one or two others:


Look at the metal case and remove the screws that hold it together. When you get the flash unit loose, short-circuit the capacitor to discharge it so you won't accidentally electrocute yourself. I used a pair of scissors WITH PLASTIC HANDLES. Touch the two points shown below to discharge the capacitor and to see a decent-sized spark in the process:

NOTE: This is the bad way to discharge a capacitor because it creates a very large current for a brief period of time, possibly destroying the capacitor. You're better off using a resistor to drain the capacitor over ten seconds or so.

Take out the screws that hold the viewfinder in place.

Now comes the fun part: disassembling the lens assembly. Start by taking off the little cover on top of the lens held by a spring if it hasn't fallen off already:


This should leave you with the following pieces held together by cables:




Slowly play with the back cover of the lens assembly. It's held together by a few latches so try not to break them. I broke one or two but I reassembled the lens assembly without any problems. The back cover snapped back into place.


Once you remove the back cover, a few gears will fall out that were connected to the little motor:


Taking apart the lens assembly is by far the trickiest and most painstaking part. The lens assembly is composed of a few plastic cylindrical pieces that have diagonal tracks to guide the other cylinders. When one of the cylinders reaches the end of the track, it pops off because the end of the track is open. Try to remember how every piece looked and fit in before you remove it. It will save you a lot of time and frustration.


Note, Piece 4 can be decomposed further.

Also, be very careful with the two ribbon cables that go into the lens assembly; I managed to break one of them at some point. I moved to another house while the camera was apart, so I stored everything in a few plastic bags and when I took them out two weeks later, one of these two ribbon cables was ripped.
It's also useful to have a can of compressed air to clean the lens of dust as you are reassembling it.

At the end of the process, you will have the following pieces:

As you see, I removed 37 screws to get to this point.

Here's my Crazy Glue job:

The plastic here doesn't work well with Crazy Glue. One solution is to go to CVS and among the instant glues they sell is a brand of glue that is packaged together with a tube of primer. The primer made the plastic surfaces hold together much better.

Okay, time to re-assemble everything! I'll refer to the cylindrical parts of the lens numbered in red in the previous pictures. The green line shows the ring edge of Piece 4. Rotate the ring until the opening in the ring lines up with the opening of the track in Piece 3. Place Piece 5 inside Piece 6 and rotate them until Piece 5 slips in. Take the combined piece and place it so that the pins from Piece 5 slips through the openings in the ring of Piece 4 and the openings in Piece 3. Push Piece 6 down so that its pins slip through the openings of Piece 2. Here's how it looks:


Rotate all the pieces back into place so the lens assembly shrinks into the retracted position.
Place the three gears inside and snap the back into place. To complete the lens, put the cover with the spring back in place--without permanently deforming the spring. Now go the steps in reverse order to re-assemble the camera.

Good luck!

Monday, May 5, 2008

Winamp Plugin - Music Archiver

Wondering where all your hard disk space is gone? Look at that, it's being taken up by all that Celine Dion music! That's easy to fix: just find the offending directory, press delete, and you just freed two gigabytes of hard disk space!

But it's not always that easy. I found myself with song after song I don't like anymore throughout my music collection and no easy way to clean up, so I created a Winamp plugin that allows me to eliminate those cheesy songs one by one as they come up when I listen with Winamp.

The plugin is at http://www.winamp.com/plugins/details/221543.

It adds a system tray icon that you can click when the currently playing song is NOT music to your ears. The main idea was to recreate the directory structure of the music collection in another root directory in order to archive the songs I don't like anymore and maybe even delete them. So for example, if I have "C:\My Music\New\Singles\Madonna - 4 Minutes.mp3", I click the system tray icon and the file moves to "C:\My Music to Archive\New\Singles\Madonna - 4 Minutes.mp3".