Android: Load, Scale, and Rotate an image from Camera

If you’re reading an image from camera, chances are it’s very large and not rotated correctly. Luckily, it’s not difficult to correct both problems, if you know how.

    public Bitmap loadFromCamera(Context context, Uri photoUri) {
        Bitmap photo = MediaStore.Images.Media.getBitmap(context.getContentResolver(), photoUri);
        if (photo != null) {
            DisplayMetrics metrics = context.getResources().getDisplayMetrics();
            int maxDim = Math.max(metrics.widthPixels, metrics.heightPixels);
            int rotation = getRotationFor(context, mPhotoUri);
            photo = BitmapUtil.scaleAndRotate(photo, maxDim, rotation);
            return photo;
        }
        return null;
    }
    
    public int getRotationFor(Context context, Uri photoUri) {
        try {
            String[] orientationColumn = { MediaStore.Images.Media.ORIENTATION };
            Cursor cur = context.getContentResolver().query(photoUri, orientationColumn, null, null, null);
            if (cur != null && cur.moveToFirst()) {
                int orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]));
                return orientation;
            }
        } catch (Exception e) {
            // couldn't parse
        }
        return 0;
    }

    public Bitmap scaleAndRotate(Bitmap bitmap, int maxDim, int rotation) {
        float scale = 1;
        if (bitmap.getWidth() > maxDim && bitmap.getWidth() > bitmap.getHeight())
            scale = maxDim * 1.0f / bitmap.getWidth();
        else if (bitmap.getHeight() > maxDim)
            scale = maxDim * 1.0f / bitmap.getHeight();

        Matrix matrix = new Matrix();
        matrix.postScale(scale, scale);
        matrix.postRotate(rotation);

        Bitmap scaled = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
                bitmap.getHeight(), matrix, true);
        return scaled;
    }

Welcome to the new Betaful!

With the move to Tumblr comes a new dedication to posting regularly. I hope to keep the world updated on:

  • tech news and happenings (especially Android)
  • my opinions on said happenings
  • learnings & tips from my daily work 

It’s going to be a fun ride, so you’re going to want to follow along.

To everyone who came here looking for a particular page:

Sorry, I got sick of managing my own Wordpress install. You can use the Search feature in the top left corner to find the content again. Import from Wordpress wasn’t very easy, so I only copied over my engineering-related posts.

Creating a Nexus 5 emulator

It is surprisingly hard to create Android emulator that supports the latest xxhdpi devices (Samsung GS4, HTC One, LG Nexus 5). All of these devices are 1080x1920 and xxhdpi resolution, but the Android SDK devices haven’t been updated in a while. Here’s how I did it.

1. Open up the AVD manager, and go to the “Device Definitions” tab. Yes, I just discovered this tab for the first time today:

AVD Manager

2. Select New Device, and enter the following (obviously you can customize it to your needs)

AVD Manager

3. Now, create an AVD with this device. When you start it, everything will look too small… this is because your device has the wrong DPI. To fix this, open up your terminal, and type the following:

adb shell setprop qemu.sf.lcd_density 445
adb shell stop
adb shell start

Your emulator will restart and everything should look just like it does on your physical device. I found that magic number (445 ppi) online - that’s the Nexus 5 density, it may be different for other devices.

Screen Shot 2014-03-06 at 5.37.04 PM

Simple, but surprisingly difficult. Good luck…

Android: Too many methods, dex fails

Have you ever had an Android build fail with the following message?

dex java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536

It means that you have referenced too many methods. Apparently it’s a recent bug.

The sad thing about this error is that there’s really no way to figure out of all your dependencies, who the most egregious offenders are. That’s what I thought, until I discovered this tip. Thanks to the amazing work by JesusFreke on this StackOverflow qustion, it is revealed that you can get the number of method references in a jar by first converting it to a dex file, and then reading the header.

Specifically, this is what I did to figure out the # of method references in my jars.

1. Grab all of the jar files

mkdir jars
cp **/*.jar jars

2. Iterate through them, displaying the method size

for file in jars/*.jar; do
  echo $file; ~/android-sdk/build-tools/17.0.0/dx --dex --output=temp.dex $file 2> /dev/null
  cat temp.dex| head -c 92 | tail -c 4 | hexdump -e '1/4 "%d\n"'
done

(note that you should replace your android path as necessary)

3. Identify the highest count jars, remove them from your project

This is the hard part, but hopefully, you can find smaller libraries that do the same thing. The biggest offenders in my current project were Google guava (14265 methods), Jackson (8177 methods), and Google Play Services (5931 methods) - just a few libraries like these can easily add up and put you over the limit.

Good luck!

Architecture Decisions & Information Overload

SysCallIISsmallAh, the rarified air of the software architect. There is no source control up here, no text editors, or servers, or pagers, or unit tests. Mostly what’s up here is blocks - lots and lots of blocks, with lines running to and fro.

What architects do with blocks is move them around furiously - a process that others might call “making decisions”. For example, how does this block talk to this other block? How can I organize my blocks? Should I make new blocks, or try to increase the abilities of my existing blocks?

Central to all of this is the ability to quickly and accurately visualize the consequences of decisions - which is why the primary enemy of architectural decision-making seems to be overload. When there are too many parts, when changing something has too many implications, or when there are difficult tradeoffs to be managed, it’s possible to lose the ability to make architectural decisions with confidence.

In particular, when systems are poorly abstracted, we tend to pay attention to the details (because we have to), leading to increased cognitive complexity. This manifests itself in slower and more difficult decisions, as things just don’t “feel right” with the system.

Here’s this crazy thing - the way you simplify an architecture is to add more things… but better things. Add layers with well-defined interfaces. Make rules. Group small things into bigger things. When at the point of overwhelm, instead of trying to solve the problem at hand, it may be worthwhile to step back and work on your mental model.

While sometimes you can get rid of things, in my experience, a lot of project requirements are handed down from “on high”. At best, you can try to make a case for getting rid of old, crufty things - which is why I’m always asking my cofounder if we can kill this feature or that. (I’m sorry, Astrid users, it’s true)

At the end of the day, as an architect, your job is to make decisions and produce blueprints that others (or yourself) can work with. Make better decisions by creating better abstractions - zoom in when you need to, but always keep the big picture in mind.

Need a hand? Some patterns that help simplify things include MVC, dependency injection or service locator pattern, and facade pattern. Design patterns, good times.

Single Table Inheritance

nesting-tablesRails Single Table Inheritance is a powerful concept where a single database table can contain various subclasses of a parent class, distinguished by a type column. For example, you can have a Cat and Dog model descend from Animal, each having their own methods or inheriting from the parent. In the database, the type field will be either “Cat” or “Dog”, and when you use query methods such as Animal#where, the models that are returned will be instances of the appropriate subclass.

STI allows your code to be much cleaner, removes those nasty case statements (see below), and gives you logical groupings for related functionality. As our code base has grown, and functionality is repurposed or expanded, I have since found myself refactoring classes to split them into subclasses as appropriate.

For example, Astrid used to only support premium accounts via Recurly. When we added the ability to perform in-app purchasing through various app stores, we ended up adding methods like “verify_android_token” and “verify_apple_token” to the PremiumAccount class. Even worse, when we had to write common functionality like a cancel method, it would look something like this:

def cancel!
  if type == :recurly
    # do stuff
  elsif type == :android
    # do stuff
  elsif type == :apple
    # do stuff
  end
end

After refactoring, each subclass of PremiumAccount has its own cancel implementation, and thanks to the magic of Single Table Inheritance, we always get the right type of class when we need to perform these operations. Unfortunately, like many things Rails, STI is not that well documented and isn’t exactly discoverable. Lucky for you, other people have done the hard work of figuring things out.

My mantra when it comes to code quality is to have smaller, conceptually grouped units - fewer files in each folder, fewer methods in a class, and shorter methods. STI lets you group related classes into a subfolder, separates out related functionality, and eliminates proliferation of if statements such as the one above. Tools like these are powerful weapons in the war we fight against code attrition.

Delayed::Job to Resque

In general, the idea of queuing long-running jobs is a great one. At Astrid, we lean heavily on queueing for anything that requires talking to external services - including emailing, push notifications, and indexing. However, when your queueing infrastructure starts hurting, that is a Very Bad Problem™.

We used to use delayed_job, but for us, processing jobs became really slow. First, each worker has to try to lock a job. Then, it has to check if it obtained the job lock, and then it has to do the work, and then it has to delete the row. Last week, we reached a point where more jobs were getting added to the queue than finishing - which means that even if we had cleared our queue of old jobs, our jobs table would still have continued to grow unbounded.

Time for some intervention in the form of Resque, the hot redis-based queuing system from Github.

how come resque doesn't have a real logo?

We’re obviously not using our old infrastructure anymore, but I would estimate that our job throughput increased at least 5x after the switch. We also get much better transparency into our jobs via sexy UI. What’s not to like?

Step 1: install resque

(We are using Rails 3.2 on Ruby 1.9) We added resque, resque_mailer, and resque_unit (in the test group) to our Gemfile. If you don’t have redis installed, you’ll need to do that in your development and production environments as well. On Mac or Linux, homebrew / apt / yum should do the trick.

While you’re here, you should check out the Github pages for resque, resque_mailer, and resque_unit.

Step 2: migrate your jobs to resque

For the most part, this is straight forward - convert the perform method to a class method, and convert the invocation (e.g. Delayed::Job.enqueue C2DMJob.new(notifications) becomes Resque.enqueue C2DMJob, notifications).

SUPER IMPORTANT! Resque serializes your parameters to JSON, not YAML. For us, this had two major implications:

  • You can’t pass ActiveRecord models directly - you need to change your jobs to take ids as parameters instead of models
  • Symbol keys will become strings (e.g. { :cat => "Mittens" } becomes { "cat" => "Mittens" }). If you check for hash[:cat], this will break.

As an added bonus, you should add a named queue to each of your jobs. We (and Github) use a named-priority queue system (critical, high, medium, low), and specify to our resque workers to work them in that order.

Step 3: convert your ActionMailers

Add “include Resque::Mailer" at the top of your mailers. Find all of your old references to the Delayed::Job mailer invocation (Notifications::delay.signup_email) and change them to Resque::Mailer style of invocation. We did this with regular expressions and sed. You may also want to change your non-delayed mail invocations to use the deliver! method. Then, change all of your ActionMailer methods to use ids instead of models (see above).

Step 4: convert your unit tests

Of course, this depends on how you wrote your tests, but we had to change from:

assert_difference "Delayed::Job.count" do
  # do some stuff
end

Delayed::Worker.new.work_off(1)

to

Resque.reset!

# do some stuff
assert_queued MyAwesomeJob

Resque.run!

We also had to add the following line to an initializer to have Resque::Mailer not suppress emails in the test environment (since the resque_unit gem handles the mocking of redis):

Resque::Mailer.excluded_environments = []

Step 5: misc stuff

There were a few loose ends for us to tie up. We had to create a simple resque.rake file that loaded the Rails environment. There were a few delay calls that weren’t emails and weren’t using background jobs that we had to convert to Resque-style jobs. Finally, we installed the resque web interface, which is awesome.

That’s it, other than the actual deployment of resque workers to your production environment. I trust that if you’ve come this far, that should not be too much of a chore.

The bottom line

Are you still using Delayed::Job in a large production environment? You shouldn’t be. Go replace it :)

Don’t be like these dudes who wait so long for a job that they turn to stone.

Date, Time, and ActiveSupport::TimeWithZone

Dates and Times are kind of a mess in the Ruby on Rails world. There are two kinds of time classes - Ruby’s Time class, and Rails’s ActiveSupport::TimeWithZone. There’s only one kind of Date, and no DateWithZone. Because of the Rails / Ruby mix of classes, there are a lot of pitfalls when working with dates and times on a Rails application used by people around the world; here are some of our learnings and best practices.

Never use the Time class

In our code, we try to enforce usage of TimeWithZone instead of Time. We make sure Time.now never occurs in our code, and instead use Time.current. In addition, whenever we need to read time from a database, we always make sure to call in_time_zone(Time.zone). This way, our code should always produce times of class ActiveSupport::TimeWithZone.

Today’s Date

Date.today no longer is valid in a TimeWithZone world. 2012-09-30 on the server could be 2012-09-29 in some parts of the world, and 2012-10-01 in others. We created our own Date.current method which gives us a better Date:

class Date
  def current
    Time.current.to_date
  end
end

Date to Time

The second problem with Dates is that Date#to_time is no longer a valid method, as it returns a Time object, and you can’t just convert that Time into a TimeWithZone (otherwise, 2012-09-30 would become 2012-09-30 00:00:00 -0700 and then 2012-09-29 21:00:00 -1000 if the server was in Pacific time and the user was in Hawaii time). Here comes another patch:

class Date
  def to_time
    Time.zone.local(self.year, self.month, self.day, 0, 0, 0)
  end
end

Time Zone context

With these patches, we are able to comfortably operate between TimeWithZone objects and Date objects. The final piece for us is to initialize our application server context to be the user’s time zone. With this, each user’s request automatically gets initialized to the user’s time zone.

class ApplicationController < ActionController::Base
  before_filter :time_zone
 
  def time_zone
    Time.zone = nil
    if user_signed_in? and current_user.time_zone
      Time.zone = current_user.time_zone
    end
  end
end


In summary, it’s possible to work cleanly with ActiveSupport::TimeWithZone objects and Date objects, but it requires some best practices and patching of the Date class to interoperate smoothly. Until we found these patches, we experienced many issues in the conversion from Date to Time. If your application can get away with not using the Ruby Date class, maybe that’s for the better, but if you do decide to use it, hopefully this helps make your experience a bit smoother.

Got any more Date / Time tricks? Do share!