Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker

Monthly Archives: June 2011

Joe Moore

Android Tidbits 6/22/2011: Hiding Header Views

Joe Moore
Wednesday, June 22, 2011

Android ListView#addHeaderView and ListView#addFooterView methods are strange: you have to add the header and footer Views before you set the ListView‘s adapter so the ListView can take the headers and footers into consideration — you get an exception otherwise. Here we add a ProgressBar (spinner) as the headerView:

// spinner is a ProgressBar
listView.addHeaderView(spinner);

We’d like to be able to show and hide that spinner at will, but removing it outright is dangerous because we’d never be able to add it again without destroying the ListView — remember, we can’t addHeaderView after we’ve it’s adapter:

listView.removeHeaderView(spinner); //dangerous!

So let’s hide it! Turns out that’s hard, too. Just hiding the spinner view itself results in an empty, but still visible, header area.


Now try to hide the spinner:

spinner.setVisibility(View.GONE);

Result: header area still visible with an ugly space:



The solution is to put the progress bar in a LinearLayout that wraps it’s content, and hiding the content. That way the wrapping LinearLayout will collapse when its content is hidden, resulting in a headerView that is technically still present, but 0dip high:

  <LinearLayout
      xmlns:a="http://schemas.android.com/apk/res/android"
      android:orientation="vertical"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content">
    <!-- simplified -->
      <ProgressBar
        android:id="@+id/spinner"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
  </LinearLayout>

Then, set the layout as the header:

spinnerLayout = getLayoutInflater().inflate(R.layout.header_view_spinner, null);
listView.addHeaderView(spinnerLayout);

And when we need to hide it, hide the layout’s content, not the layout:

    spinnerLayout.findViewById(R.id.spinner).setVisibility(View.GONE);

Now the header disappears from view. No more ugly space at the top!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Joe Moore

Android Tidbits 6/21/2011: Unregister? Nah!

Joe Moore
Tuesday, June 21, 2011

C2DM Unregister Issues

It turns out when you follow the client-side C2DM unregistration process, this does not guarantee that those registration tokens are permanently unregistered for that device.

If we unregister as specified above and then send a push notification to that registration_id, the server receives an Error=NotRegistered as expected.

But, unexpectedly, when that device re-register with C2DM (and getting a new registration_id), the old registration_id is reactivated as well and can receive push notifications and does not result in a server-side Error=NotRegistered.

The end result: we implemented our server-side API to take both the new and old registration_ids when the Android client successfully registers with C2DM, allowing us to manually delete the old registration_id.

Drawable XML Files

Prefixing the name of a drawable xml file with “active_” seems to prevent android from using that drawable at all.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

Standup 6/21/2011: Our varnish is stale

Pivotal Labs
Tuesday, June 21, 2011

Ask for Help

“Varnish seems to be serving an old asset after a deploy. Where should we look to make it serve the new asset we just deployed?”

You should be looking at your web server’s cache settings. If you are cache busting assets on deploy (built in to Rails 2 & 3) then Varnish should always serve the latest assets. You can also use cache headers to determine the TTL Varnish will use, although a “cache forever” + cache bust strategy should be used if possible.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

Standup 6/20/2011: The sound of failure

Pivotal Labs
Monday, June 20, 2011

Ask for Help

“How do you start nginx on boot on port 80 using homebrew?”

If you sudo add the plist using launchctl it should let you start nginx on port 80. There might be some settings you will need to add to the plist file to make sure nginx starts as the right user.

Interesting Things

  • jQuery 1.5 and IE 9 causes epic failure. What does that failure sound like? We’re not sure, but using jQuery 1.5.1 will make it so you don’t have to find out.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Matthew Kocher

Velocity and Devopsdays Roundup

Matthew Kocher
Sunday, June 19, 2011

I spent a large part of this week at Velocity and Devopsdays. I met a lot of great people and heard way more interesting things than I could absorb. Here’s a collection of things (in no particular order) I found interesting.

  • Get a #&%*&#$##%#% SSD Already

  • JSFiddle is a gist-list site for sharing HTML/CSS/JS snippets. Looks to be a great way to share useful examples and problems. jQuery uses it for bug reports.

  • Dyn’s DynECT seemed to be the standard answer for how to distribute load to different datacenters for load balancing and geo-targetting. There is no standard answer to defeating the CAP theorem.

  • There’s a huge movement to rebuild Splunk in various open source projects. Logstash is an open source project which is piecing together various open source components to get something similar, but is doing index time extraction instead of search time extraction and hasn’t gotten to graphing or analysis yet. Etsy is using Graphite extensively for metrics collection and say that developers prefer it to Splunk. Various other companies are building app-level only metrics collection/reporting solutions. The consensus in the devops community is that Splunk’s pricing does work for the web. As a fan of Splunk, I hope they can figure this out as it’s still better than anything I’ve seen.

  • Etsy’s work with metrics collection is interesting – they’ve written statsD for aggregating things before sending to graphite and Logster for tailing logs and making graphite events out of them.

  • Joshua Timberman of Opscode has some great slides on how to write a Chef cookbook and I wish I’d gotten to see the talk at Devopsdays. I tend to think they error on the side of premature extraction for reusability, but I see their point of view. I’ll definitely be using the remote_file resource and the file_cache_path.

  • 2011 is shaping up to be the year of the Zookeeper alternatives. If you’re not familiar, Zookeeper is a reimplementation of Google’s Chubby – a highly available and reliable system designed to be the system of record for where services are currently available. Netflix has their own internal solution. Heroku has Doozer, and Noah is the new kid on the block with a simple rest interface and http callbacks(aka: webhooks). Opscode is also trying to answer this need by querying the Chef server at runtime for the identities of other hosts on the network. As environments and servers becoming ephemeral, telling every server about every server gets to be a tedious liability. It’ll be interesting to see where this goes.

  • Run Deck (aside from having a great logo) seems to be an interesting way to give users limitable, auditable, and repeatable access to server shells. It’s a web interface that lets you execute commands on various configurable subsets of your infrastructure. It’s got plugins so it can grab the current instances out of EC2, and a jenkins plugin so a Jenkins build can trigger a job in Run Deck. I’ll definitely be checking it out when I get a chance.

  • Pipe Viewer – (pv) Looks awesome. You can put it in a series of pipes in a shell, and it’ll print out a nice status bar about the amount of data passing through the pipe. ‘brew install pv’

  • Opscode has a “fat” installer of chef coming out. It goes in /opt/opscode and includes all the dependencies in the package. This should answer a common complaint about having to install ruby to install ruby. (Yo, dawg, I heard you like Ruby)

  • CSS Lint – Nicole Sullivan and Nicholas Zakas teamed up and introduced CSSLint at Velocity, which looks like it’ll a good addition to a lot of test suites. Nicole also mentioned some cool pure CSS buttons that work on dark and light backgrounds. Lea Verou’s pure css backgrounds were mentioned, which went around the office a while ago but are worth a link. It was also news to me that CSS selectors are run left to right by a browser – “ul.foo span.special *” will match all tags on the page, then narrow it down.

  • Blue/Green Deployment is all the rage the days, and for good reason. Netflix and Amazon are both using it. You’ll have to decide how it fits with your data storage layer, but it’s worked well for me in the past and I’m glad to see it gaining popularity.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Tyler Schultz

Android Image Caching

Tyler Schultz
Saturday, June 18, 2011

Web development spoiled me. Set the src tag on an img tag and away you go. For the most part, browsers just do the right thing and cache these requests. Disappointingly, Android does not come with out of the box support for caching content downloaded from the network. Server apis often require SSL, request headers, support for different HTTP methods, multipart post bodies, etc. requiring the use of the apache http client libraries. These libraries are powerful, but are a bear to work with. As far as I can tell there is no support for caching http responses built into the apache libraries, requiring that you roll your own caching scheme. Images often do not have all these complicated HTTP requirements. They’re usually simple HTTP GET calls. This makes the java.net.* libraries appealing. The java.net libraries come with some handy classes that makes caching a breeze.

Here is a snippet that will cause your request to be pulled from the cache, should it exist. If it doesn’t exist, the retrieved response will be written to the cache.

URL url = new URL("https://pivotallabs.com/images/pivotallabs-logo.png");
URLConnection connection = url.openConnection();
connection.setUseCaches(true);
Drawable drawable = Drawable.createFromStream(connection.getInputStream(), "src");

In the past I tried to use the code above alone and found it didn’t work, and no solutions seemed obvious. The javadocs for URLConnection don’t mention anything about ResponseCache, but there is work to be done there to make it all work. The following example shows using Android’s cache directory to cache the responses. You’ll want to take a moment to read the Android docs about the cache dir. There are guidelines for use of the directory. This looks like a lot of code (Java, Java, Java, Java), but IntelliJ will allow you to cntl-shift-space your way to happiness and write most of it for you.

final String cacheDir = context.getCacheDir();
ResponseCache.setDefault(new ResponseCache() {
    @Override
    public CacheResponse get(URI uri, String s, Map<String, List<string>> headers) throws IOException {
        final File file = new File(cacheDir, escape(uri.getPath()));
        if (file.exists()) {
            return new CacheResponse() {
                @Override
                public Map<String, List<string>> getHeaders() throws IOException {
                    return null;
                }

                @Override
                public InputStream getBody() throws IOException {
                    return new FileInputStream(file);
                }
            };
        } else {
            return null;
        }
    }

    @Override
    public CacheRequest put(URI uri, URLConnection urlConnection) throws IOException {
        final File file = new File(cacheDir, escape(urlConnection.getURL().getPath()));
        return new CacheRequest() {
            @Override
            public OutputStream getBody() throws IOException {
                return new FileOutputStream(file);
            }

            @Override
            public void abort() {
                file.delete();
            }
        };
    }

    private String escape(String url) {
       return url.replace("/", "-").replace(".", "-");
    }
});
</string></string>

This is a simple implementation that pays no attention to the response headers, returns no cached response headers, etc. but I think you get the gist. There is one gotcha: the URI passed into the put method does not contain the path info for the url, it must be retrieved from the URLConnection. Happy caching!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Dan Podsedly

New in Pivotal Tracker: Multi-story select and drag/drop, iPad usability improvements

Dan Podsedly
Friday, June 17, 2011

Happy Friday! We’ve just rolled out some changes to Pivotal Tracker, which we’re hoping will have a very noticeable impact on usability, especially for those of you who manage large projects. You can now select multiple stories with a few clicks, using shift-click, and drag them together to a new location. Also, iPad usability has been greatly improved – for example, story panels can now be scrolled with one finger, and you can move stories via drag and drop

Dragging Multiple Stories

Changing business priorities on large projects has always been a bit painful for us, having to drag stories one by one. Cloning panels helps with this, but really, what we’ve always wanted to do is just select a whole group of stories, and drop them in their new place in the backlog or the icebox with one action. You can now do this, and it’s even possible to drag stories that are in-progress to the backlog or icebox and it just does the right thing (un-starts them).

Click on the screenshot above to see a larger version.

To select multiple stories, use the small checkboxes to the right of story titles. If you’d like to select a range of stories, select the first story in the list, then shift-click on the last story. This will select all in the range, and allow you to drag them together, or use some of the other actions in the Stories drop-down, such as export to CSV or move to another project. Note: range select with shift-click only works in a single panel at a time, but you can select multiple ranges of stories across the whole project.

The Stories drop-down menu has been changed – it now shows the number of selected stories more prominently, and we’ve removed the old bulk story move actions (move to icebox, etc), since this is now possible (and easier) with drag and drop. Note – the Stories menu allows you to unselect all selected stories, which can be useful if you’re moving a lot of stories around in steps.

Note: We realize the that the checkboxes are a bit small, and hard to click on – we’ll be addressing that in an upcoming release. Also, in certain panels and/or browsers, shift-clicking on a checkbox highlights text on the page, we’ll be fixing that as well.

iPad Usability

We’ve addressed most of the major usability issues on the iPad, and Tracker (the web application) now supports one-touch scrolling of panels, drag and drop, easier expanding and collapsing of stories, and displays properly in both orientations.

In horizontal orientation, you can see up to 3 panels at one time, and 2 panels in vertical orientation. But, you can open others, and the panel section will slide sideways to reveal newly opened ones. Dragging sideways will move the panels left and right.

To drag a story, touch it for a brief moment, until it turns yellow, then drag it.

Possible Issues

One of the reasons that all these usability changes were possible, and fairly easy, is because we’ve changed the underlying drag and drop library that Tracker uses. We’ve tried to test thoroughly, and there are some minor issues, but there is fairly good chance that you’ll find some as well. Please let us know, by email to tracker@pivotallabs.com, in the comments here, or over at Twitter.

We’d love your feedback on these changes. There are more new features lined up!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Joe Moore

Syncing IntelliJ Android .apk Files Using Dropbox

Joe Moore
Thursday, June 16, 2011

During a typical day of Android development we compile Android applications (.apk files) dozens of times, deploying to emulators and devices simply by pressing the Run button in IntelliJ. This is great for our in-office developers, but it’s more difficult for our remote-pairing developers to install those same .apks on their own emulators and phones. As a remote developer, I wanted seamless, instant access to all .apks we build during development. Using Dropbox and some IntelliJ configuration changes I now have all .apks we build available for me to install on my local emulators and phones just seconds after we build them on our development machines, 2500 miles away.

Dropbox

Many developers already know about Dropbox, the fast, super-secure file sharing service. I installed Dropbox on all of our machines and created Dropbox directories for each machine our team uses. They happened to be named after streets in San Francisco, Boulder, and Atlanta.

Dropbox dir

Symlinks

Next, on each machine, create an apk symlink to the appropriate Dropbox directory within IntellJ’s ide_bulid directory.

~/workspace/PivotalAndroid$ ln -s ~/Dropbox/PivotalAndroid/grafton_apks ide_build/production/PivotalAndroid/apk

Next, tell IntelliJ to output .apks to that directory. We have to be careful here, especially if you check your .iml file and .idea directory into source control. You can select Project Structure => Facets => (Your Android Module) => Compiler => APK Path:, but this will follow the symlink you created and change your project’s .iml file to include the machine-specific Dropbox directory, and thus a merge conflict on each machine.

Instead, you can manually edit the appropriate value in your .iml:

<!-- old value: -->
<option name="APK_PATH" value="" />

<!-- new value, where '/apk/' is the symlink to Dropbox: -->
<option name="APK_PATH" value="/ide_build/production/PivotalAndroid/apk/PivoalAndroid.apk" />

Note: IntelliJ will sometimes reset APK_PATH back to either the default or to the Dropbox dir. Watch for this and fix the path again when needed. We run into this once per week or so.

Result: Updates Galore!

Now I have .apk files streaming in from three different development machines; as a bonus, each development machine is synced with each other, so we all have access to all .apks. Whenever I want to install the latest .apk from another pair (or my own) onto my local test phone I simply pass the machine name into a script:

#!/usr/bin/env ruby
system "adb -d install -r ~/Dropbox/PivotalAndroid/#{ARGV[0]}-apks/PivotalAndroid.apk"

Thus, scripts/apk cedar installs the latest .apk file created on our machine named “cedar”.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Joseph Palermo

SF Standup 06/16/2011: Instantiate Paperclip model?

Joseph Palermo
Thursday, June 16, 2011

Ask for Help

“I have paperclip columns from a custom sql query. Is there any way to instantiate the associated objects just to generate the paperclip urls for those attachments?”

Calling new on the base class and passing in the data does not seem to work.

Interesting Things

The script tab of the webkit inspector has breakpoints for all kinds of events. Is a click event not behaving like you think it should? You can easily check a box and have all click events open the debugger.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ryan Dy

SF Standup 06/15/2011: Ruby 1.9.2patched and iScroll

Ryan Dy
Wednesday, June 15, 2011

Ask for Help

Interesting Things

  • Looking for performance patches from ruby 1.9.3 that improve the performance of require? They have been back ported to ruby1.9.2p180.
  • A new version of iScroll has been released (v4.1.3). It has performance fixes and better compatibility support. If you need position:fixed or overflow:scroll on a mobile device today you need to check it out.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (781)
  • rails (113)
  • testing (88)
  • ruby (83)
  • ruby on rails (70)
  • jobs (62)
  • javascript (55)
  • techtalk (44)
  • rspec (38)
  • ironblogger (32)
  • productivity (30)
  • activerecord (29)
  • gogaruco (29)
  • git (28)
  • nyc (27)
  • rubymine (26)
  • bloggerdome (23)
  • mobile (22)
  • process (21)
  • pivotal tracker (21)
  • cucumber (20)
  • design (19)
  • jasmine (19)
  • ios (18)
  • webos (17)
  • objective-c (17)
  • android (16)
  • tracker ecosystem (16)
  • palm (16)
  • "soft" ware (16)
  • fun (15)
  • ci (15)
  • cedar (15)
  • rails3 (14)
  • performance (14)
  • bdd (14)
  • gem (13)
  • css (13)
  • tdd (13)
  • selenium (12)
  • goruco (12)
  • bundler (12)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
  • mojo (10)
  • chef (10)
  • api (10)
Subscribe to Community Feed
  1. ←
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5
  7. →
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >