teaching machines

CS 491 Lecture 19 – Smile and Wave

November 10, 2011 by . Filed under cs491 mobile, fall 2011, lectures.

Agenda

Mixing widgets and SurfaceView

An unfortunate consequence of switching to a SurfaceView is that our gestures no longer get recognized. GestureOverlayView and SurfaceView do not play well together. No documentation I can find details their incompatibility, but gesture recognition simply doesn’t happen.

The good news is that there’s another layout out that supports stacked views. We can stack a GestureOverlayView on top of SurfaceView using a FrameLayout:

<FrameLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <edu.uwec.cs491.RatorVadersSurfaceView
    android:id="@+id/world"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" />
  <android.gesture.GestureOverlayView
    android:id="@+id/gesture_plate"
    android:gestureStrokeType="multiple"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
  </android.gesture.GestureOverlayView>
</FrameLayout>

The last added view is the “top” one — the one which will get first dibs on touch events. In this case, the gesture overlay will snarf them all up for itself.

Writing a custom camera app

We saw how we could issue an intent for taking a picture with the camera. Now let’s take the picture ourselves.

  1. Write a SurfaceView subclass. Have it implement SurfaceHolder.Callback.
  2. In its constructor, register it as the SurfaceHolder event listener.
  3. We still must not touch the surface except between surfaceCreated and surfaceDestroyed. In surfaceCreated, then, let’s connect to the camera with Camera.open.
  4. surfaceChanged is called right after surfaceCreated. Here let’s tell the camera to start showing its preview here.
    try {
      camera.setPreviewDisplay(getHolder());
      camera.startPreview();
    } catch (IOException e) {
      Log.d("WAVE", e.toString());
    }
  5. In surfaceDestroyed, we stop the preview and release the camera. If we do not, we will own the camera even when our app is not active. That’s unfriendly to other apps.

Camera.open() connects to a back-facing camera. A lot of devices have front-facing cameras as well. Camera.open(1) grabs the front-facing camera on my Transformer.

The preview resolution can be adjusted. Arbitrary resolutions may not be handled, but the camera advertises the resolutions it definitely supports. In this example, we set the resolution to the last size in the advertised list:

Camera.Parameters settings = camera.getParameters();
List sizes = settings.getSupportedPreviewSizes();
Camera.Size size = sizes.get(sizes.size() - 1);
settings.setPreviewSize(size.width, size.height);
camera.setParameters(settings);

The order of supported resolutions in the returned list is not defined. On my Transformer the highest resolution is last.

Taking a picture can be done by calling takePicture on the camera object. We’ll need to supply at least three handlers for a) handling a shutter event (playing a sound), b) handling raw camera data (null is fine), and c) handling the compressed JPEG data buffer. We’re not going to worry about taking pictures today.

Enhancing the preview

TODO