| /* |
| * 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(); |
| } |
| |
| } |