Friday, June 18, 2010

[Gd] SlideRocket completes Google Apps Marketplace integration in just a few days

| More

Google Apps Developer Blog: SlideRocket completes Google Apps Marketplace integration in just a few days

Editor's Note: Mitch Grasso is CTO at SlideRocket. We invited SlideRocket to share their experience integrating the Google Apps APIs for the Marketplace.

We at SlideRocket were very excited to take part in the launch of the new Google Apps Marketplace. We've always seen the value for our customers in providing integration with the Google platform—for example, in SlideRocket you could already load your Google contacts when inviting others to view your presentation, as well as link a table to a Google Docs spreadsheet. The new Google Apps Marketplace made it simple to leverage Google's existing set of extensive data API's to take SlideRocket's integration with Google to a new level for the millions of people already using Google Apps. The best part was that we were able to complete our initial integration for the Marketplace in only a few days thanks to the straightforward platform Google has built using various open standards.

The first and most pivotal step was setting up SlideRocket to work with Google's Federated Login using OpenID. Without the single sign-on capability of Federated Login, the rest of the integration wouldn't work. A key part of the login integration is making sure that Google Apps administrators have control over which of their Apps users have SlideRocket accounts. We accomplished this using the Google Provisioning API, which allowed us to make a small application for administrators to see a list of users in their domain, and check which ones should have SlideRocket accounts.

Fortunately, not only does Google Federated Login provide simple one-click login from Google Apps so that customers don't need a separate SlideRocket user name and password, but it also allows SlideRocket to utilize 2-Legged OAuth to integrate Google Apps users' data into the SlideRocket workflow. This provides the best user experience, because once the Google Apps administration as added SlideRocket as an application, we no longer need to prompt the users for additional permission or confirmation—the integration is seamless from the user's perspective.

Now that the users could easily sign in, it was time to integrate their contacts and Google Docs into SlideRocket. Our existing Google contact integration allowed users to login to their Google account using AuthSub and allow SlideRocket to access their contacts. We left this functionality in place for our existing customers, but for Google Apps users, we now utilize OAuth to automatically load their Google contacts—with no additional work for the user.

Similarly, we expanded our existing Google spreadsheet import functionality for Google Apps users, without having to change it for our existing customers. Existing SlideRocket customers can still paste a link to a published Google spreadsheet and have it imported into a table, but now Google Apps users in SlideRocket will see a list of all of the spreadsheets in their Google Docs account and can easily choose the source for their table. This was easily accomplished on our end using the Google Documents List API. We even expanded this functionality to allow all users—existing customers and Google Apps users—to import a Google spreadsheet directly as a chart or graph in SlideRocket.

We also leveraged the Google Documents List API to allow users to import their Google presentations into SlideRocket, so that they can spice them up a little with some animations, 3D transitions, video, and Flash content. Since the Documents List API provides all of this functionality, we were able to extensively reuse code for tables, charts, and presentations, thereby minimizing the resources required for our integration into the Google Apps Marketplace.

Finally, we are now beginning to use the Google Apps Licensing API so that we are able to view and monitor which Google Apps companies have added SlideRocket to their suite of apps. Although the licensing API is still in Labs, it's provided us a great start towards keeping our Google Apps users properly integrated with our billing system.

It was amazing how quickly we were able to build such a compelling integration for Google Apps and we've just scratched the surface of all the possibilities the dozens of Google Data API's can provide. The best part is that Google has wisely chosen to build upon existing standards like OpenID, OAuth, and AtomPub. This means that none of the resources we invested in learning these technologies and writing integration code is restricted to any one partner—we can reuse what we've gained with other standards-compliant partners in the future.

Author: Mitch Grasso is CTO at SlideRocket
URL: http://googleappsdeveloper.blogspot.com/2010/06/sliderocket-completes-google-apps.html

[Gd] How App Engine served the Humble Indie Bundle

| More

Google App Engine Blog: How App Engine served the Humble Indie Bundle

This is a guest post from Jeffrey Rosen, of Wolfire Games.



Recently, Wolfire Games, joined by four other independent video game developers and two charities, put on a pretty unusual promotion: The Humble Indie Bundle. For twelve days, you could have gone to the promotional site and paid what you want (divided any way you choose among the developers, the EFF, and the Child's Play Charity) for a bundle of independent video games, all compatible with Mac, Windows, and Linux.



The reason why I've been invited to write this guest blog post is because the site was built on Google App Engine and, according to Google Analytics, it served about 3.4 million pageviews (1 million unique visitors) in the 12 days it was live. It grossed over $1.2 million. Depending on who you ask, this is quite a lot of traffic, and we exceeded the free App Engine quota. Google sent us a bill for a grand total of $71.56.



I've been a long time advocate of Google App Engine on the Wolfire Blog, even when traffic was tiny, for a number of reasons. I really like its ease of use, and the fact that Google engineers, including Guido himself (the creator of Python), are the ones making sure everything works at 4 AM, and Google's infrastructure is responsible for data durability and security. The pay-as-you-go price combined with a generous free quota is icing.



As an independent video game developer, it's pretty crazy to have these resources at my disposal. While I'm confident in my Python web coding ability, I am definitely not confident in being a Linux sys-admin and commiting to an expensive server that may or may not handle the load properly (especially scary when critical data is involved). This upfront risk and steep learning curve would probably have been the straw that broke the camels back and turned the bundle into vaporware.



How did App Engine perform?



According to Google Analytics we did about 3.4 million pageviews (1 million unique visitors) during the bundle period on the Wolfire site (heavily concentrated around the first and last days). The traffic came in huge surges from Reddit, Slashdot, Digg, and a plethora of gaming and tech sites, and people seemed to really enjoy pushing the server by refreshing the page to update the real-time statistics. App Engine performed as advertised: additional servers were seamlessly brought up as needed and shut down when appropriate.



One thing that was really neat about the bundle is that it had a bunch of real-time statistics about purchases along with a leaderboard of the top contributions. There were many interesting donations, for example, $3333.33, $1337, $327.67, and $313.37 and watching the average donation go up and down was really addictive. I think being able to refresh the page to see the sales coming in was a really big draw for the bundle. This feature was really easy to implement on App Engine using a sharding counter. I'm really looking forward to native comet support in App Engine so the next bundle can have this update completely live, without polling or refreshing. Memcache and the datastore is built for stuff like this, so it was very fast.



How was developing on App Engine?



One awesome thing about App Engine is how it handles the deployment for you transparently and seamlessly. I felt comfortable developing, testing, and ultimately deploying new features to the site, even while it was serving say, 100 visitors per second. App Engine handles all the details of seamlessly bringing down the servers and getting the new ones in place even under intense loads. Because of this, I was able to hack on new features to the site as necessary. For example, I expanded the statistics so that you could see the platform specific average payments in real-time. That feature was started, tested, and deployed on maybe the third day of the bundle. Similarly, I spontaneously added an unplanned sixth game (Samorost 2) to the bundle on the fifth day and deployed minor tweaks dozens of times throughout the promo.



One thing that the bundle made clear to me is that raw Python code is much faster than you might expect. After I finished building the prototype of the bundle, I was getting ready to heavily optimize everything: each hit to the Humble Bundle page executed a few hundred lines of my Python code, doing all sorts of calculations for the statistics and inserting that into a massive Django template. Initially I thought that there would be no way this would be scalable and I'd need to aggressively cache the whole page. However, when I looked at the estimated CPU usage (tip: if you look at the request headers of a page while logged in as an admin, App Engine gives you some estimates on how much it will charge you for 1000 requests and how long it will take) it was something like 0.00375 CPM and was executing in milliseconds. Despite what I had assumed to be inefficient, unoptimized code, the CPM was so ridiculously low and it was executing so fast, I decided not to even bother optimizing the backend further. The only thing that was taking any time at all were the few memcache calls to retrieve the real-time list of tweets, real-time raw sales data, and other interesting stats. In hindsight though, I could have easily shaved off 30 ms by combining all the memcache requests into a single RPC with memcache.get_multi.



Was there anything App Engine could improve?



While I am really satisfied with App Engine and credit its existence and my familiarity with it for the existence of the Humble Indie Bundle in the first place, there were a few gotchas:



Due to a scheduled maintenance period on the datastore, the bundle was down for about 20 minutes (we need to store metadata about people's orders before we forward them to PayPal, Amazon Payments, or Google Checkout). Normally a message pops up to inform people when downtime occurs is going on, but this didn't activate for some reason, so we had to handle a lot of email about a blank page when people were trying to place their orders. I understand that Google is addressing this though.



The features that I would like to ask for are mostly all "on deck" on the roadmap: SSL for custom domains, comet support, and longer background tasks in particular. I'd also like to see App Engine focus on utilizing Google's infrastructure by serving non-static requests geographically like "web acceleration" services from CDNs. There are some trade-offs due to the nature of the datastore, but I think it can be done.



Thanks for having me on the blog! People can find me on the Wolfire Blog where we talk about more technical and game design topics, and check out our upcoming game Overgrowth.




Posted by Jeffrey Rosen of Wolfire Games
URL: http://googleappengine.blogspot.com/2010/06/how-app-engine-served-humble-indie.html

Thursday, June 17, 2010

[Gd] Highlights from the Google I/O Wave Developer Sandbox

| More

Google Wave Developer Blog: Highlights from the Google I/O Wave Developer Sandbox



We recently celebrated Google Wave's 1st Birthday and announced several API and protocol updates at Google I/O. Along with that we invited 17 partners and developers to showcase their Wave extensions and integrations as part of the Google Wave Developer Sandbox. We've been amazed at the many extensions and product integrations that developers have built eversince we launched Wave and we wanted to share with the public what were showcased at I/O:




Extensions:





Product Integrations:



  • ProcessOne demoed their WaveOne XMPP server built based on the Wave protocol.


  • Salesforce demoed their wave integration inside Chatter, their collaborative product.


  • Oracle demoed their wave integration inside their CRM product.




Federation:



  • SAP demoed their new Gravity product built based on the Wave protocol.


  • Novell showcased Pulse, their collaborative product based on Wave protocol.




To see videos of many of the above extensions in action and read more about them, check out our featured extension page. We hope these extensions and product integrations will inspire you to build more things on Google Wave. As always, we love to hear from developers. If you have feedback on our APIs or want to build extensions, read our guide and drop us a line in the Wave APIs forum. If you're interested in the Wave Protocol, check out http://www.waveprotocol.org and join the Wave Protocol discussion forum.

URL: http://googlewavedev.blogspot.com/2010/06/highlights-wave-developer-sandbox-at-io.html

[Gd] Bringing improved PDF support to Google Chrome

| More

Chromium Blog: Bringing improved PDF support to Google Chrome

Millions of web users rely on PDF files every day to consume a wide variety of text and media content. To enable this, a number of plug-ins exist today which allow users to open PDF files inside their browsers.

As we’ve previously mentioned, the traditional browser plug-in model, though powerful, presents challenges in compatibility, performance, and security. To overcome this, we’ve been working with the web community to help define a next generation browser plug-in API.

We have begun using this API to improve the experience of viewing and interacting with PDF files in Google Chrome. This mirrors our efforts to optimize the Adobe Flash Player experience in Chrome.

Today, we are making available an integrated PDF viewing experience in the Chrome developer channel for Windows and Mac, which can be enabled by visiting chrome://plugins. Linux support is on the way, and we will be enabling the integration by default in the developer channel in the coming weeks.

With this effort, we will accomplish the following:
  • PDF files will render as seamlessly as HTML web pages, and basic interactions will be no different than the same interactions with web pages (for example, zooming and searching will work as users expect). PDF rendering quality is still a work in progress, and we will improve it substantially before releasing it to the beta and stable channels.
  • To further protect users, PDF functionality will be contained within the security “sandbox” Chrome uses for web page rendering.
  • Users will automatically receive the latest version of Chrome’s PDF support; they won’t have to worry about manually updating any plug-ins or programs.
Currently, we do not support 100% of the advanced PDF features found in Adobe Reader, such as certain types of embedded media. However, for those users who rely on advanced features, we plan to give them the ability to launch Adobe Reader separately.

We would also like to work with the Adobe Reader team to bring the full PDF feature set to Chrome using the same next generation browser plug-in API.

We’re excited about the usability and security improvements this will bring to Chrome users, and we’ll continue to keep everyone updated on our efforts through this blog.

Posted by Marc Pawliger, Engineering Director
URL: http://blog.chromium.org/2010/06/bringing-improved-pdf-support-to-google.html

[Gd] Reintroducing Video Ads

| More

AdWords API Blog: Reintroducing Video Ads

Back in 2007, we first introduced support for video ads (Click-to-Play Video) in the AdWords API. This required a dedicated VideoAd type, which made it less adaptive to future video formats. The AdWords API has significantly improved since then with more flexible support for handling various ad types.

Video ads in the API are now supported through a new type, the TemplateAd. Template ads allow for an easy way to introduce new ad types, defined through template ad formats, without having to add new ad types. In turn, this makes it possible to release new ad features and updates much faster without waiting for the next version of the API.

Before a video ad can be created, the campaign must be set to show ads on the content network. As in previous versions, the video itself must be uploaded to your account via the web interface (see instructions). Once your video is uploaded, it is assigned a media ID, one of the elements required to create a video ad, which can be retrieved through the MediaService’s get() method. Now you have everything you need to create a video ad via the AdGroupAdService using the Click-to-Play Video template ad format. The client libraries have examples for retrieving a media ID and creating video
ads in various languages. Here’s an example in Python,

operations = [
{
'operator': 'ADD',
'operand': {
'type': 'AdGroupAd',
'adGroupId': ad_group_id,
'ad': {
'type': 'TemplateAd',
'templateId': '9',
'templateElements': [{
'uniqueName': 'adData',
'fields': [
{
'name': 'startImage',
'type': 'IMAGE',
'fieldMedia': {
'mediaTypeDb': 'IMAGE',
'name': 'Starting Image',
'data': image_data
}
},
{
'name': 'displayUrlColor',
'type': 'ENUM',
'fieldText': '#ffffff'
},
{
'name': 'video',
'type': 'VIDEO',
'fieldMedia': {
'mediaId': video_media_id,
'mediaTypeDb': 'VIDEO'
}
}
]
}],
'dimensions': {
'width': '300',
'height': '250'
},
'name': 'VideoAdTemplateExample',
'url': 'http://www.example.com',
'displayUrl': 'www.example.com'
}
}
}
]
ads = ad_group_ad_service.Mutate(operations)

As always, post any questions you have regarding this topic or other aspects of the API to the forum.


-- Stan Grinberg, AdWords API Team
URL: http://adwordsapi.blogspot.com/2010/06/reintroducing-video-ads.html

[Gd] Dev Channel Update

| More

Google Chrome Releases: Dev Channel Update

The Dev channel has been updated to 6.0.437.1 for Windows and Linux, and Mac has been updated to 6.0.437.2.

All
  • [r49492] Detach Reload from omnibox, combine with Stop, and eliminate Go. (Issue: 45745).
  • [r49712] Implemented initial version of extension syncing. (Issue (with instructions on how to enable): 32413, but see 46742).
  • The onChanged event is now working in the extensions experimental cookies API.
Windows
  • See All
Mac
  • [r49442] Faster scrolling on 10.6 (Issue: 45553).
  • [r49536] Fix a bug where menu items would be disabled if no windows were open. (Issue: 46355)
Linux
  • [r49458] Undo experiment where we used the tab theme image as the frame in popup windows. We now always use the default blue frame, matching Windows instead of matching Mac. (Issue: 43938)
  • [r49467] Side tabs for content settings window (Issue: 45546)
  • [r49451] Fix restore button doing nothing in certain circumstances (Issue: 46232)
Known Issues
  • Some images for the main toolbar are wrong (the Stop button is incorrectly squared off on Windows and Linux, and the omnibox edges are wrong on Mac).
More details about additional changes are available in the svn log of all revision.

You can find out about getting on the Dev channel here: http://dev.chromium.org/getting-involved/dev-channel.

If you find new issues, please let us know by filing a bug at http://code.google.com/p/chromium/issues/entry

Anthony Laforge
Google Chrome
URL: http://googlechromereleases.blogspot.com/2010/06/dev-channel-update_17.html

Wednesday, June 16, 2010

[Gd] Private Member Variables in Javascript Objects

| More

Google Apps Developer Blog: Private Member Variables in Javascript Objects

The programming language of Google Apps Script is JavaScript (ECMAScript). JavaScript is a very flexible and forgiving language which suits us perfectly, and there's also a surprising amount of depth and power in the language. To help users get into some of the more useful power features we're starting a series of articles introducing some more advanced topics.

Let's say we want to create an object that counts the number of occurrences of some event. To ensure correctness, we want to guarantee the counter can't be tampered with, like the odometer on your car. It needs to be "monotonically increasing". In other words, it starts at 0, only counts up, and never loses any previously counted events.

Here's a sample implementation:

  Counter = function() {
    this.value = 0;
  };

  Counter.prototype = {    
    get: function() {
      return this.value;
    },
    increment: function() {
      this.value++;
    }
  };

This defines a constructor called Counter which can be used to build new counter objects, initialized to a value of zero.  To construct a new object, the user scripts counter = new Counter(). The constructor has a prototype object, providing every counter object with the methods counter.increment() and counter.get(). These methods count an event, and check the value of the counter, respectively. However, there is nothing to stop the script from erroneously writing to counter.value. We would like to guarantee that the counter's value is monotonically increasing, but lines of code such as counter.value-- or counter.value = 0 roll the counter back, breaking our guarantee.

Most programming languages have mechanisms to limit the visibility of variables. Object-oriented languages often feature a private keyword, which limits a variable's visibility to the code within the class. Such a mechanism would be ideal here, ensuring that only the methods counter.increment() and counter.get() could access value. Assuming that these two methods are correctly implemented, we can be sure that our counter can't get rolled back.

Javascript has this private variable capability as well, despite not having an actual keyword for it. Let's examine the following code:

  Counter = function() {
    var value = 0;
    this.get = function() {
      return value;
    };
    this.increment = function() {
      value++;
    };
  };

This constructor gives you objects that are indistinguishable from those built with the first constructor, except that value is private. The variable value here is not the same variable as counter.value used above. In fact, the latter is undefined for all objects built with this constructor.

How does this work? Instead of making value a member variable of the object, it is a local variable of the constructor function, by use of the var keyword. The get and increment functions are the only functions that can see value because they are defined within the same code block. Only code inside this block can see value; outside code does not have access to it. However, these methods are publicly visible by having been assigned to the this object.

Limiting visibility of variables is considered a good practice, because it rules out many buggy states of your program. Make sure to use this technique wherever possible.

Cross-posted from Google Apps Script Blog 

by: Jason Ganetsky, Software Engineer, Google Apps Script

URL: http://googleappsdeveloper.blogspot.com/2010/06/private-member-variables-in-javascript.html

[Gd] The votes are in!

| More

OpenSocial API Blog: The votes are in!

The OpenSocial Foundation community representatives election has concluded. You have selected Paul Lindner and Mark Halvorson to serve as your two representatives for this year's board. Congratulations to Paul and Mark!

For those of you looking to get involved with OpenSocial, there are many opportunities outside the board, including:
  • wiki.opensocial.org: Contribute to documenting best practices and articles on the new OpenSocial community wiki
  • Get Started Building Apps: Brainstorm, check out a few tutorials, and get programming
  • Help build OpenSocial 1.1: Participate in the on-going evolution of OpenSocial's technical specification by contributing to the next version of the specification

See you on the forums!

Posted on behalf of the OpenSocial Foundation by Mark Weitzel (Secretary)
URL: http://blog.opensocial.org/2010/06/votes-are-in.html

[Gd] Google Storage for Developers: Sharing with Groups

| More

Google Code Blog: Google Storage for Developers: Sharing with Groups

Last month we introduced Google Storage for Developers with support for sharing with Google account holders. Today, we are enabling support for sharing with groups, giving you greater control and flexibility over how you share your data.

You can now easily share your Google Storage data with groups of users as well as individuals. Here are some examples of the things you can do with group sharing:
  • Share data with an entire department or mailing list
  • Make data publicly readable, but editable only by a group within your company
  • Keep access controls consistent with the current membership of a team
  • Add or remove a user's access to shared data via a single group membership change without having to change access control lists (ACLs) on all the buckets and objects involved.
You can share with groups by adding one or more Google Groups to the ACL of a bucket or object. A group member can be anyone with a Google Account, and members can authenticate using either their Google Storage credentials or in an authenticated browser session.

You can find more details on the new group sharing feature here. We have also updated our GSUtil command-line tool to support group sharing.

Thanks to everyone who has tested Google Storage so far. As always, we appreciate your feedback. Please let us know what you think on the Google Storage forum.

By Jessie Jiang, Google Storage for Developers Team
URL: http://googlecode.blogspot.com/2010/06/google-storage-for-developers-sharing.html

[Gd] Different ways to delete

| More

AdWords API Blog: Different ways to delete

Part of managing an AdWords account is cleaning out old or non-performing items, such as unused ad groups or low search volume keywords. Not all entities are deleted in the same way however, and the different methods are outlined below.

Use the SET operator and change the status to DELETED

This approach is used for entities that can be restored at any time and start serving again. The DELETED status is not permanent in this case and can be changed to ACTIVE in the future. For these requests you only need to include the entity's id and its new status.

This approach used by:
  • CampaignService
  • AdGroupService

Use the REMOVE operator

This approach is used for entities that are permanently deleted from your account and can't be restored. This operator doesn't guarantee that the entity is completely removed from your account and may remain but in a DELETED or DISABLED state.

This approach is used by:
  • AdGroupAdService
  • AdGroupCriterionService
  • AdExtensionOverrideService
  • AdParamService
  • CampaignAdExtensionService

Use the SET operator and exclude the entity from the list

This method is used for entities that don't have unique ids but are returned in a list. This process involves retrieving the current list, removing the entity, and then sending back the updated list.

This approach is used by the CampaignTargetService.

As always, post any questions you have regarding this topic or other aspects of the API to the forum.

Best,
- Eric Koleda, AdWords API Team
URL: http://adwordsapi.blogspot.com/2010/06/different-ways-to-delete.html

[Gd] The polls are closed!!

| More

OpenSocial API Blog: The polls are closed!!

Greetings Everyone,

This is just a quick note to let you know that the election for the two OpenSocial Board Community Representatives is now officially closed. We will be tallying up the ballots and posting the results shortly.

I would like to thank all of our nominees for being willing to commit their time and effort to OpenSocial, as well as all of those who took the time to vote. Finally, I owe one last thank you to Ryan Boyd of Google who went above and beyond to helped make everything happen behind the scenes.

Posted on behalf of the OpenSocial Foundation by Mark Weitzel (Secretary)


URL: http://blog.opensocial.org/2010/06/polls-are-closed.html

Tuesday, June 15, 2010

[Gd] Game Development for Android: A Quick Primer

| More

Android Developers Blog: Game Development for Android: A Quick Primer

[This post is by Chris Pruett, an outward-facing Androider who focuses on the world of games. — Tim Bray]

If you attended Google I/O this year, you might have noticed the large number of game developers showing off their stuff in the Android part of the Developer Sandbox. Unity, EA, Com2Us, Polarbit, Laminar Research, and several others demonstrated high-end games running on Android devices. Part of my role as a Game Developer Advocate for Android is to field requests for information about Android from game developers, and in the last six months the number of requests has gone through the roof. Since there’s clearly a huge amount of interest in Android game development, here’s an overview of how Android games work and what you as a developer should know.

Step One: Decide on a Target Device Class

There are basically two types of devices running Android that you should consider: lower-end devices like the G1 (which I’ll call “first generation” devices), and high-end devices like the Nexus One (”second generation” devices). Though there are a lot of different Android phones on the market, they fall rather neatly into these two classes when it comes to CPU and graphics performance, which are the variables that game developers usually care the most about.

First generation devices are generally phones with HVGA screens, running Android 1.5 or 1.6 (though a few are starting to make their way to 2.1), typically with an 500mhz CPU and hardware accelerated OpenGL ES 1.0 backend. A large number of devices sport internals similar to the G1 (Qualcomm MSM7K CPU/GPU at ~500mhz), so the G1 is representative of this class (and can be safely considered the low end of the spectrum). Based on my tests, these devices can push about 5000 textured, colored, unlit vertices per frame and still maintain 30 frames per second. Using OpenGL ES to draw, I can get just over 250 animating sprites on the screen at 30 frames per second (at 60 fps I can draw just over 100 sprites per frame). These aren’t hard numbers; my benchmarks are fairly primitive, and I’m sure that they can be improved (for example, I haven’t done tests using the GL_OES_point_sprite extension, which the G1 supports). But they should give you an idea of what the first generation class of devices can do.

Second generation devices generally have WVGA screens, much faster CPUs and GPUs, and support for OpenGL ES 2.0. The Nexus One and Verizon Droid by Motorola are both good examples of this class. These devices seem to be about 5x faster than the first generation devices when it comes to raw OpenGL 1.0 performance (I can get at least 27,000 textured unlit colored vertices per frame at 30 frames per second on all of the second generation devices I’ve tested). Using OpenGL ES 2.0 can be even faster, as these devices typically incur some overhead translating OpenGL ES 1.0 commands to their 2.0-native graphics hardware. However, the large screens on these devices often mean that they are fill-bound: the cost of filling the screen with pixels is high enough that it’s often not possible to draw faster than 30 frames per second, regardless of scene complexity.

Since there is a pretty wide performance delta between the first generation class of devices and the second, you should be careful when selecting a target. Based on our metrics about Android versions, first generation devices represent over half of all of the Android phones on the market (as of this writing, anyway; 2.0 devices are growing very quickly). Those games that are able to scale between the first and second generation devices have the largest audience.

Step Two: Pick a Language

If you’re an Android app programmer who’s thinking about getting into game development, chances are you are planning on writing code in Java. If you’re a game development veteran who’s thinking of bringing games to Android, it’s likely that you prefer to do everything in C++.

The side-scrolling action game that I wrote, Replica Island, is entirely Java. It uses OpenGL ES 1.0 to draw and is backwards compatible to Android 1.5. It runs at a good frame rate (close to 60 fps on the G1) across almost all Android devices. In fact, many of the popular games on Android Market were written in Java, so if you’re the type of person who finds coding in C++ like speaking in tongues, you can rest easy in the knowledge that Java on Android is perfectly viable for games.

That said, native code is the way to go if your game needs to run as fast as possible. We’ve just released the fourth revision of our Native Development Kit for Android, and it includes a number of improvements that are particularly useful to game developers. Using the NDK, you can compile your code into a shared library, wrap it in a thin Java shell to manage input and lifecycle events, and do all of the heavy lifting in C++ with regular OpenGL ES APIs. As of Revision 4, you can also draw directly into Java Bitmap pixel buffers from native code, which should be faster than loading bitmaps as GL textures every frame for 2D games that want to do their own scene compositing. Revision 4 also (finally!) includes gdb support for debugging your native code on the device.

You should know that when using the NDK, you don’t have access to Android Framework APIs. There’s no way, for example, to play audio from C++ (though we announced at Google I/O our intention to support OpenSL ES in the future). Some developers use the AudioTrack API to share a direct buffer with native code that mixes and generates a PCM stream on the fly, and many call from C++ into the Java SoundPool interface. Just be aware that for this type of work, a jump through JNI back into Java code is required.

Step Three: Carefully Design the Best Game Ever

Once you have a target system spec and have decided on a development environment, you’re off and running. But before you get too deep into your epic ragdoll physics-based space marine action online RPG with branching endings and a morality system, take a minute to think about your end users. Specifically, there are two areas that require consideration for Android games that you might not be used to: texture compression and input systems.

Texture compression is a way to (surprise!) compress your texture data. It can improve draw performance and let you pack more texture into vram. The problem with texture compression is that different graphics card vendors support different texture formats. The G1 and other MSM7k devices support ATI’s ATITC compression format. The Droid supports PowerVR’s PVRTC format. Nvidia’s Tegra2 platform supports the DXT format. The bad news is, these formats are not compatible. The good news is, all OpenGL ES 2.0 devices (including the Snapdragon-based Nexus One, the OMAP3-based Droid, and Tegra2 devices) support a common format called ETC1. ETC1 isn’t the best texture format (it lacks support for alpha channels), and it isn’t supported on the first generation devices, but it’s the most common format supported (the Android SDK provides a compressor utility (see sdk/tools/etc1tool) and runtime tools for this format).

The bottom line is that if you compress your textures, you’ll need to somehow provide different versions of those textures compressed with different formats. You could do this all in a single apk, or you could download textures from a web site over HTTP, or you could use ETC1 and restrict yourself to only OpenGL ES 2.0 devices. For Replica Island, I just chose not to compress my textures at all and had no problems. You can query the GL_EXTENSIONS string to see what the device you are currently running on supports.

String extensions = gl.glGetString(GL10.GL_EXTENSIONS);

String version = gl.glGetString(GL10.GL_VERSION);
String renderer = gl.glGetString(GL10.GL_RENDERER);

boolean isSoftwareRenderer = renderer.contains("PixelFlinger");
boolean isOpenGL10 = version.contains("1.0");
boolean supportsDrawTexture =
extensions.contains("draw_texture"); // looking for "GL_OES_draw_texture"
boolean supportsETC1 =
extensions.contains("ETC1"); // looking for "GL_OES_compressed_ETC1_RGB8_texture"

// VBOs are guaranteed in GLES1.1, but they were an extension under 1.0.
// There's no point in using VBOs when using the software renderer (though they are supported).

boolean supportsVBOs =
!isSoftwareRenderer && (!isOpenGL10 || extensions.contains("vertex_buffer_object"));

You should also think carefully about how your game will be played. Some phones have a trackball, some have a directional pad, some have a hardware keyboard, some support multitouch screens. Others have none of those things. Per the Compatibility Definition Document, all Android devices that have Android Market are required to have a touch screen and three-axis accelerometer, so if you can get away with just tilt and single touch, you don’t need to worry about input much. If you want to take advantage of the various input devices that these phones support (which, based on several thousand comments on Android Market about Replica Island, I wholeheartedly recommend), the Android API will package the events up for you in a standard way.

That said, one of the most dramatic lessons I learned after shipping Replica Island is that users want customizable controls. Even if you have added perfect support for every phone, many users will want to go in and tweak it. Or they prefer the hardware keyboard over their phone’s dpad. Or they prefer tilt controls over trackball controls. My advice: plan on providing customizable controls, both so that you can support phones that have input configurations that you didn’t consider, and also so that you can allow users to tweak the experience to match their preferences.

Step Four: Profit!

The rest is up to you. But before you go, here are a few resources that might come in handy:

  • HeightMapProfiler. This is a simple 3D benchmarking tool that I wrote. It is the source of the performance numbers in this post. You can also use it to test how various GL state affects performance on your device (texture size, texture filtering, mip-mapping, etc).

  • SpriteMethodTest. Another simple benchmarking tool, this one for sprite drawing. This code is also a useful as a 2D game skeleton application.

  • GLSurfaceView. This is a Java class that makes it trivial to set up an OpenGL ES application. You can use this code in combination with the NDK or with Java alone.

  • Quake Port. The complete source for an Android port of Quake has been made available by Jack Palevich, an Android team engineer. It’s a great sample of how to mix Java and native code, how to download textures to the sdcard over HTTP, and all kinds of other cool stuff (check out his memory-mapped-to-sdcard texture manager).

  • Replica Island. Here’s the complete source to my game, released under Apache2. Use it as a reference, or to make your own games.

URL: http://android-developers.blogspot.com/2010/06/game-development-for-android-quick.html

[Gd] Reversing Code Bloat with the JavaScript Knowledge Base

| More

Google Code Blog: Reversing Code Bloat with the JavaScript Knowledge Base

JavaScript libraries let developers do more with less code. But JavaScript libraries need to work on a variety of browsers, so using them often means shipping even more code. If JQuery has code to support XMLHttpRequest over ActiveX on an older browser like IE6 then you end up shipping that code even if your application doesn't support IE6. Not only that, but you ship that code to the other 90% of newer browsers that don't need it.


This problem is only going to get worse. Browsers are rushing to implement HTML5 and EcmaScript5 features like JSON.parse that used to be provided only in library code, but libraries will likely have to keep that code for years if not decades to support older browsers.


Lots of compilers (incl. (JSMin, Dojo, YUI, Closure, Caja) remove unnecessary code from JavaScript to make the code you ship smaller. They seem like a natural place to address this problems. Optimization is just taking into account the context that code is going to run in to improve it; giving compilers information about browsers will help them avoid shipping code to support marginal browsers to modern browsers.

The JavaScript Knowledge Base (JSKB) on browserscope.org seeks to systematically capture this information in a way that compilers can use.

It collects facts about browsers using JavaScript snippet. The JavaScript code (!!window.JSON && typeof window.JSON.stringify === 'function') is true if JSON is defined. JSKB knows that this is true for Firefox 3.5 but not Netscape 2.0.

Caja Web Tools includes a code optimizer that uses these facts. If it sees code like

if (typeof JSON.stringify !== 'function') { /* lots of code */ }

it knows that the body will never be executed on Firefox 3.5, and can optimize it out. The key here is that the developer writes feature tests, not version tests, and as browsers roll out new features, JSKB captures that information, letting compilers produce smaller code for that browser.


The Caja team just released Caja Web Tools, which already uses JSKB to optimize code. We hope that other JavaScript compilers will adopt these techniques. If you're working on a JavaScript optimizer, take a look at our JSON APIs to get an idea of what the JSKB contains.


If you're writing JavaScript library code or application code then the JSKB documentation can suggest good feature tests. And the examples in the Caja Web Tools testbed are good starting places.


By Mike Samuel (Caja), Lindsey Simon (Browserscope)

URL: http://googlecode.blogspot.com/2010/06/reversing-code-bloat-with-javascript.html

[Gd] Reversing Code Bloat with the JavaScript Knowledge Base

| More

Google Code Blog: Reversing Code Bloat with the JavaScript Knowledge Base

JavaScript libraries let developers do more with less code. But JavaScript libraries need to work on a variety of browsers, so using them often means shipping even more code. If JQuery has code to support XMLHttpRequest over ActiveX on an older browser like IE6 then you end up shipping that code even if your application doesn't support IE6. Not only that, but you ship that code to the other 90% of newer browsers that don't need it.


This problem is only going to get worse. Browsers are rushing to implement HTML5 and EcmaScript5 features like JSON.parse that used to be provided only in library code, but libraries will likely have to keep that code for years if not decades to support older browsers.


Lots of compilers (incl. (JSMin, Dojo, YUI, Closure, Caja) remove unnecessary code from JavaScript to make the code you ship smaller. They seem like a natural place to address this problems. Optimization is just taking into account the context that code is going to run in to improve it; giving compilers information about browsers will help them avoid shipping code to support marginal browsers to modern browsers.

The JavaScript Knowledge Base (JSKB) on browserscope.org seeks to systematically capture this information in a way that compilers can use.

It collects facts about browsers using JavaScript snippet. The JavaScript code (!!window.JSON && typeof window.JSON.stringify === 'function') is true if JSON is defined. JSKB knows that this is true for Firefox 3.5 but not Netscape 2.0.

Caja Web Tools includes a code optimizer that uses these facts. If it sees code like

if (typeof JSON.stringify !== 'function') { /* lots of code */ }

it knows that the body will never be executed on Firefox 3.5, and can optimize it out. The key here is that the developer writes feature tests, not version tests, and as browsers roll out new features, JSKB captures that information, letting compilers produce smaller code for that browser.


The Caja team just released Caja Web Tools, which already uses JSKB to optimize code. We hope that other JavaScript compilers will adopt these techniques. If you're working on a JavaScript optimizer, take a look at our JSON APIs to get an idea of what the JSKB contains.


If you're writing JavaScript library code or application code then the JSKB documentation can suggest good feature tests. And the examples in the Caja Web Tools testbed are good starting places.


By Mike Samuel (Caja), Lindsey Simon (Browserscope)
URL: http://googlecode.blogspot.com/2010/05/reversing-code-bloat-with-javascript.html