<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-556059086866018353</atom:id><lastBuildDate>Sat, 04 Feb 2012 20:36:38 +0000</lastBuildDate><category>android</category><category>release</category><category>image processing</category><category>wallswitch</category><category>programming</category><title>Playing with Androids</title><description>My current experiments learning the Android platform.  I'm currently working on an App called WallSwitch that will automagically switch your wallpaper for you, at a defined interval.  I figured I might as well do something the iPhone can't do (for now).</description><link>http://kfb-android.blogspot.com/</link><managingEditor>noreply@blogger.com (Keith)</managingEditor><generator>Blogger</generator><openSearch:totalResults>8</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/PlayingWithAndroids" /><feedburner:info uri="playingwithandroids" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><guid isPermaLink="false">tag:blogger.com,1999:blog-556059086866018353.post-1006303047187733290</guid><pubDate>Sat, 08 May 2010 23:44:00 +0000</pubDate><atom:updated>2010-05-08T16:44:52.350-07:00</atom:updated><title>Making Random Suck Less</title><description>One of the biggest complaints I get about WallSwitch is that the random switching sucks.  It repeats images too frequently and just doesn't 'feel right'.  I couldn't agree more, so when I ran across &lt;a href="http://www.rexswain.com/benford.html"&gt;this article,&lt;/a&gt; I figured I could do something about it.
&lt;br/&gt;&lt;br/&gt;

The problem is that random numbers don't work how the human brain expects.  The article above explains it in detail, but suffice it to say that pure/pseudo random numbers suck for most things a user interacts with.  What I wanted was a way to provide selections that are still nondeterministic, but closer to what users expect.
&lt;/br&gt;&lt;/br&gt;

The method itself is nothing more than random selection using weighted items.  I wanted to keep a feeling of randomness, but make sure more recent selections were less likely to appear.  This being Java, the first thing I did was make an interface to hold the object and it's priority:
&lt;br/&gt;&lt;br/&gt;

&lt;pre class="brush: java"&gt;
public interface BetterRandomItem {
 int getPriority();
 void setPriority(int newPriority);
}
&lt;/pre&gt;
&lt;br/&gt;&lt;br/&gt;

Then, I made a choice() function (name taken from Python's &lt;a href="http://docs.python.org/library/random.html#random.choice"&gt;random.choice&lt;/a&gt;) that uses this priority.
&lt;br/&gt;&lt;br/&gt;

&lt;pre class="brush: java"&gt;
public static BetterRandomItem choice(List&lt;BetterRandomItem&gt; items) {
  if(items == null || items.size() == 0)
   throw new IllegalArgumentException("items is null or empty");
  
  // Sum all the priority values
  int itemSpace = 0;
  for(int i = 0; i &lt; items.size(); i++)
   itemSpace += items.get(i).getPriority();  
  
  // Pull an int from that space
  int target = new Random().nextInt(itemSpace + 1);
  
  // Match the int to the corresponding item
  int tmpVal = 0;
  for(int i = 0; i &lt; items.size(); i++){
   tmpVal += items.get(i).getPriority();
   if(tmpVal &gt;= target)
    return items.get(i);
  }
  
  // If that failed, return the last in the list, I guess
  return items.get(items.size() - 1);
 }
&lt;/pre&gt;
&lt;br/&gt;&lt;br/&gt;

Not the most complex piece of code ever written, but it'll go a long way to making users a bit happier with 'random' selections.  Since putting this in, the emails and comments about my random function sucking have completely stopped.
&lt;br/&gt;&lt;br/&gt;

&lt;b&gt;Note&lt;/b&gt;: For my implementation, I kept track of the last 50 images displayed and gave them weights 1-50. Any unseen images were weighted as (num seen images * 10), giving them significantly more weight than those that had been seen.
&lt;br/&gt;&lt;br/&gt;

&lt;b&gt;Another Note&lt;/b&gt;: Watch out for int overflows in itemSpace. It would be nice if Random.nextLong took an argument.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/556059086866018353-1006303047187733290?l=kfb-android.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PlayingWithAndroids/~4/4Z9doNdb1PE" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/PlayingWithAndroids/~3/4Z9doNdb1PE/making-random-suck-less.html</link><author>noreply@blogger.com (Keith)</author><thr:total>7</thr:total><feedburner:origLink>http://kfb-android.blogspot.com/2010/05/making-random-suck-less.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-556059086866018353.post-7913366831230987603</guid><pubDate>Fri, 26 Feb 2010 23:52:00 +0000</pubDate><atom:updated>2010-02-26T16:13:20.244-08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">wallswitch</category><category domain="http://www.blogger.com/atom/ns#">release</category><category domain="http://www.blogger.com/atom/ns#">android</category><title>WallSwitch 2.0 (and 2.0.1) Released!</title><description>WallSwitch 2.0 was released a couple days ago.  It was quickly followed by 2.0.1 with some bug fixes for Droid users.

There are more blog posts and updates to come.  I'll be working on a couple more bug fixes and a new, smaller, widget for the next version.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/556059086866018353-7913366831230987603?l=kfb-android.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PlayingWithAndroids/~4/neWT-8RT8Cc" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/PlayingWithAndroids/~3/neWT-8RT8Cc/wallswitch-20-and-201-release.html</link><author>noreply@blogger.com (Keith)</author><thr:total>7</thr:total><feedburner:origLink>http://kfb-android.blogspot.com/2010/02/wallswitch-20-and-201-release.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-556059086866018353.post-5761462858668954826</guid><pubDate>Tue, 07 Jul 2009 05:12:00 +0000</pubDate><atom:updated>2009-07-06T22:20:39.525-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">wallswitch</category><category domain="http://www.blogger.com/atom/ns#">release</category><category domain="http://www.blogger.com/atom/ns#">android</category><title>WallSwitch v1.5.0 Released!</title><description>I'm incredibly happy to finally announce that WallSwitch 1.5 has been published to the Android Market!  It's been a significant amount of work to add some of the new features and fix the outstanding bugs.  Here's what you can expect to find in the new version:
&lt;br/&gt;

&lt;ul&gt;
&lt;li&gt;You can now select multiple wallpaper folders&lt;/li&gt;
&lt;li&gt;New picker for auto-switch interval&lt;/li&gt;
&lt;li&gt;Low Performance Mode, in case your phone is sluggish&lt;/li&gt;
&lt;li&gt;Android 1.5 officially, and exclusively, supported&lt;/li&gt;
&lt;li&gt;Won't auto-switch right at boot. It waits a minute so the boot can finish.&lt;/li&gt;
&lt;/ul&gt;

There were also a few bugs fixed in the image processing.  Notably, cropping should be faster and more accurate. As always, if you find any bugs, please don't hesitate to email me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/556059086866018353-5761462858668954826?l=kfb-android.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PlayingWithAndroids/~4/okIJ-RnCIGo" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/PlayingWithAndroids/~3/okIJ-RnCIGo/wallswitch-v150-released.html</link><author>noreply@blogger.com (Keith)</author><thr:total>3</thr:total><feedburner:origLink>http://kfb-android.blogspot.com/2009/07/wallswitch-v150-released.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-556059086866018353.post-3530620184863319765</guid><pubDate>Mon, 04 May 2009 00:34:00 +0000</pubDate><atom:updated>2009-07-06T22:20:24.288-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">wallswitch</category><category domain="http://www.blogger.com/atom/ns#">release</category><category domain="http://www.blogger.com/atom/ns#">android</category><title>WallSwitch v1.0.4 Released!</title><description>Released tonight with a couple more bug fixes.  
&lt;br/&gt;&lt;br/&gt;

I'm going to start work on v1.1 soon, which will add some of my more frequently requested features.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/556059086866018353-3530620184863319765?l=kfb-android.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PlayingWithAndroids/~4/6npj_c02OAA" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/PlayingWithAndroids/~3/6npj_c02OAA/wallswitch-v104-released.html</link><author>noreply@blogger.com (Keith)</author><thr:total>2</thr:total><feedburner:origLink>http://kfb-android.blogspot.com/2009/05/wallswitch-v104-released.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-556059086866018353.post-6780065081313624884</guid><pubDate>Thu, 30 Apr 2009 03:40:00 +0000</pubDate><atom:updated>2009-07-06T22:21:08.788-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">wallswitch</category><category domain="http://www.blogger.com/atom/ns#">release</category><category domain="http://www.blogger.com/atom/ns#">android</category><title>WallSwitch v1.0.3 Released!</title><description>Just a quick note on a release that happened a couple days ago.  Some bugs were found very quickly and I had to do a quick release so it would work on more phones.
&lt;br/&gt;&lt;br/&gt;

Other than that, working on a couple more features.  Right now, I'm thinking checkboxes instead of a radio button for choosing the folder for your wallpapers will be the first thing I do.  It seems to be the more requested feature at the moment and is a really good idea.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/556059086866018353-6780065081313624884?l=kfb-android.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PlayingWithAndroids/~4/4d9aheyb8ng" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/PlayingWithAndroids/~3/4d9aheyb8ng/wallswitch-v103-released.html</link><author>noreply@blogger.com (Keith)</author><thr:total>1</thr:total><feedburner:origLink>http://kfb-android.blogspot.com/2009/04/wallswitch-v103-released.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-556059086866018353.post-6743760763318255263</guid><pubDate>Mon, 27 Apr 2009 03:25:00 +0000</pubDate><atom:updated>2009-07-06T22:21:14.988-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">wallswitch</category><category domain="http://www.blogger.com/atom/ns#">release</category><category domain="http://www.blogger.com/atom/ns#">android</category><title>WallSwitch 1.0 Released!</title><description>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_FP2z5pic0Zs/SfT6lVTHQ8I/AAAAAAAAAUk/qULW5otrfRU/s1600-h/icona.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 96px; height: 96px;" src="http://3.bp.blogspot.com/_FP2z5pic0Zs/SfT6lVTHQ8I/AAAAAAAAAUk/qULW5otrfRU/s400/icona.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5329159778365555650" /&gt;&lt;/a&gt;


I'm happy to announce that WallSwitch 1.0 has been released!
&lt;br/&gt;&lt;br/&gt;

WallSwitch is a program designed to randomly switch the wallpaper on your phone at a given interval.  It handles all the image processing, like cropping, automatically so that you never have to manually set your wallpaper again!
&lt;br/&gt;&lt;br/&gt;

It is also designed to intelligently determine if an image should be cropped or letterboxed so that you always have the optimal wallpaper size for you.
&lt;br/&gt;&lt;br/&gt;

You can download it to your G1 (or any future Android devices) through the Android Marketplace.  Search for 'WallSwitch'.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/556059086866018353-6743760763318255263?l=kfb-android.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PlayingWithAndroids/~4/AuK1SMX574g" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/PlayingWithAndroids/~3/AuK1SMX574g/wallswitch-10-released.html</link><author>noreply@blogger.com (Keith)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_FP2z5pic0Zs/SfT6lVTHQ8I/AAAAAAAAAUk/qULW5otrfRU/s72-c/icona.png" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://kfb-android.blogspot.com/2009/04/wallswitch-10-released.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-556059086866018353.post-4186869992369781460</guid><pubDate>Sat, 25 Apr 2009 19:18:00 +0000</pubDate><atom:updated>2009-04-25T14:26:04.222-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">programming</category><category domain="http://www.blogger.com/atom/ns#">android</category><title>Registering for TIME_TICK After a Reboot in Android</title><description>Creating a service that will receive &lt;code&gt;TIME_TICK&lt;/code&gt;, but also start on boot isn't immediately obvious.  It took me a bit to figure out the best way to do it, so I figure it's worth sharing.
&lt;br/&gt;&lt;br/&gt;

To start, you can't register your receiver to get &lt;code&gt;TIME_TICK&lt;/code&gt; in the android manifest.  The registration for &lt;code&gt;TIME_TICK&lt;/code&gt; has to happen in code using &lt;code&gt;Intent.registerReceiver&lt;/code&gt;. You can, however, define that your receiver has &lt;code&gt;android.permission.RECEIVE_BOOT_COMPLETED&lt;/code&gt; and set your receiver to handle it, which will give you some control on boot.  Here's the relevant portion of &lt;code&gt;AndroidManifest.xml&lt;/code&gt;:
&lt;br/&gt;&lt;br/&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;application android:icon="@drawable/icon" android:label="@string/app_name"
 android:enabled="true" android:debuggable="false"&amp;gt;
 &amp;lt;activity android:name=".AndroidMain" android:label="@string/app_name"&amp;gt;
  &amp;lt;intent-filter&amp;gt;
   &amp;lt;action android:name="android.intent.action.MAIN" /&amp;gt;
   &amp;lt;category android:name="android.intent.category.LAUNCHER" /&amp;gt;
  &amp;lt;/intent-filter&amp;gt;
 &amp;lt;/activity&amp;gt;
 &amp;lt;service android:name="DemoService"&amp;gt;&amp;lt;/service&amp;gt;
 &amp;lt;receiver android:name="DemoReceiver"
  android:permission="android.permission.RECEIVE_BOOT_COMPLETED"&amp;gt;
  &amp;lt;intent-filter&amp;gt;
   &amp;lt;action android:name="android.intent.action.TIME_TICK"&amp;gt;&amp;lt;/action&amp;gt;
   &amp;lt;action android:name="android.intent.action.BOOT_COMPLETED"&amp;gt;&amp;lt;/action&amp;gt;
  &amp;lt;/intent-filter&amp;gt;
 &amp;lt;/receiver&amp;gt;
&amp;lt;/application&amp;gt;
&amp;lt;uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"&amp;gt;&amp;lt;/uses-permission&amp;gt;
&lt;/pre&gt;

&lt;br/&gt;
This isn't enough, however, since your receiver can't register itself to listen to &lt;code&gt;TIME_TICK&lt;/code&gt;.  &lt;code&gt;Intent.registerReceiver&lt;/code&gt; registers for the lifetime of the Intent it's called from.  If we register it using the intent created for &lt;code&gt;BOOT_COMPLETED&lt;/code&gt;, it's dead as soon as it exits the handler.  Therefore, we need to start a background service that will keep running.  This service then creates a new instance of the receiver and registers that for &lt;code&gt;TIME_TICK&lt;/code&gt;.
&lt;br/&gt;&lt;br/&gt;

DemoReceiver.java:
&lt;br/&gt;
&lt;pre class="brush: java"&gt;
public class DemoReceiver extends BroadcastReceiver {
 static final String LOGGING_TAG = "MyDemo";

 @Override
 public void onReceive(Context context, Intent intent) {
  if (intent.getAction().compareTo(Intent.ACTION_BOOT_COMPLETED) == 0){   
   Log.v(LOGGING_TAG, "DemoReceiver.onReceive(ACTION_BOOT_COMPLETED)");   
   context.startService(new Intent(context, DemoService.class));   
  }else if(intent.getAction().compareTo(Intent.ACTION_TIME_TICK) == 0)
   Log.v(LOGGING_TAG, "DemoReceiver.onReceive(ACTION_TIME_TICK)");
  else
   Log.v(LOGGING_TAG, "DemoReceiver.onReceive(" + intent.getAction() + ")");
 }
}
&lt;/pre&gt;
&lt;br/&gt;&lt;br/&gt;
DemoService.java:
&lt;br/&gt;
&lt;pre class="brush: java"&gt;
public class DemoService extends Service {
 static final String LOGGING_TAG = "MyDemo";
 
 @Override
 public IBinder onBind(Intent intent) {
  return null;
 }
 
 @Override
 public void onStart(Intent intent, int startId){
  super.onStart(intent, startId);
  Log.v(LOGGING_TAG, "DemoService.onStart()");
 }
 
 @Override
 public void onCreate(){
  super.onCreate();
  Log.v(LOGGING_TAG, "DemoService.onCreate()");
  
  registerReceiver(
    new DemoReceiver(), 
    new IntentFilter(Intent.ACTION_TIME_TICK));  
 }
}
&lt;/pre&gt;
&lt;br/&gt;&lt;br/&gt;

If this all works correctly, we'll see log messages that look something like:
&lt;br/&gt;

&lt;pre class="brush: plain"&gt;
04-25 21:04:22.580: VERBOSE/MyDemo(182): DemoReceiver.onReceive(ACTION_BOOT_COMPLETED)
04-25 21:04:22.630: VERBOSE/MyDemo(182): DemoService.onCreate()
04-25 21:04:22.650: VERBOSE/MyDemo(182): DemoService.onStart()
04-25 21:05:00.140: VERBOSE/MyDemo(182): DemoReceiver.onReceive(ACTION_TIME_TICK)
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/556059086866018353-4186869992369781460?l=kfb-android.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PlayingWithAndroids/~4/56zdAoH9Iw8" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/PlayingWithAndroids/~3/56zdAoH9Iw8/registering-for-timetick-after-reboot.html</link><author>noreply@blogger.com (Keith)</author><thr:total>5</thr:total><feedburner:origLink>http://kfb-android.blogspot.com/2009/04/registering-for-timetick-after-reboot.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-556059086866018353.post-3300054423614128985</guid><pubDate>Wed, 15 Apr 2009 02:11:00 +0000</pubDate><atom:updated>2009-07-06T22:20:56.007-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">image processing</category><category domain="http://www.blogger.com/atom/ns#">programming</category><category domain="http://www.blogger.com/atom/ns#">android</category><title>Image Processing in Android</title><description>While working on WallSwitch, I ran into a number of hairy problems with image processing.  The worst, by far, was this:

&lt;pre class="brush: plain"&gt;
04-15 02:20:34.693: ERROR/dalvikvm-heap(165): 50331648-byte external allocation too large for this process.
04-15 02:20:34.693: ERROR/(165): VM won't let us allocate 50331648 bytes
04-15 02:20:38.233: ERROR/AndroidRuntime(165): java.lang.OutOfMemoryError: bitmap size exceeds VM budget 
&lt;/pre&gt;

I got it when trying to do a simple &lt;code&gt;BitmapFactory.decodeFile()&lt;/code&gt; on a jpeg I had on the sd card.  The jpeg was huge (~4MB) but that should exceed the 16MB heap I get, right?  I found some decent help &lt;a href="http://www.mail-archive.com/android-developers@googlegroups.com/msg20988.html"&gt;here&lt;/a&gt; and &lt;a href="http://groups.google.com/group/android-developers/browse_thread/thread/bb9375aecad6d47c/4f1592a89880b295"&gt;here&lt;/a&gt;, but nothing that really explained what was going on.  I knew I was hitting the limit, but had no idea why.
&lt;br/&gt;&lt;br/&gt;


Then, I remembered something a friend had told me a few years ago about how jpegs are compressed (duh) but that it had to first decompress to a bitmap before painting to your screen.  It makes sense, after all.  If I've got 1024x768 pixels on my monitor and I want to paint a picture over all of it, I'm going to need 768,432 bytes (depending on bit-depth).
&lt;br/&gt;&lt;br/&gt;

I whipped out my calculator and had a facepalm moment.  Needless to say 50,331,648 is 4096x6144 * 2, which corresponds to the size of my jpeg, when fully decompressed.
&lt;br/&gt;&lt;br/&gt;

Fixing this was, happily, very easy.  You just need to set &lt;code&gt;inSampleSize&lt;/code&gt; on your &lt;code&gt;BitmapFactory.Options&lt;/code&gt; to something useful. It'll sample the image you get back, returning something 1/2, 1/4, ... the size.  The key here is to try to keep the sample size a power of two.  It isn't necessary, but it makes the processing faster and it'll make sure the image you get back keeps the same proportions.
&lt;br/&gt;&lt;br/&gt;

&lt;pre class="brush: java"&gt;
// First, get the dimensions of the image
Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);

// Only scale if we need to 
// (16384 buffer for img processing)
Boolean scaleByHeight = Math.abs(options.outHeight - targetHeight) &gt;= Math.abs(options.outWidth - targetWidth);
if(options.outHeight * options.outWidth * 2 &gt;= 16384){
    // Load, scaling to smallest power of 2 that'll get it &lt;= desired dimensions
    double sampleSize = scaleByHeight
        ? options.outHeight / targetHeight
        : options.outWidth / targetWidth;
    options.inSampleSize = 
        (int)Math.pow(2d, Math.floor(
        Math.log(sampleSize)/Math.log(2d)));
}

// Do the actual decoding
options.inJustDecodeBounds = false;
options.inTempStorage = new byte[IMG_BUFFER_LEN];  
Bitmap output = BitmapFactory.decodeFile(filePath, options);
&lt;/pre&gt;

It's still a pretty slow operation to perform, but this at least makes it possible!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/556059086866018353-3300054423614128985?l=kfb-android.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/PlayingWithAndroids/~4/GRuhfqUcwcs" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/PlayingWithAndroids/~3/GRuhfqUcwcs/image-processing-in-android.html</link><author>noreply@blogger.com (Keith)</author><thr:total>7</thr:total><feedburner:origLink>http://kfb-android.blogspot.com/2009/04/image-processing-in-android.html</feedburner:origLink></item></channel></rss>

