Tuesday, July 13, 2010

New About Google - 13 July 2010

  • Introduction to ReportDefinitionService

    July 13, 2010

    Reporting is an integral part of most AdWords API applications. To help you create and manage reports related to your AdWords campaigns, we introduced the ReportDefinitionService in the v201003 version of the AdWords API. In this post, we’ll cover the basics of working with the ReportDefinitionService. If you’ve used the v13 ReportService, you’ll notice that the new ReportDefinitionService differs in many ways from its v13 counterpart.

    Retrieving the report fields

    To create a report in the v201003 version of AdWords API, you pick a

  • How to have your (Cup)cake and eat it too

    July 12, 2010

    [This post is by Adam Powell, his second touchy-feely outing in just a few weeks. I asked him to send me a better picture than we ran last time, and got this in response. Photo by our own Romain Guy. — Tim Bray]

    Android developers concerned with targeting every last device with their apps are no doubt familiar with this chart:

    On July 1, 2010 this was the breakdown of active devices running different versions of the Android platform. With all of the new platform features added to the Android SDK in each version, this chart has many developers shouting the F-word when they are forced to choose between integrating newer platform features and providing their app to the widest possible audience.

    Savvy Android developers already know that these two options aren’t really mutually exclusive, but that straddling between them can be painful. In this post I’m going to show you that it doesn’t have to be that way.

    Several weeks ago we took a look at how to handle multitouch on Android 2.0 (Eclair) and above, and by the end we had a simple demo app. That app uses features exclusive to Android 2.2 (Froyo) which as of this writing hasn’t had a chance to reach many devices yet. In this post we’re going to refactor that demo to run on devices all the way back to Android 1.5 (Cupcake). If you’d like to follow along, start off by grabbing the code in the trunk of the android-touchexample project on Google Code.

    The problem manifests

    The uses-sdk tag in your AndroidManifest.xml can specify both a minSdkVersion and a targetSdkVersion. You can use this to declare that while your app is prepared to run on an older version of the platform, it knows about newer versions. Your app can now build against newer SDKs. However, if your code accesses newer platform functionality directly you will probably see something like this in the system log of devices running an older version of Android:

    E/dalvikvm( 792): Could not find method android.view.MotionEvent.getX, referenced from method com.example.android.touchexample.TouchExampleView.onTouchEvent
    W/dalvikvm( 792): VFY: unable to resolve virtual method 17: Landroid/view/MotionEvent;.getX (I)F
    W/dalvikvm( 792): VFY: rejecting opcode 0x6e at 0x0006
    W/dalvikvm( 792): VFY: rejected Lcom/example/android/touchexample/TouchExampleView;.onTouchEvent (Landroid/view/MotionEvent;)Z
    W/dalvikvm( 792): Verifier rejected class Lcom/example/android/touchexample/TouchExampleView;
    D/AndroidRuntime( 792): Shutting down VM
    W/dalvikvm( 792): threadid=3: thread exiting with uncaught exception (group=0x4000fe70)

    We broke the contract of minSdkVersion, and here is the result. When we build our app against SDK 8 (Froyo) but declare minSdkVersion="3" (Cupcake) we promise the system that we know what we’re doing and we won’t try to access anything that doesn’t exist. If we mess this up, we see the above, and our users see an ugly error message.

    Cue a lot of frustrated users and one-star ratings on Market. We need a safe way of accessing newer platform functionality without making the verifier angry on older platform versions.

    Stop and reflect

    Many Android developers are already familiar with the practice of accomplishing this through reflection. Reflection lets your code interface with the runtime, detect when certain methods or classes are present, and invoke or instantiate them without touching them directly.

    The prospect of querying each platform feature individually and conditionally invoking it using reflection isn’t pretty. It’s ugly. It’s slow. It’s cumbersome. Most of all, heavy use can turn your app’s codebase into an unmaintainable mess. What if I said there is a way to write Android apps that target Android 1.5 (Cupcake) through 2.2 (Froyo) and beyond with a single codebase and no reflection at all?

    Lazy Loading

    Computer science researcher Bill Pugh published and popularized a method of writing singletons in Java that takes advantage of the laziness of ClassLoaders. Wikipedia explains his solution further. The code looks like this:

    public class Singleton { // Private constructor prevents instantiation from other classes private Singleton() {} /** * SingletonHolder is loaded on the first execution of Singleton.getInstance() * or the first access to SingletonHolder.INSTANCE, not before. */ private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; }

    There is a very important guaranteed behavior at work here explained by the comment above SingletonHolder. Java classes are loaded and initialized on first access - instantiating the class or accessing one of its static fields or methods for the first time. This is relevant to us because classes are verified by the VM when they are loaded, not before. We now have everything we need to write Android apps that span versions without reflection.

    Designing for compatibility

    As it turns out this is fairly simple to apply. You generally will want your app to degrade gracefully on older platform versions, dropping features or providing alternate functionality when the platform support isn’t available. Since Android platform features are tied to the API level you have only one axis to consider when designing for compatibility.

    In most cases this version support can be expressed as a simple class hierarchy. You can design your app to access version-sensitive functionality through a version-independent interface or abstract class. Subclasses of that interface intended to run on newer platform versions will support newer platform features, and subclasses intended for older versions might need to present alternate ways for your users to access app functionality.

    Your app can use a factory method, abstract factory, or other object creation pattern to instantiate the proper subclass at runtime based on the information exposed by android.os.Build.VERSION. This last step insures that the system will never attempt to load a class it can’t verify, preserving compatibility.

    The principle in practice

    At the beginning of this post I said that we are going to refactor the touch example app from Making Sense of Multitouch to be compatible from API level 3 (Cupcake) on through API level 8 (Froyo). In that post I pointed out that GestureDetectors can be a useful pattern for abstracting the processing of touch events. At the time I didn’t realize how soon that statement would be put to the test. We can refactor the version-specific elements of the demo app’s touch handling into an abstract GestureDetector.

    Before we begin the real work, we need to change our manifest to declare that we support API level 3 devices with minSdkVersion in the uses-sdk tag. Keep in mind that we’re still targeting SDK 8, both with targetSdkVersion in our manifest and in our project configuration. Our manifest now looks like this:

    Our TouchExampleView class isn’t compatible with Android versions prior to Froyo thanks to its use of ScaleGestureDetector, and it isn’t compatible with versions prior to Eclair thanks to its use of the newer MotionEvent methods that return multitouch data. We need to abstract that functionality out into classes that will not be loaded on versions of the platform that don’t support it. To do this, we will create the abstract class VersionedGestureDetector.

    The example app allows the user to perform two gestures, drag and scale. VersionedGestureDetector will therefore publish two events to an attached listener, onDrag and onScale. TouchExampleView will obtain a VersionedGestureDetector instance appropriate to the platform version, filter incoming touch events through it, and respond to the resulting onDrag and onScale events accordingly.

    The first pass of VersionedGestureDetector looks like this:

    public abstract class VersionedGestureDetector { OnGestureListener mListener; public abstract boolean onTouchEvent(MotionEvent ev); public interface OnGestureListener { public void onDrag(float dx, float dy); public void onScale(float scaleFactor); }

    We’ll start with the simplest functionality first, the VersionedGestureDetector for Cupcake. For simplicity’s sake in this example we will implement each version as a private static inner class of VersionedGestureDetector. You can organize this however you please, of course, as long as you use the lazy loading technique shown above or some equivalent. Don’t touch any class that directly accesses functionality not supported by your platform version.

    private static class CupcakeDetector extends VersionedGestureDetector { float mLastTouchX; float mLastTouchY; @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: { mLastTouchX = ev.getX(); mLastTouchY = ev.getY(); break; } case MotionEvent.ACTION_MOVE: { final float x = ev.getX(); final float y = ev.getY(); mListener.onDrag(x - mLastTouchX, y - mLastTouchY); mLastTouchX = x; mLastTouchY = y; break; } } return true; }

    This simple implementation dispatches onDrag events whenever a pointer is dragged across the touchscreen. The values it passes are the X and Y distances traveled by the pointer.

    In Eclair and later we will need to properly track pointer IDs during drags so that our draggable object doesn’t jump around as extra pointers enter and leave the touchscreen. The base implementation of onTouchEvent in CupcakeDetector can handle drag events for us with a few tweaks. We’ll add the methods getActiveX and getActiveY to fetch the appropriate touch coordinates and override them in EclairDetector to get the coordinates from the correct pointer:

    private static class CupcakeDetector extends VersionedGestureDetector { float mLastTouchX; float mLastTouchY; float getActiveX(MotionEvent ev) { return ev.getX(); } float getActiveY(MotionEvent ev) { return ev.getY(); } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: { mLastTouchX = getActiveX(ev); mLastTouchY = getActiveY(ev); break; } case MotionEvent.ACTION_MOVE: { final float x = getActiveX(ev); final float y = getActiveY(ev); mListener.onDrag(x - mLastTouchX, y - mLastTouchY); mLastTouchX = x; mLastTouchY = y; break; } } return true; }

    And now EclairDetector, overriding the new getActiveX and getActiveY methods. Most of this code should be familiar from the original touch example:

    private static class EclairDetector extends CupcakeDetector { private static final int INVALID_POINTER_ID = -1; private int mActivePointerId = INVALID_POINTER_ID; private int mActivePointerIndex = 0; @Override float getActiveX(MotionEvent ev) { return ev.getX(mActivePointerIndex); } @Override float getActiveY(MotionEvent ev) { return ev.getY(mActivePointerIndex); } @Override public boolean onTouchEvent(MotionEvent ev) { final int action = ev.getAction(); switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: mActivePointerId = ev.getPointerId(0); break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: mActivePointerId = INVALID_POINTER_ID; break; case MotionEvent.ACTION_POINTER_UP: final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; final int pointerId = ev.getPointerId(pointerIndex); if (pointerId == mActivePointerId) { // This was our active pointer going up. Choose a new // active pointer and adjust accordingly. final int newPointerIndex = pointerIndex == 0 ? 1 : 0; mActivePointerId = ev.getPointerId(newPointerIndex); mLastTouchX = ev.getX(newPointerIndex); mLastTouchY = ev.getY(newPointerIndex); } break; } mActivePointerIndex = ev.findPointerIndex(mActivePointerId); return super.onTouchEvent(ev); }

    EclairDetector calls super.onTouchEvent after determining the active pointer index and lets CupcakeDetector take care of dispatching the drag event. Supporting multiple platform versions doesn’t have to mean code duplication.

    Finally, let’s add scale gesture support for Froyo devices that have ScaleGestureDetector. We’ll need a couple more changes to CupcakeDetector first; we don’t want to drag normally while scaling. Some devices have touchscreens that don’t deal well with it, and we would want to handle it differently on devices that do anyway. We’ll add a shouldDrag method to CupcakeDetector that we’ll check before dispatching onDrag events.

    The final CupcakeDetector:

    private static class CupcakeDetector extends VersionedGestureDetector { float mLastTouchX; float mLastTouchY; float getActiveX(MotionEvent ev) { return ev.getX(); } float getActiveY(MotionEvent ev) { return ev.getY(); } boolean shouldDrag() { return true; } @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: { mLastTouchX = getActiveX(ev); mLastTouchY = getActiveY(ev); break; } case MotionEvent.ACTION_MOVE: { final float x = getActiveX(ev); final float y = getActiveY(ev); if (shouldDrag()) { mListener.onDrag(x - mLastTouchX, y - mLastTouchY); } mLastTouchX = x; mLastTouchY = y; break; } } return true; }

    EclairDetector remains unchanged. FroyoDetector is below. shouldDrag will return true as long as we do not have a scale gesture in progress:

    private static class FroyoDetector extends EclairDetector { private ScaleGestureDetector mDetector; public FroyoDetector(Context context) { mDetector = new ScaleGestureDetector(context, new ScaleGestureDetector.SimpleOnScaleGestureListener() { @Override public boolean onScale(ScaleGestureDetector detector) { mListener.onScale(detector.getScaleFactor()); return true; } }); } @Override boolean shouldDrag() { return !mDetector.isInProgress(); } @Override public boolean onTouchEvent(MotionEvent ev) { mDetector.onTouchEvent(ev); return super.onTouchEvent(ev); }

    Now that we have our detector implementations in order we need a way to create them. Let’s add a factory method to VersionedGestureDetector:

    public static VersionedGestureDetector newInstance(Context context, OnGestureListener listener) { final int sdkVersion = Integer.parseInt(Build.VERSION.SDK); VersionedGestureDetector detector = null; if (sdkVersion < Build.VERSION_CODES.ECLAIR) { detector = new CupcakeDetector(); } else if (sdkVersion < Build.VERSION_CODES.FROYO) { detector = new EclairDetector(); } else { detector = new FroyoDetector(context); } detector.mListener = listener; return detector;

    Since we’re targeting Cupcake, we don’t have access to Build.VERSION.SDK_INT yet. We have to parse the now-deprecated Build.VERSION.SDK instead. But why is accessing Build.VERSION_CODES.ECLAIR and Build.VERSION_CODES.FROYO safe? As primitive static final int constants, these are inlined by the compiler at build time.

    Our VersionedGestureDetector is ready. Now we just need to hook it up to TouchExampleView, which has become considerably shorter:

    public class TouchExampleView extends View { private Drawable mIcon; private float mPosX; private float mPosY; private VersionedGestureDetector mDetector; private float mScaleFactor = 1.f; public TouchExampleView(Context context) { this(context, null, 0); } public TouchExampleView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public TouchExampleView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mIcon = context.getResources().getDrawable(R.drawable.icon); mIcon.setBounds(0, 0, mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight()); mDetector = VersionedGestureDetector.newInstance(context, new GestureCallback()); } @Override public boolean onTouchEvent(MotionEvent ev) { mDetector.onTouchEvent(ev); return true; } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(); canvas.translate(mPosX, mPosY); canvas.scale(mScaleFactor, mScaleFactor); mIcon.draw(canvas); canvas.restore(); } private class GestureCallback implements VersionedGestureDetector.OnGestureListener { public void onDrag(float dx, float dy) { mPosX += dx; mPosY += dy; invalidate(); } public void onScale(float scaleFactor) { mScaleFactor *= scaleFactor; // Don't let the object get too small or too large. mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f)); invalidate(); } }

    Wrapping up

    We’ve now adapted the touch example app to work from Android 1.5 on through the latest and greatest, taking advantage of newer platform features as available without a single reflective call. The same principles shown here can apply to any new Android feature that you want to use while still allowing your app to run on older platform versions:

    • The ClassLoader loads classes lazily and will only load and verify classes on first access.

    • Factor out app functionality that can differ between platform versions with a version-independent interface or abstract class.

    • Instantiate a version-dependent implementation of it based on the platform version detected at runtime. This keeps the ClassLoader from ever touching a class that it will not be able to verify.

    To see the final cross-version touch example app, check out the “cupcake” branch of the android-touchexample project on Google Code.

    Extra Credit

    In this example we didn’t provide another way for pre-Froyo users to zoom since ScaleGestureDetector was only added as a public API for 2.2. For a real app we would want to offer some alternate affordance to users. Traditionally Android offers a set of small tappable zoom buttons along the bottom of the screen. The ZoomControls and ZoomButtonsController classes in the framework can help you present these controls to the user in a standard way. Implementing this is left as an exercise for the reader.

  • HTML5 features now in Safari too

    July 12, 2010

    We've been posting a bunch recently about new Gmail features built on top of HTML5 and other advancements in browser platforms, but so far you've only be able to drag in attachments and drag images into messages in Chrome and Firefox, and the ability to have new windows outlive your original Gmail window was limited to Chrome. Now, all three of these features work in the newest version of Safari (Safari 5) too.

  • Our highlights from Vidcon

    July 12, 2010

    Wow. Let’s hope vlogbrothers Hank and John Green are somewhere tropical right now, resting up after the coup they just pulled off in Vidcon 2010. The sold-out online video conference took over L.A.’s Hyatt Regency Century Plaza from July 9 -11 in a flurry of cameras, Bieber-inspired hairstyles and coveted subscribe pillows. Feedback on Twitter was unanimously positive: Vidcon rulez!

    We were lucky enough to be among the 1,300+ fanboys and girls who gathered to fete all things video and hear from some of the biggest names in the online

  • Open, Integrated and Giving You Choice: The Story Behind the Google Apps Marketplace

    July 12, 2010

    Gmail, Calendar, Docs, Sites and all Google Apps were designed as cloud-based services from day one. Google’s web-centric approach allows any application to work seamlessly on any device with a browser, allowing users to work when, where, and how they want. No more need for constant upgrades, security patches and bug fixes required by client based software.

    Given the first step to the cloud for many businesses and schools is Gmail, the Google Apps Marketplace aims to make it easier for organizations that have “gone Google” to take the

  • Back-to-School: 46% Plan To Shop For Themselves

    July 12, 2010

    Students are not the only target audience this Back-to-School season: Parents are also using this opportunity to shop for other family members and themselves. In fact, 46% of consumers plan to take advantage of the back-to-school season to purchase items for themselves.

    And what is driving their purchase decisions? Sales, coupons, and free shipping lead the way as the top influences of Back-to-School purchases.

    This Back-to-School season, be sure to target both parents and children, and highlight any promotions through ad text and

  • Sharing the Joy of Creating Android Apps with Everyone

    July 12, 2010

    Sharing the joy of building software with someone that doesn’t have an engineering background is hard. Today it got a little easier with App Inventor for Android.

    App Inventor for Android is a Google Labs project that makes it possible to create complex Android applications without having to write any code. This is because, instead of writing code, you can visually design the way the app looks and use blocks to specify behavior.

    This helps introduce concepts about logic and programming in a compelling way, without getting lost

  • .NET Data API SDK updated

    July 12, 2010

    We are proud to announce a new release of the Google Data API .NET SDK.

    This new release, version 1.6, adds support for the latest Contacts and Documents services, as well as support for Google Analytics. It also sports a very easy to use ResumableUpload component to support those gigantic YouTube Videos that you are dying to upload, as well as other services that support this feature, like Google Documents.

    For a complete list of changes and bugfixes: http://google-gdata.googlecode.com/svn/trunk/clients/cs/RELEASE_NOTES.HTML

    To download

  • A Guide to Getting Started with Google drawings

    July 12, 2010

    Last year we published Getting Started Guides for spreadsheets, documents, and presentations -- because using a product for the first time can sometimes be challenging. People have found these very helpful, so we’ve created a Getting Started Guide for drawings.

    This guide covers the basics about Google drawings and gives you all the information you need to start creating, editing, formatting, and sharing your drawings. It also includes some tips and tricks about features you may not know too much about. If you already use Google presentations

No comments: