October 1st, 2009

MediaDroid now cycles images from the selected album

Using a Service and ACTION_SCREEN_OFF  I’ve successfully added a new feature to MediaDroid which cycles the images in your photo album.  Every time the screen is put to sleep, the next photo in the album is placed in the photo widget on the Home screen of your Android device.  Here’s a code snippet…

public class ChangeImageService extends Service
{
	private static final boolean LOGD = Constants.LOGD;

	private BroadcastReceiver _receiver;
	private static final String LOG_TAG = "ChangeImageService";

        @Override
	public void onCreate()
        {
		super.onCreate();

	    _receiver = new BroadcastReceiver()
	    {
	        public void onReceive(Context context, Intent intent)
	        {
	        	loadNextImage();
	        }
	    };

	    IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
	    registerReceiver(_receiver, filter);
	}

....
}

A couple of gotchas you have to watch out for… The ACTION_SCREEN_OFF Intent does not get picked up from the AndroidManifest.xml file so you have to assign it in code as shown above.  Also, I put the assignment in the onCreate method because the Service can get killed off.  If the Service is killed off, Android will schedule it to restart, but in order to catch the Screen Off broadcasts the Service must sign up again in the onCreate method…at least, this is what worked for me and all seems to be going well.  As always, the docs are a little sparse and I had to go through some trial and error to figure it out, but I’m pretty happy with the results.

The new feature (along with a bug fix) is available in both the Trial and Full version of MediaDroid in the Android market…check em out and let me know what you think!

October 1st, 2009

Email directly from Note To Me

I’m pretty excited about this…don’t remember how I found Nilvec, but thanks to a pair of blogs on their site I’ve been able to integrate dispatching of emails directly into Note To Me (this feature isn’t yet available for the version in the Android market) so the user doesn’t have to go through the Gmail client, very slick.  Check out these posts…

Sending Email Without User Interaction In Android

Email Sending Example

They packaged the Apache classes very nicely and made it easy to get the email set up and running.  Now for all the other features that are needed because I’m implementing my own email client…ie, making sure the emails are sent later if there is no wireless connection.

September 22nd, 2009

Full version of MediaDroid on the Android Market

Just wanted to post a quick note that I’ve released a full version of MediaDroid to the Android Market.  I’ve got lots more feature coming up and there’s a couple of bugs to iron out, but I think it’s feature complete enough for a first version.

Would love to get your feedback, good or bad!  More information with screen shots at http://www.mgmblog.com/mediadroid.

September 21st, 2009

My implementation of ImageCache

Been awhile since I’ve posted any code and thought it was about time.  The image gallery has definitely been one of the most challenging parts of the MediaDroid application so far.  I even seem to have uncovered a bug in one of the earlier versions.  But thanks to some advice from the Google I/O talk by Romain Guy I settled on an implementation using SoftReferences and the AsyncTask class.  If you have more experience with threading then I do, I’d be interested in your opinion!

The task of the ImageCache is to load Bitmaps as they are requested.  From the outside the Bitmaps are requested using the get method which takes the Uri of the Bitmap to load, and the ImageView which will eventually be updated with the Bitmap. A single thread waits for the requests or jobs as I call them to be added to a job list.

The ImageCache follows the Singleton pattern and is initiated using the follow call,

ImageCache.getInstance().executeLoadImagesTask( context );

This call initiates a thread which waits for jobs to be posted on the job list.

A Bitmap is retrieved from the ImageCache with the following call

Bitmap bm = ImageCache.getInstance().get( _thumbUri.toString(), _imgVw );

If the image isn’t initially in the cache, a default Bitmap is returned, then a job is added to the job list.  This job contains the Uri to the Bitmap and and the ImageView to update when the Bitmap is done loading.

I also extended ImageView to contain a Uri for the image it displays. When the image is loaded into the UriImageView it is checked against the one that is currently assigned. Otherwise, the ImageView will cycle through all the images that are loaded, kind of a cool effect, but not the best result for the UI.

As always, sorry for the funky formatting, someday I’ll find and install a proper CSS for computer code.  Be weary of cut-n-paste, I’m not sure if I caught all the formatting issues.


public class ImageCache
{
	private static final String LOG_TAG = "ImageCache";
	private static final boolean LOGD = true;

	private static ImageCache _instance = null;
	private final HashMap<String, SoftReference<Bitmap>> _cache;

	private Context _ctx;
	private static Bitmap defaultBitmap;
	private Object _lock;
	private ArrayList<ImageJob> jobs =  new ArrayList<ImageJob>();

	public static ImageCache getInstance()
	{
		if ( _instance == null )
		{
			_instance = new ImageCache();
		}

		return _instance;
	}

	private ImageCache()
	{
		_lock = new Object();
		_cache = new HashMap&ltString, SoftReference<Bitmap>>();
	}

	public void executeLoadImagesTask( Context ctx )
	{
		_ctx = ctx;
        	defaultBitmap = BitmapFactory.decodeResource( _ctx.getResources(), R.drawable.camera_icon );
		new LoadImagesTask().execute(null);
	}

	public void put( String key, Bitmap bitmap )
	{
		_cache.put( key, new SoftReference<Bitmap>(bitmap) );
	}

	public void clear()
	{
		_cache.clear();
	}

	public Bitmap get( String imguri, UriImageView viewToUpdate )
	{

		Bitmap bm = null;
		SoftReference>Bitmap< reference = _cache.get(imguri);

		if ( reference != null )
		{
			bm = reference.get();
		}

		if ( bm == null )
		{
			bm = defaultBitmap;
			postJob( new ImageJob( imguri, viewToUpdate ) );
		}

		return bm;
	}

	/**
	 * Called after the bitmap has been retrieved bitmap from the
	 * sdcard
	 *
	 * @param jobs
	 */
	public void addImage( ImageJob... jobs )
	{
		ImageJob job = jobs[0];
		final UriImageView view = job.getViewToUpdate();
		final Bitmap bm = job.getBitmap();
		final Uri imguri = job.getImageUri();

		put( imguri.toString(), bm );

		view.post( new Runnable() {

			public void run()
			{
				view.setImage(imguri, bm);
			}

		});
	}

	private void dbg( String msg )
	{
		if (LOGD) Log.d( LOG_TAG, msg );
	}

	private void postJob( final ImageJob job )
	{
    		dbg( "Thread: " + Thread.currentThread().getName() + " posting job " + job.getImageUri() );
    		synchronized(_lock)
    		{
    			jobs.add(job);
    			_lock.notify();
    		}
	}

	private class ImageJob
	{
		private Uri _imageUri;
		private UriImageView _viewToUpdate;
		private Bitmap _bm;

		public ImageJob( Uri imageUri, UriImageView viewToUpdate )
		{
			_imageUri = imageUri;
			_viewToUpdate = viewToUpdate;
		}

		public ImageJob( String imageUri, UriImageView viewToUpdate )
		{
			this( Uri.parse( imageUri ), viewToUpdate );
		}

		public Uri getImageUri()
		{
			return _imageUri;
		}

		public UriImageView getViewToUpdate()
		{
			return _viewToUpdate;
		}

		public void setBitmap( Bitmap bm )
		{
			_bm = bm;
		}

		public Bitmap getBitmap()
		{
			return _bm;
		}
	}

	private class LoadImagesTask extends AsyncTask<Object, ImageJob, Integer>
	{
		@Override
		protected Integer doInBackground(Object... params)
		{
			Thread.currentThread().setName( "LoadImagesTask" );

			while( true )
			{
				int jobsize = 0;

				synchronized( _lock )
				{
					jobsize = jobs.size();
				}

				if ( jobsize > 0 )
				{
					synchronized( _lock )
					{
						ImageJob job = jobs.remove(0);
						dbg( "performing image job " + job.getImageUri() );

						try
						{
							job.setBitmap( ImgUtils.buildBitmap(_ctx, job.getImageUri(), 4) );
							onProgressUpdate( job );
						}
						catch (IOException e)
						{
							e.printStackTrace();
						}
					}
				}
				else
				{
					try
					{
						synchronized( _lock )
						{
							dbg( "Thread: " + Thread.currentThread().getName() + " waiting for jobs" );
							_lock.wait();
							dbg( "Thread: " + Thread.currentThread().getName() + " got a job" );
						}
					}
					catch (InterruptedException e)
					{
						e.printStackTrace();
					}
				}
			}
		}

	    @Override
	    public void onProgressUpdate(ImageJob... job)
	    {
	        addImage( job );
	    }

	    @Override
	    public void onPostExecute(Integer imagesLoaded)
	    {
	    	dbg( "loaded " + imagesLoaded + " images" );
	    }

	}
}

Again, I’d love to hear any comments you may have about the implementation, one thing about bootstrapping and doing all the coding yourself is it’s much harder to find code reviewers!

August 21st, 2009

MediaDroid let loose

After many long months of thinking, planning, and thinking some more.  The flagship application of my grand scheme is out in the wild.  MediaDroid is an Android Application Widget which allows the user to create albums and add photos to those albums.  The selected photo is displayed on the home screen and can be changed at anytime by the user by selecting a different photo.

The current version of MediaDroid in the Android Market is just a trial version, and it certainly has some performance short comings.  But I believe in release early and release often, so time permitting I will be getting updates out soon, and when I feel it’s up to snuff I’ll release a full version.  The trial version limits the user to 2 albums with 5 photos in each.  The full version won’t have these limitations and other features as well.

A full writeup coming soon, along with screen shots, for right now, it’s way to late and I must get to bed.

August 14th, 2009

Why I wrote NoteToMe

NoteToMe is a simple tool which helps me capture thoughts and ideas as they migrate through my brain and compete for attention.

I consider myself a pretty heavy Right Brain person, I try not to label any of my ideas are stupid or outrageous.  It seems that the more ideas I entertain, no matter how crazy,  the more ideas pop into my head.  I’ve been working awhile on a system or workflow to improve the collection and storage of these thoughts so I can action on them at a later date.

The first problem is having a place to hold these ideas so they won’t be forgetten. Enter Gmail…I use my Gmail account for lots more then just recieving spam.  I capture ideas, reminders, todos, and links just to name a few, it’s my catch all.  I’m constantly emailing one liners to myself, because I know that I have a much better chance of revisiting the topic if it’s in my inbox.  It’s certainly not a perfect workflow, but something I continue to improve.

So the next challenge is getting the thoughts from my head into my inbox. I started by having a shortcut to my email on my desktop.

emailshortcut.png   enteridea.png

This kinda worked, but I still had to enter some marking or tag to help filter the clutter and a subject.  The subject is moot in my book, it’s the meat of the message I want to get to and capture before I forget it, and move onto the next one which is bubbling to the top.  Instead I’m screwing around trying to “think” of a subject as opposed to just letting the thoughts come streaming out.

These where some of the first requirements for NoteToMe.  Quickly allow me to get thoughts out of my head, and allow me to quickly mark them with predefined tags.

So now I have a NoteToMe Application Shortcut on my main screen which brings up the app allowing me to instantly capture my todo/thought/next big thing and  send it on its way.

notetomeshortcut.png notetomenote.png

The current version still goes through the Gmail client so it could still be trimmed down a bit as far as number of button clicks, but it seems to be working into my workflow so far…but maybe that’ll change.

I know that NoteTeMe has lots of competition out there.  Apps that are much more feature rich when it comes to note taking or todo lists, AK Notepad, Note Everything and OI Notepad are a couple that come to mind.  But NoteToMe fills a little different niche in my opinion, kinda geared specifically to how my brain works.  So if you’re brain kinda works the same way, I hope you give it a try and let me know how it goes…good or bad.  Any type of comments at this stage are appreciated.

Click here to see more screen shots of NoteToMe…come back soon, I got lots more ideas!

And again, thanks for your support, all proceeds go towards my bootstrapping effort.

August 10th, 2009

Second application on Android Market - NoteToMe

In between my new contracting gig, family life and the new dog I found room to put together a quick Android application which I just uploaded to the market.  It’s my first attempt at a paid app and more information can be seen on the app link, NoteToMe, at the top of the screen.  It’s a small one feature app, but I’ve got a couple more ideas I’ll be putting into it when time permits…bootstrapping is tough stuff!

Just wanted to put a quick message together to put out the news, thanks for taking a look at it if you get the chance.

March 10th, 2009

Life has its ups and downs

To get right to the point, due to a budgeting hiccup, I have been laid off from my employer until the next project comes online.  Since I do not like to resign my fate to others, I have officially joined those looking for new employment.

So if you are, or know someone looking for a Software Developer with Java/XML/Android/Ruby on Rails experience I would greatly appreciate if you could pass my name along.

I will also be continuing to work on my side projects and finally have some extra time to figure out my last bug or two in my current Android programs, and get my latest idea for a Ruby on Rails website up and running.  And with any luck (or a lot of luck, depending on how optimistic you are), I’ll be able to become self employeed!

Wish me luck!

February 13th, 2009

I have an Android Market Merchant Account!!!

 WARNING….really bad formatting follows!  I’ll try and make it a little nicer when I get a chance.

Could it be true???

Merchant Account Approval

This is what I got after I filled out the form with my private data.  The Merchant form is accessed off of  my main Android Developers page.  This is what the invitation looks like…

Invitation for Merchant Account

I haven’t figured out how to put a price in for an application yet, or if you can…but we are very close.  Guess I know what I’ll be doing with my free time this weekend!  The deck has been shuffled, the hands have been delt, how are you going to play yours??

(Update)

From the email I got from Android Market Support, it looks like the charging of apps will start mid next week.  I’m assuming that’s why I can’t actually put a price towards my apps yet.

From the email:

“Initially, priced applications will be available to end users in the US starting mid next week.”

Other news from the email, the Android Market will be open in Australia soon (Feb 15th) and Singapore in the coming weeks.

Also, paid apps are only supported in the US and UK Android Markets, but other countries will be coming online this quarter.  Another, quote from the email:

“We will also enable developers in Germany, Austria, Netherlands, France, and Spain to offer priced applications later this quarter.  By the end of Q1 2009, we will announce support for developers in additional countries.”

February 6th, 2009

Export an Android SQLite db to an XML file on the SD Card

I’m pretty syched about this code.  It took some figuring out and some hunting and asking questions on Google’s Android forum.  But thanks to the following posts

 File permissions for world read/write

SQLite3 sql command to show tables in database

I pieced together the beginnings of some code that will take an Android SQLite db and export it to XML data within a file on the SD Card.  This has a couple potential uses,

read the rest of this entry… »