Designing Hopper 1.0 for Android
Or, Learning to Design for Two Platforms
The Hopper app analyzes billions of flight prices daily to predict how they are going to change, when are the best times to fly, and notifies you when to buy your tickets.
Hopper is currently a mobile-only product, and what that meant for some time was that we were an iOS-only product. Our iOS app has seen a lot of traction since its release at the end of January, with more than 1 million installs since then, and plenty of other forms of appreciation:
We listen closely to this growing community of users. One thing we kept hearing was how many would-be-fans we were losing out on by not having a Hopper app for Android. Android is now the preferred platform for the majority of the global smartphone-using population (around 82.8% vs. 13.9% iOS, according to IDC). If we wanted to grow and scale our product (which, spoiler alert, we do!), we could not ignore these voices.
Making the Switch
I have spent the last several years in product design roles for both web and mobile. I had worked on a few Android projects in the past, specifically on new features or UI elements for existing apps, but my experience was limited. This was the first time I was going to be building one from the ground up. This was also the case for much of the team, so we did a lot of homework up front to understand what we were getting ourselves into. The dev team spent time familiarizing themselves with the Android programming environment, standards, APIs, and so on, while the Product Manager, Jess, and I spent some time understanding the core principles of Google’s Material Design standards, as well as the differences of building for iOS vs. Android, and the Play Store’s requirements.
Material Design played an important and pragmatic role in the process. Their very detailed spec helped me take some focus off the dirty details of the app (e.g. divider types and widths, card IA and padding, etc.) and allowed me to put my energy toward bigger architectural questions surrounding how the core features and flows of the app are applied to Android’s native conventions. That way, we could build something that felt native but still uniquely Hopper.
With our first release on Android, we decided to aim for 1:1 feature parity with our production iOS app, to keep the scope manageable while simultaneously working on our QuickTap Booking feature for iOS. The easiest starting point for us was doing a 1:1 mapping of our current iOS app. In practice, this was literally taking the Sketch files used in our iOS app, copying the app screens (represented by artboards in the file), and renaming them for Android. We then mapped and grouped the screens to the primary user flows so we could analyze how this might change according to Android conventions.
This would set us up for the more painstaking process of remaking all of these screens, one by one, to match the new architectural needs and apply the Material styling.
Changes to the App Architecture
We decided certain architectural changes were critical, in particular, addressing the core navigation of the app. In iOS, the home screen was both a search launch point and a list of trips the user was “watching” in the app. If our app recommends that you should wait to buy your tickets, you can press “watch” and the app will track the flight prices for your route and dates until it hits its expected low before your departure date, and then it will send you a push notification to buy. This home screen is where the watched trips lived. For our QuickTap Booking feature in iOS, we were splitting these two states, search and watch, into two different screens, to set us up for future iterations of the product. We prepared ourselves in Android by doing the same.
Searching for a destination took the user to what we internally call “the report.” In iOS, the report used a standard iOS tab bar to navigate through its several screens, pinned to the footer of the screen. This was perhaps the most visually dramatic iOS convention from which we would have to break: Moving the tabs from the footer up into the Android app bar.
Another major shift in our thinking was required when working with the Android “navigation bar.”
This is used for going back to a previous step or screen, taking the user home, or other functions such as overview and menu. It meant that the user could easily go back a step in the user flow from controls that were not originally designed in the app. This was something we didn’t have to plan for in iOS. If a user tapped between tabs on iOS, the only “back” state was either pressing a new tab or the “home” icon which left the report all together.
Here we had to deal with the possibility that a user would press this device “back” button anywhere in the app. Merely having it play the same role as the “home” button in the report UI seemed too simplistic and potentially jarring for the user. For example, if they were to come to the report and then tap to a second tab, pressing back and going immediately to the app home screen seemed like a potentially frustrating experience. Working closely with our Android developer, Marc, we experimented with a set of rules: We remember the user’s tab patterns, progress right to left on the tabs, and never show one tab more than once with the left-most tab always the exit point from the report.
We’ll be watching the results of these decisions closely for insights into tweaks and improvements we can make.
Preparing Files & Assets
Even more challenging for me was dealing with the fragmentation of devices running Android and assuring that the app’s layout and assets scaled appropriately. While I can’t say we’ve completely optimized this, we’ve built a strong foundation that later iterations will continue to build upon.
I won’t go into all the dirty details, as there are entire resources and articles dedicated to this, but one of the ways Android has evolved to accommodate this is a move away from designing in absolute pixel (px) densities and toward Density-Independent Pixels (DPs) and Scale-Independent Pixels (SPs). One of these units is equal to, as a baseline measurement, one physical pixel on a 160dpi device. But there are also a host of screen densities, and Android has grouped these into several “density buckets,” in which the 160dpi density is the “medium” value, or “mdpi.” The math is easy for a device that has a screen density at 160dpi, since one physical pixel is one dp (1px x 1 scaling factor = 1dp). However, for target devices within other density buckets, you will have to update your pixel values to match their appropriate scaling factor, such as 1dp being equal to 0.75px for phones with resolutions in the low density (ldpi) bucket, or 1dp to 1.5px for those in the high density (hdpi) bucket.
If you are working with vectors, which in most cases you should be, Android recommends starting with a 160dpi density as a baseline and then scaling your assets accordingly for export. The challenge I had for these was really nailing down the proper devices we were targeting, their physical pixels, their associated density buckets (and thus associated scaling factor), and finally the proper DP to pixels ratio.
As a starting point for setting up artboards in Sketch, we used a Samsung Galaxy S5 for our target device, with a physical pixel size of 1920x1080 and the xxhdpi scaling factor of 3. To make our pixel to DP pixel ratio 1:1, we needed to scale down the physical pixel size of the screen by 3, making the baseline artboard size 640x360.
All of this was useful for understanding the relative pixel values we would use for setting up and communicating about typography and layout, ensuring any pixel size we were using was the same in DPs as it was in pixels. It was important that design could communicate this to the development team, so we had a common place to start from when working collaboratively on the UI implementation.
Changes to App Styling
Stylistically, we identified changes that would make the app feel more at home in its new Android surroundings. For starters, we redid the app bar to follow Material standards, with text labels for tabs and the heavy use of our Hopper coral hue:
Our “cards” in the iOS app had been deliberately scaled to be full width, whereas we opted for the more Material-style cards, with rounded corners:
We also identified the buy/wait recommendations as an opportunity to add a bit of character to the UI, using the bunny to further reinforce the prediction results:
In iOS we were using Helvetica Neue as our default typeface; we decided to stick with the Android default Roboto in this version.
Hopper 1.0 for Android
While any v1.0 product is imperfect and we undoubtedly had some missteps along the way, we are pretty excited about the first release of Hopper for Android. Apparently so is the Android community, with over 100K installs in less than a month and plenty of encouraging feedback:
We look forward to how your feedback helps us shape it.
In addition to the many exciting features which we intend to release on both iOS and Android, you can expect us to continue fine-tuning the user experience and interface, as well as defining more platform-independent aspects of the product UI for better unity between the two platforms. Lastly, we’ll be working to get our Android users booking just as easily and effortlessly as they have been with our most recent iOS feature: QuickTap Booking.
-Pantelis Korovilas (@pantelisak), Lead Product Designer at Hopper
Interested in becoming part of the Hopper team? Click on our Jobs page for more information and to apply.