public static interface

Slideshow.DataSource

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.cooliris.wallpaper;

//import android.app.Service;
import com.cooliris.media.Vector3f;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.os.SystemClock;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.graphics.PorterDuff.Mode;

public class Slideshow extends SurfaceView implements SurfaceHolder.Callback {
    public Slideshow(Context context) {
        super(context);
        SurfaceHolder holder = getHolder();
        holder.addCallback(this);
    }

    public static final int SLIDESHOW_DURATION = 2000;

    public interface DataSource {
        /**
         * 
         * @param currentSlideshowCounter
         * @return
         */
        Bitmap getBitmapForIndex(Context context, int currentSlideshowCounter);
    }

    private final Handler mHandler = new Handler();
    private final Runnable mDrawFrame = new Runnable() {
        public void run() {
            drawFrame();
        }
    };
    private static final Paint sPaint = new Paint();
    static {
        sPaint.setFilterBitmap(true);
        sPaint.setDither(true);
    }
    private boolean mVisible = true;
    private DataSource mSource;
    private int mCurrentSlideshowCounter;
    private Bitmap mBitmap;
    private Rect mRect;
    private RectF mFrameRect;
    private static final Vector3f sGrow = new Vector3f();
    private Bitmap mQueuedBitmap;
    private Rect mQueuedRect;
    private RectF mQueuedFrameRect;
    private static final Vector3f sQueuedGrow = new Vector3f();

    private long mPrevTime;
    private long mTimeElapsed;

    public void setDataSource(DataSource source) {
        mSource = source;
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        mHandler.post(mDrawFrame);
        if (mBitmap != null) {
            mRect = getRectToFitBitmap(mBitmap.getWidth(), mBitmap.getHeight(), width, height);
            mFrameRect.right = width;
            mFrameRect.bottom = height;
        }
        if (mQueuedBitmap != null) {
            mQueuedRect = getRectToFitBitmap(mQueuedBitmap.getWidth(), mQueuedBitmap.getHeight(), width, height);
            mQueuedFrameRect.right = width;
            mQueuedFrameRect.bottom = height;
        }
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // We may need to make calls to super once this is a subclass of
        // WallpaperService.
        mHandler.post(mDrawFrame);
    }

    public void surfaceDestroyed(SurfaceHolder holder) {

    }

    public void drawFrame() {
        final SurfaceHolder holder = getHolder();
        Rect frame = holder.getSurfaceFrame();
        final Paint paint = sPaint;
        Canvas c = null;
        try {
            c = holder.lockCanvas();
            if (c != null) {
                long now = SystemClock.uptimeMillis();
                long delta = now - mPrevTime;
                if (delta > 50)
                    delta = 50;
                mTimeElapsed += delta;
                mPrevTime = now;
                performSetup(frame.width(), frame.height());
                // We draw the source bitmap
                if (mBitmap != null) {
                    if (mTimeElapsed > SLIDESHOW_DURATION) {
                        float alpha = ((float) (mTimeElapsed - SLIDESHOW_DURATION)) / 2000.0f;
                        paint.setColorFilter(null);
                        if (alpha < 1.0f) {
                            // int val = (int)(255 * (1.0f - alpha));
                            // int srcColor = Color.argb(val, 0, 0, 0);
                            // PorterDuffColorFilter colorFilter = new
                            // PorterDuffColorFilter(srcColor, Mode.SRC_IN);
                            // paint.setColorFilter(null);
                        }
                        c.drawBitmap(mBitmap, mRect, mFrameRect, paint);
                        if (alpha < 1.0f) {
                            int val = (int) (255 * alpha);
                            int srcColor = Color.argb(val, 0, 0, 0);
                            PorterDuffColorFilter colorFilter = new PorterDuffColorFilter(srcColor, Mode.DST_IN);
                            paint.setColorFilter(colorFilter);
                        }

                        c.drawBitmap(mQueuedBitmap, mQueuedRect, mQueuedFrameRect, paint);
                        performUpdate(mQueuedFrameRect, sQueuedGrow, delta);
                        if (alpha >= 1.0f) {
                            // We switch the image.
                            mRect = mQueuedRect;
                            mBitmap = mQueuedBitmap;
                            mFrameRect = mQueuedFrameRect;
                            sGrow.set(sQueuedGrow);
                            mQueuedBitmap = null;
                            mQueuedRect = null;
                            mQueuedFrameRect = null;
                            mTimeElapsed = 0;
                        }
                    } else {
                        paint.setColorFilter(null);
                        c.drawBitmap(mBitmap, mRect, mFrameRect, paint);
                    }
                    performUpdate(mFrameRect, sGrow, delta);
                }

            }
        } finally {
            if (c != null)
                holder.unlockCanvasAndPost(c);
        }
        mHandler.removeCallbacks(mDrawFrame);
        if (mVisible) {
            mHandler.postDelayed(mDrawFrame, 20);
        }
    }

    private void performUpdate(RectF rect, Vector3f grow, long delta) {
        float timeElapsed = ((float) (delta)) / 1000.0f;
        float amountToGrowX = timeElapsed * (rect.width() / 15.0f);
        float amountToGrowY = amountToGrowX * (rect.height() / rect.width());
        rect.top -= amountToGrowY * grow.x;
        rect.left -= amountToGrowX * grow.y;

        rect.bottom += amountToGrowY * (1 - grow.x);
        rect.right += amountToGrowX * (1 - grow.y);
    }

    private void performSetup(int viewWidth, int viewHeight) {
        if (mBitmap == null) {
            mBitmap = getRandomBitmap();
            if (mBitmap != null) {
                mRect = getRectToFitBitmap(mBitmap.getWidth(), mBitmap.getHeight(), viewWidth, viewHeight);
                mFrameRect = new RectF();
                mFrameRect.right = viewWidth;
                mFrameRect.bottom = viewHeight;
                sGrow.set((float) Math.random(), (float) Math.random(), 0);
            }
        }
        if (mQueuedBitmap == null) {
            mQueuedBitmap = getRandomBitmap();
            if (mQueuedBitmap == null) {
                mQueuedBitmap = mBitmap;
            }
            if (mQueuedBitmap != null) {
                mQueuedRect = getRectToFitBitmap(mQueuedBitmap.getWidth(), mQueuedBitmap.getHeight(), viewWidth, viewHeight);
                mQueuedFrameRect = new RectF();
                mQueuedFrameRect.right = viewWidth;
                mQueuedFrameRect.bottom = viewHeight;
                sQueuedGrow.set((float) Math.random(), (float) Math.random(), 0);
            }
        }
    }

    private Rect getRectToFitBitmap(int bitmapWidth, int bitmapHeight, int viewWidth, int viewHeight) {
        Rect rect = new Rect();
        float viewAspect = (float) viewHeight / viewWidth;
        float newWidth = bitmapWidth * viewAspect;
        if (bitmapHeight < newWidth) {
            // Vertically constrained.
            newWidth = bitmapHeight / viewAspect;
            rect.set((int) (bitmapWidth / 2 - newWidth / 2), 0, (int) (bitmapWidth / 2 + newWidth / 2), bitmapHeight);
        } else {
            // Horizontally constrained
            float newHeight = bitmapWidth * viewAspect;
            rect.set(0, (int) (bitmapHeight / 2 - newHeight / 2), bitmapWidth, (int) (bitmapHeight / 2 + newHeight / 2));
        }
        return rect;
    }

    private Bitmap getRandomBitmap() {
        if (mSource != null) {
            return mSource.getBitmapForIndex(getContext(), mCurrentSlideshowCounter++);
        }
        return null;
    }

    public void onVisibilityChanged(boolean visible) {
        mVisible = visible;
        if (!visible) {
            mHandler.removeCallbacks(mDrawFrame);
        }
        drawFrame();
    }

}