
- •Contents
- •Acknowledgments
- •Preface
- •What Makes Android Special?
- •Who Should Read This Book?
- •Online Resources
- •Fast-Forward >>
- •Introducing Android
- •Quick Start
- •Installing the Tools
- •Creating Your First Program
- •Running on the Emulator
- •Running on a Real Phone
- •Key Concepts
- •The Big Picture
- •Building Blocks
- •Using Resources
- •Safe and Secure
- •Android Basics
- •Designing the User Interface
- •Introducing the Sudoku Example
- •Designing by Declaration
- •Creating the Opening Screen
- •Using Alternate Resources
- •Implementing an About Box
- •Applying a Theme
- •Adding a Menu
- •Adding Settings
- •Starting a New Game
- •Debugging
- •Exiting the Game
- •Exploring 2D Graphics
- •Learning the Basics
- •Adding Graphics to Sudoku
- •Handling Input
- •The Rest of the Story
- •Making More Improvements
- •Multimedia
- •Playing Audio
- •Playing Video
- •Adding Sounds to Sudoku
- •Storing Local Data
- •Adding Options to Sudoku
- •Continuing an Old Game
- •Remembering the Current Position
- •Accessing the Internal File System
- •Accessing SD Cards
- •Beyond the Basics
- •The Connected World
- •Browsing by Intent
- •Web with a View
- •From JavaScript to Java and Back
- •Using Web Services
- •Locating and Sensing
- •Location, Location, Location
- •Set Sensors to Maximum
- •Putting SQL to Work
- •Introducing SQLite
- •Hello, Database
- •Data Binding
- •Using a ContentProvider
- •Implementing a ContentProvider
- •3D Graphics in OpenGL
- •Understanding 3D Graphics
- •Introducing OpenGL
- •Building an OpenGL Program
- •Rendering the Scene
- •Building a Model
- •Lights, Camera, ...
- •Action!
- •Applying Texture
- •Peekaboo
- •Measuring Smoothness
- •Fast-Forward >>
- •The Next Generation
- •Multi-Touch
- •Building the Touch Example
- •Understanding Touch Events
- •Setting Up for Image Transformation
- •Implementing the Drag Gesture
- •Implementing the Pinch Zoom Gesture
- •Hello, Widget
- •Live Wallpaper
- •Write Once, Test Everywhere
- •Gentlemen, Start Your Emulators
- •Building for Multiple Versions
- •Evolving with Android APIs
- •Bug on Parade
- •All Screens Great and Small
- •Installing on the SD Card
- •Publishing to the Android Market
- •Preparing
- •Signing
- •Publishing
- •Updating
- •Closing Thoughts
- •Appendixes
- •Bibliography
- •Index

IMPLEMENTING THE DRAG GESTURE 229
// Remember some things for zooming PointF start = new PointF();
PointF mid = new PointF(); float oldDist = 1f;
@Override
public boolean onTouch(View v, MotionEvent event) { ImageView view = (ImageView) v;
//Dump touch event to log dumpEvent(event);
//Handle touch events here...
switch (event.getAction() & MotionEvent.ACTION_MASK) {
}
view.setImageMatrix(matrix);
return true; // indicate event was handled
}
}
The matrix variable will be calculated inside the switch statement when we implement the gestures.
11.5Implementing the Drag Gesture
A drag gesture starts when the first finger is pressed to the screen (ACTION_DOWN) and ends when it is removed (ACTION_UP or ACTION_ POINTER_UP).
Download Touchv1/src/org/example/touch/Touch.java
switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix); start.set(event.getX(), event.getY()); Log.d(TAG, "mode=DRAG");
mode = DRAG; break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: mode = NONE;
Log.d(TAG, "mode=NONE"); break;
case MotionEvent.ACTION_MOVE: if (mode == DRAG) {
matrix.set(savedMatrix); matrix.postTranslate(event.getX() - start.x,
event.getY() - start.y);
}
break;
}

IMPLEMENTING THE PINCH ZOOM GESTURE 230
When the gesture starts, we remember the current value of the transformation matrix and the starting position of the pointer. Every time the finger moves, we start the transformation matrix over at its original value and call the postTranslate( ) method to add a translation vector, the difference between the current and starting positions.
If you run the program now, you should be able to drag the image around the screen using your finger. Neat, huh?
11.6Implementing the Pinch Zoom Gesture
The pinch zoom gesture is similar, except it starts when the second finger is pressed to the screen (ACTION_POINTER_DOWN).
Download Touchv1/src/org/example/touch/Touch.java
case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); Log.d(TAG, "oldDist=" + oldDist); if (oldDist > 10f) {
savedMatrix.set(matrix); midPoint(mid, event); mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
break;
case MotionEvent.ACTION_MOVE: if (mode == DRAG) {
// ...
}
else if (mode == ZOOM) {
float newDist = spacing(event); Log.d(TAG, "newDist=" + newDist); if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist; matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
When we get the down event for the second finger, we calculate and remember the distance between the two fingers. In my testing, Android would sometimes tell me (incorrectly) that there were two fingers pressed down in almost exactly the same position. So, I added an check to ignore the event if the distance is smaller than some arbitrary number of pixels. If it’s bigger than that, we remember the current transformation matrix, calculate the midpoint of the two fingers, and start the zoom.

IMPLEMENTING THE PINCH ZOOM GESTURE 231
When a move event arrives while we’re in zoom mode, we calculate the distance between the fingers again. If it’s too small, the event is ignored; otherwise, we restore the transformation matrix and scale the image around the midpoint.
The scale is simply the ratio of the new distance divided by the old distance. If the new distance is bigger (that is, the fingers have gotten farther apart), then the scale will be greater than 1, making the image bigger. If it’s smaller (fingers closer together), then the scale will be less than one, making the image smaller. And of course if everything is the same, the scale is equal to 1 and the image is not changed.
Now let’s define the spacing( ) and midPoint( ) methods.
Distance Between Two Points
To find out how far apart two fingers are, we first construct a vector (x, y) that is the difference between the two points. Then we use the formula for Euclidean distance to calculate the spacing:4
Download Touchv1/src/org/example/touch/Touch.java
private float spacing(MotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return FloatMath.sqrt(x * x + y * y);
}
The order of the points does not matter because any negative signs will be lost when we square them. Note that all math is done using Java’s float type. Although some Android devices may not have floatingpoint hardware, we’re not doing this often enough to worry about its performance.
Midpoint of Two Points
Calculating a point in the middle of two points is even easier:
Download Touchv1/src/org/example/touch/Touch.java
private void midPoint(PointF point, MotionEvent event) { float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1); point.set(x / 2, y / 2);
}
4. http://en.wikipedia.org/wiki/Euclidean_distance

FAST -FORWARD >> 232
All we do is take the average of their X and Y coordinates. To avoid garbage collections that can cause noticeable pauses in the application, we reuse an existing object to store the result rather than allocating and returning a new one each time.
Try running the program now on your phone. Drag the image with one finger, and zoom it by pinching two fingers in or out. For best results, don’t let your fingers get closer than an inch or so apart. Otherwise, you’ll start to run into some of those bugs in the API I mentioned earlier.
11.7Fast-Forward >>
In this chapter, we learned how to use the multi-touch API to create a pinch zoom gesture. There’s a nice site called GestureWorks5 that describes a whole library of gestures that have been implemented on the Adobe Flash platform. If you’re willing to push the limits of Android’s quirky multi-touch support, then perhaps you can find ideas there for other gestures to implement in your Android programs.
Because multi-touch code uses new methods that didn’t exist before Android 2.0, if you try to run the touch example on earlier versions, it will fail with a “Force close” error. Luckily, there are ways around this limitation, as described in Section 13.3, Evolving with Android APIs, on page 259. You can’t teach an old phone new tricks, but you can at least keep it from crashing.
In the next chapter, we’ll investigate home screen extensions, including live wallpaper.
5. http://gestureworks.com