The latest Android and Google Play news for app and game developers.
I’ve always loved screen savers. Supposedly they exist for a practical purpose: protecting that big, expensive monitor from the ghosts of spreadsheets past.
But I’ve always imagined that your computer is secretly hoping you’ll stand up and walk away for a bit. Just long enough for that idle timer to expire…so it can run off and play for a little while. Draw a picture, set off fireworks, explore the aerodynamics of kitchen appliances, whatever—while always ready to get back to work at a keystroke or nudge of the mouse.
Daydream, new in Android 4.2, brings this kind of laid-back, whimsical experience to Android phones and tablets that would otherwise be sleeping. If you haven’t checked it out, you can turn it on in the Settings app, in Display > Daydream; touch When to Daydream to enable the feature when charging.
Apps that support Daydream can take advantage of the full Android UI toolkit in this mode, which means it’s easy to take existing components of your app — including layouts, animations, 3D, and custom views—and remix them for a more ambient presentation. And since you can use touchscreen input in this mode as well, you can provide a richly interactive experience if you choose.
Daydream provides an opportunity for your app to show off a little bit. You can choose to hide some of your app’s complexity in favor of one or more visually compelling experiences that can entertain from across a room, possibly drawing the user into your full app, like a video game’s attract mode.
Figure 1. Google Currents scrolls stories past in a smooth, constantly-moving wall of news.
Google Currents is a great example of this approach: as a Daydream, it shows a sliding wall of visually-interesting stories selected from your editions. Touch a story, however, and Currents will show it to you full-screen; touch again to read it in the full Currents app.
Each Daydream implementation is a subclass of android.service.dreams.DreamService. When you extend DreamService, you’ll have access to a simple Activity-like lifecycle API.
android.service.dreams.DreamService
DreamService
Key methods on DreamService to override in your subclass (don’t forget to call the superclass implementation):
onAttachedToWindow()
setContentView()
onDreamingStarted()
onDreamingStopped()
onDetachedFromWindow()
Important methods on DreamService that you may want to call:
View
setInteractive(boolean)
setInteractive(true)
setFullscreen(boolean)
setScreenBright(boolean)
Finally, to advertise your Daydream to the system, create a <service> for it in your AndroidManifest.xml:
<service>
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.app"> <uses-sdk android:targetSdkVersion="17" android:minSdkVersion="17" /> <application> <service android:name=".ExampleDaydream" android:exported="true" android:label="@string/my_daydream_name"> <intent-filter> <action android:name="android.service.dreams.DreamService" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <meta-data android:name="android.service.dream" android:resource="@xml/dream_info" /> </service> </application> </manifest>
The <meta-data> tag is optional; it allows you to point to an XML resource that specifies a settings Activity specific to your Daydream. The user can reach it by tapping the settings icon next to your Daydream’s name in the Settings app.
<meta-data>
<!-- res/xml/dream_info.xml --> <?xml version="1.0" encoding="utf-8"?> <dream xmlns:android="http://schemas.android.com/apk/res/android" android:settingsActivity="com.example.app/.ExampleDreamSettingsActivity" />
Here's an example to get you going: a classic screen saver, the bouncing logo, implemented using a TimeAnimator to give you buttery-smooth 60Hz animation.
Figure 2. Will one of them hit the corner?
public class BouncerDaydream extends DreamService { @Override public void onDreamingStarted() { super.onDreamingStarted(); // Our content view will take care of animating its children. final Bouncer bouncer = new Bouncer(this); bouncer.setLayoutParams(new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); bouncer.setSpeed(200); // pixels/sec // Add some views that will be bounced around. // Here I'm using ImageViews but they could be any kind of // View or ViewGroup, constructed in Java or inflated from // resources. for (int i=0; i<5; i++) { final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); final ImageView image = new ImageView(this); image.setImageResource(R.drawable.android); image.setBackgroundColor(0xFF004000); bouncer.addView(image, lp); } setContentView(bouncer); } } public class Bouncer extends FrameLayout implements TimeAnimator.TimeListener { private float mMaxSpeed; private final TimeAnimator mAnimator; private int mWidth, mHeight; public Bouncer(Context context) { this(context, null); } public Bouncer(Context context, AttributeSet attrs) { this(context, attrs, 0); } public Bouncer(Context context, AttributeSet attrs, int flags) { super(context, attrs, flags); mAnimator = new TimeAnimator(); mAnimator.setTimeListener(this); } /** * Start the bouncing as soon as we’re on screen. */ @Override public void onAttachedToWindow() { super.onAttachedToWindow(); mAnimator.start(); } /** * Stop animations when the view hierarchy is torn down. */ @Override public void onDetachedFromWindow() { mAnimator.cancel(); super.onDetachedFromWindow(); } /** * Whenever a view is added, place it randomly. */ @Override public void addView(View v, ViewGroup.LayoutParams lp) { super.addView(v, lp); setupView(v); } /** * Reposition all children when the container size changes. */ @Override protected void onSizeChanged (int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mWidth = w; mHeight = h; for (int i=0; i<getChildCount(); i++) { setupView(getChildAt(i)); } } /** * Bouncing view setup: random placement, random velocity. */ private void setupView(View v) { final PointF p = new PointF(); final float a = (float) (Math.random()*360); p.x = mMaxSpeed * (float)(Math.cos(a)); p.y = mMaxSpeed * (float)(Math.sin(a)); v.setTag(p); v.setX((float) (Math.random() * (mWidth - v.getWidth()))); v.setY((float) (Math.random() * (mHeight - v.getHeight()))); } /** * Every TimeAnimator frame, nudge each bouncing view along. */ public void onTimeUpdate(TimeAnimator animation, long elapsed, long dt_ms) { final float dt = dt_ms / 1000f; // seconds for (int i=0; i<getChildCount(); i++) { final View view = getChildAt(i); final PointF v = (PointF) view.getTag(); // step view for velocity * time view.setX(view.getX() + v.x * dt); view.setY(view.getY() + v.y * dt); // handle reflections final float l = view.getX(); final float t = view.getY(); final float r = l + view.getWidth(); final float b = t + view.getHeight(); boolean flipX = false, flipY = false; if (r > mWidth) { view.setX(view.getX() - 2 * (r - mWidth)); flipX = true; } else if (l < 0) { view.setX(-l); flipX = true; } if (b > mHeight) { view.setY(view.getY() - 2 * (b - mHeight)); flipY = true; } else if (t < 0) { view.setY(-t); flipY = true; } if (flipX) v.x *= -1; if (flipY) v.y *= -1; } } public void setSpeed(float s) { mMaxSpeed = s; } }
This example code is handy for anything you want to show the user without burning it into the display (like a simple graphic or an error message), and it also makes a great starting point for more complex Daydream projects.
setScreenBright()
setFullscreen()
View.SYSTEM_UI_FLAG_LOW_PROFILE
Activity
OK, that’s enough for now; you have the tools to go build Daydream support into your apps. Have fun with it — if you do, your users will have fun too. Oh, and when you upload your shiny new APK to Google Play, be sure to add a note to your app’s description so that users searching for Daydreams can discover it.
Posted by Ellie Powers, Product Manager on the Google Play team
Google Play is your way to reach millions and millions of Android users around the world. In fact, since the start of 2011, the number of countries where you can sell apps has increased from 30 to over 130 — including most recently, the launch of paid app support in Israel, Mexico, the Czech Republic, Poland, Brazil and Russia, and fully two-thirds of revenue for apps on Google Play comes from outside of the United States.
To help you capitalize on this growing international audience, it’s now even easier to market your apps to users around the world, by adding images and a video URL to your Google Play store listing for each of Google Play’s 49 languages, just as you’ve been able to add localized text.
A localized feature graphic can show translated text or add local flavor to your app — for example, changing its theme to reflect local holidays. Always make sure that your feature graphic works at different sizes.
Once you’ve localized your app, you’ll want to make sure users in all languages can understand what your app does and how it can benefit them. Review the graphics guidelines and get started with localized graphics.
Localized screenshots make it clear to the user that they’ll be able to use your app in their language. As you’re adding localized screenshots, remember that a lot of people will be getting new tablets for the holidays, and loading up with new apps, so you’ll want to include localized tablet screenshots to show off your tablet layouts.
With localized videos, you can now include a language-appropriate voiceover and text, and of course show the app running in the user’s language.
Ready to add localized images and videos to your store listing? To add localized graphics and video to your apps, you need to use the Google Play Developer Console preview — once you add localized graphics, you won’t be able to edit the app using the old version anymore. Those of you who use APK Expansion Files will now want to try the new Developer Console because it now includes this feature. We’ll be adding support for Multiple APK very soon. Once you’ve saved your application in the new Developer Console, automated translations become available to users on the web and devices — with no work from you.
What are you doing to help your app reach a global audience?
In-app Billing version 3 is available now and lets you sell both in-app items and (since February 2013) subscriptions, including subscriptions with free trials. It is supported by Android 2.2+ devices running the latest version of the Google Play Store (over 90% of active devices).
Bundle bundle = mService.getBuyIntent(3, "com.example.myapp", MY_SKU, ITEM_TYPE_INAPP, developerPayload); PendingIntent pendingIntent = bundle.getParcelable(RESPONSE_BUY_INTENT); if (bundle.getInt(RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) { // Start purchase flow (this brings up the Google Play UI). // Result will be delivered through onActivityResult(). startIntentSenderForResult(pendingIntent, RC_BUY, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0)); }
public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == RC_BUY) { int responseCode = data.getIntExtra(RESPONSE_CODE); String purchaseData = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA); String signature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE); // handle purchase here (for a permanent item like a premium upgrade, // this means dispensing the benefits of the upgrade; for a consumable // item like "X gold coins", typically the application would initiate // consumption of the purchase here) } }
Bundle bundle = mService.getPurchases(3, mContext.getPackageName(), ITEM_TYPE_INAPP); if (bundle.getInt(RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) { ArrayList mySkus, myPurchases, mySignatures; mySkus = bundle.getStringArrayList(RESPONSE_INAPP_ITEM_LIST); myPurchases = bundle.getStringArrayList(RESPONSE_INAPP_PURCHASE_DATA_LIST); mySignatures = bundle.getStringArrayList(RESPONSE_INAPP_PURCHASE_SIGNATURE_LIST); // handle items here }
Bundle bundle = mService.getSkuDetails(3, "com.example.myapp", ITEM_TYPE_INAPP, skus); // skus is a Bundle with the list of SKUs to query if (bundle.getInt(RESPONSE_CODE) == BILLING_RESPONSE_RESULT_OK) { List detailsList = bundle.getStringArrayList(RESPONSE_SKU_DETAILS_LIST); for (String details : detailsList) { // details is a JSON string with // SKU details (title, description, price, ...) } }
<fragment android:id="@+id/map" android:layout_width="match_parent" android:layout_height="match_parent" class="com.google.android.gms.maps.MapFragment" />
// This listener will be called with information about the given panorama. OnPanoramaInfoLoadedListener infoLoadedListener = new OnPanoramaInfoLoadedListener() { @Override public void onPanoramaInfoLoaded(ConnectionResult result, Intent viewerIntent) { if (result.isSuccess()) { // If the intent is not null, the image can be shown as a // panorama. if (viewerIntent != null) { // Use the given intent to start the panorama viewer. startActivity(viewerIntent); } } // If viewerIntent is null, the image is not a viewable panorama. } }; // Create client instance and connect to it. PanoramaClient client = ... ... // Once connected to the client, initiate the asynchronous check on whether // the image is a viewable panorama. client.loadPanoramaInfo(infoLoadedListener, panoramaUri);
To learn more about Google Play services and the APIs available to you through it, visit the new Google Services area of the Android Developers site.
Posted by Roman Nurik, who often writes about Android design-related topics on Google+
So you’ve got a great Android phone app on Google Play, your users love it, and you’re kicking back and watching the download numbers soar. Congrats! But like any enterprising developer, you may be thinking, “how do I take my app’s success even further?” The answer: an equally awesome experience on tablets. Users love their tablet apps! For example, Mint.com found that the larger screen real estate allowed tablet users to engage with their budget data 7x more than on phones. And TinyCo found that on average, paying users spent 35% more on tablets than on handsets. So now is the right time to think about how your app translates onto these larger screen devices that are designed to meet users’ more generic, everyday computing needs.
In this post, we’ll recap some of the resources available for crafting a great tablet experience for your users. These resources are useful for everyone in the app development pipeline—from product managers, to designers, to developers, and QA engineers.
No conversation about Android app design or development should go very far without first consulting the Android Design guidelines. While most of the sections are relevant to all Android devices, certain sections stand out as particularly relevant to design on tablets.
The Devices and Displays page introduces the concept of density-independence. For example, although the Nexus 4, Nexus 7, and Motorola XOOM all have a similar pixel resolution (1280x768, 1280x800, and 1280x800 respectively), they have vastly different screens. Instead of thinking in pixels, think in dips (density-independent pixels)—that way, it’s much easier to conceptualize the difference between Nexus 4 (640x384 dp), Nexus 7 (960x600dp), and Nexus 10 or the Motorola XOOM (1280x800 dp).
Following the 48dp rhythm discussed in Metrics and Grids helps take some of the guesswork out of sizing elements, especially for tablets. When in doubt, use multiples of 48dp (or 16dp for a finer grid) for sizing elements horizontally and vertically. For example, when showing sparse content on larger screens, consider using generous side margins of 96dp or 144dp. Or when deciding how wide your master pane should be in a master/detail layout for 10” tablets, see how your master content looks and feels with a width of 240dp or 288dp.
The Multi-pane Layouts guide discusses use cases and examples for combining related views into a single screen to simultaneously improve app navigation and make optimal use of the available screen real estate. It also discusses strategies for laying out content across both portrait and landscape, all while maintaining functional parity across orientations. Since users enjoy using tablets in both portrait and landscape orientations, it’s even more important to react properly to orientation changes than with phones.
Lastly, the Downloadable Stencils offer designers a great starting point for high-fidelity mockups, complete with reference device outlines, correctly sized action bars, and more.
The Training section of the developer site offers task-oriented technical training material, complete with flow diagrams, code snippets, sample projects and more. Several of these ‘classes’ are geared toward helping developers understand how to scale your apps across any screen size.
The Designing Effective Navigation class—aimed more at the initial design phase of the app creation process—offers a methodology for effectively planning and grouping screens on tablets, and even shows example wireframes for a simple news reader application following this methodology.
The classes Building a Dynamic UI with Fragments and Designing for Multiple Screens demonstrate how to use fragments in conjunction with Android’s resources framework. They show how to easily choose between tablet and handset layouts at runtime while maximizing code reuse and minimizing your application size using resource aliases. They also demonstrate techniques for adapting UI flows based on the current layout.
Lastly, while not precisely a training class, the Supporting Tablets and Handsets document offers even more information about some of these key best practices. And if you’re the type of developer that would prefer to skip the text and jump right into the code, you can even add a Master/Detail flow, complete with handset and tablet support, to your app with just a few clicks using the Android Developer Tools for Eclipse.
Each week, a few of us on the developer relations team get together on the Android Design in Action live show to discuss Android design best practices, as well as provide original ‘redesign’ mockups to help demonstrate our vision of how Android apps should look and feel.
A recent episode focused on the topic of responsive design, or designing flexible apps that can adapt to whatever screen size or form factor they’re run on:
In the episode, we celebrated successful examples of responsive design on Android, ranging from creating calendar events in Google Calendar, to browsing wallpapers and stories in Pattrn and Pocket, to playing video in TED, and finally to managing your conference schedule in the open-source Google I/O 2012 app.
We also regularly feature tablet design concepts on the show (some are shown below), so we highly recommend tuning in each week for design ideas.
For even more tablet app inspiration, check out a few of these apps: Expedia Hotels & Flights, Pulse News, SeriesGuide, Tasks and Timer.
Over in the “Distribute” section of developer.android.com, the recently published Tablet App Quality checklist is a great way to check if your app is tablet-ready along a variety of technical dimensions. You should make sure that everyone involved in your mobile products is aware of the standards defined in this checklist, as it is one of the ways in which the Google Play team selects apps to feature in the Staff Picks for Tablets collection.
It's been an exciting year for Android tablets. Make sure your app is positioned to succeed in the evolving device landscape by following some of the best practices and examples discussed here and on the rest of developer.android.com.
If you have specific questions about your app, let us know on Google+ (+Android Developers) or Twitter (@AndroidDev)!