Search code examples
androidgesture-recognitiongestureslive-wallpapergesturedetector

Gesture detection in an Android Live Wallpaper


I have a Live Wallpaper which I'd like to add gestures to but I can't seem to find where to actually add the listener. What is considered the 'view' in a live wallpaper which i can add setOnGestureListener() to please?

here is the code for my engine

class HexClockEngine extends Engine
{
    private static final int SWIPE_MIN_DISTANCE = 120;
    private static final int SWIPE_MAX_OFF_PATH = 250;
    private static final int SWIPE_THRESHOLD_VELOCITY = 200;
    private static final float LINE_WIDTH = 275f;
    private static final float TEXT_SIZE_DP = 70f;
    private static final String TAG = "WallpaperEngine";

    private final   Handler     _handler        = new Handler();
    private final   Paint       _borderPaint    = new Paint();
    private final   Paint       _shadowPaint    = new Paint();
    private final   Paint       _textPaint      = new Paint();
    private final   Runnable    _draw       = new Runnable() {
                                public void run()
                                {
                                    drawFrame();
                                }
                            };
    class HexGestureListener extends SimpleOnGestureListener
    {
        @Override 
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) 
        {
            Log.i("fling", TAG);

            try
            {
                if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                    return false;

                if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY)
                {
                    Log.i(TAG, "swipe left");
                    return true;
                }
                else if (e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY)
                {
                    Log.i(TAG, "swipe right");
                    return true;
                }
            }
            catch (Exception e)
            {
                Log.e(TAG, e.toString());
            }

            return false;
        }

        @Override
        public boolean onDown(MotionEvent e) 
        {
            Log.i(TAG, "onDown");
            return true;
        }
    }
    private GestureDetector         _gestureDetector;
    private View.OnTouchListener    _gestureListener;

    private         Rect            _border;
    private         Rect            _screenBounds;
    private         boolean         _isVisible;
    private final   float           _scale;


    HexClockEngine()
    {
        DisplayMetrics metrics = new DisplayMetrics();
        Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
        display.getMetrics(metrics);

        // initialise drawables
        _scale = metrics.density;

        Log.i(TAG, "adding gestures");
        _gestureDetector = new GestureDetector(new HexGestureListener());
        _gestureListener = new View.OnTouchListener()
        {
            public boolean onTouch(View v, MotionEvent e)
            {
                if (_gestureDetector.onTouchEvent(e)) return true;
                else return false;
            }
        };

    }

    @Override
    public void onCreate(SurfaceHolder surfaceHolder)
    {
        super.onCreate(surfaceHolder);
        surfaceHolder.setFormat(android.graphics.PixelFormat.RGBA_8888);
        setTouchEventsEnabled(true);
    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();
        _handler.removeCallbacks(_draw);
    }

    @Override
    public void onVisibilityChanged(boolean visible)
    {
        _isVisible = visible;

        if (_isVisible)
        {
            drawFrame();
        }
        else
        {
            _handler.removeCallbacks(_draw);
        }
    }

    @Override
    public void onSurfaceChanged(SurfaceHolder holder, int format,
            int width, int height)
    {
        super.onSurfaceChanged(holder, format, width, height);

        drawFrame();
    }

    @Override
    public void onSurfaceCreated(SurfaceHolder holder)
    {
        super.onSurfaceCreated(holder);
    }

    @Override
    public void onSurfaceDestroyed(SurfaceHolder holder)
    {
        super.onSurfaceDestroyed(holder);
        _isVisible = false;
        _handler.removeCallbacks(_draw);
    }

    @Override
    public void onOffsetsChanged(float xOffset, float yOffset, float xStep,
            float yStep, int xPixels, int yPixels)
    {

        drawFrame();
    }


    void drawFrame()
    {
        final SurfaceHolder holder = getSurfaceHolder();

        Canvas c = null;
        try
        {
            c = holder.lockCanvas();

            if (c != null)
            {
                // draw something
            }
        }
            finally
        {
            if (c != null)
                holder.unlockCanvasAndPost(c);
        }

        _handler.removeCallbacks(_draw);

        if (_isVisible)
        {
            _handler.postDelayed(_draw, 1000);
        }
    }
}

Thanks in advance

obie


Solution

  • Live wallpaper works somewhat differently from normal Android stuff. You don't get a view. All you get is a canvas, and you have to structure things differently...essentially you are coordinating with the launcher. The Cube example in the SDK is a good point of departure: it enables touch events in onCreate, and then overrides the onTouchEvent method. Bear in mind that any gestures you get this way will also be processed by the launcher. If all you need is simple screen taps, it is better practice to use onCommand and check for android.wallpaper.tap as described here.