diff options
author | Andrzej J.R. Hunt <andrzej@ahunt.org> | 2012-07-24 11:46:48 +0200 |
---|---|---|
committer | Michael Meeks <michael.meeks@suse.com> | 2012-08-06 10:23:00 +0100 |
commit | fa189184fd1f139986aab32531ab19f03223d312 (patch) | |
tree | 1f985d62c60cdb76f38caf2acd9600d66f2ae964 /android | |
parent | 612a2064986643ba69de4b59d2baab9068987ba3 (diff) |
Added cover flow.
Change-Id: I7ffc47269a2e0b1fea4ec4dbcf6c03cdc37d4721
Diffstat (limited to 'android')
10 files changed, 867 insertions, 18 deletions
diff --git a/android/sdremote/res/layout/fragment_presentation.xml b/android/sdremote/res/layout/fragment_presentation.xml index 3da7e0997cf6..fb501489cb47 100644 --- a/android/sdremote/res/layout/fragment_presentation.xml +++ b/android/sdremote/res/layout/fragment_presentation.xml @@ -1,16 +1,21 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/presentation_layout" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical" - android:id="@+id/presentation_layout"> + android:orientation="vertical" > - <ImageView - android:id="@+id/imageView1" - android:layout_width="wrap_content" + <pl.polidea.coverflow.CoverFlow + xmlns:coverflow="http://schemas.android.com/apk/res/org.libreoffice.impressremote" + android:id="@+id/presentation_coverflow" + android:layout_width="fill_parent" android:layout_height="wrap_content" - android:contentDescription="TODO" - android:src="@drawable/testimage" /> + android:layout_marginTop="5dip" + coverflow:imageHeight="150dip" + coverflow:imageReflectionRatio="0.2" + coverflow:imageWidth="100dip" + coverflow:reflectionGap="2dip" + coverflow:withReflection="true" /> <ImageView android:id="@+id/presentation_handle" @@ -25,12 +30,12 @@ android:src="@drawable/handle" /> <ScrollView - android:id="@+id/scrollView1" + android:id="@+id/presentation_scrollview" android:layout_width="match_parent" android:layout_height="wrap_content" > <WebView - android:id="@+id/textView1" + android:id="@+id/presentation_notes" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </ScrollView> diff --git a/android/sdremote/res/values/attrs.xml b/android/sdremote/res/values/attrs.xml new file mode 100644 index 000000000000..43de3bc8e95f --- /dev/null +++ b/android/sdremote/res/values/attrs.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <declare-styleable name="CoverFlow"> + <attr name="imageWidth" format="dimension" /> + <attr name="imageHeight" format="dimension" /> + <attr name="withReflection" format="boolean" /> + <attr name="reflectionGap" format="dimension" /> + <attr name="imageReflectionRatio" format="float" /> + </declare-styleable> +</resources>
\ No newline at end of file diff --git a/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java b/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java index e06d2b5a3e1b..88066101a588 100644 --- a/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java +++ b/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java @@ -69,8 +69,10 @@ public class PresentationActivity extends Activity { mCommunicationService = ((CommunicationService.CBinder) aService) .getService(); mCommunicationService.setActivityMessenger(mMessenger); + + mPresentationFragment + .setCommunicationService(mCommunicationService); mThumbnailFragment.setCommunicationService(mCommunicationService); - // TODO: add mCommunicationSercie to all fragments. } @@ -85,6 +87,7 @@ public class PresentationActivity extends Activity { protected class MessageHandler extends Handler { @Override public void handleMessage(Message aMessage) { + mPresentationFragment.handleMessage(aMessage); mThumbnailFragment.handleMessage(aMessage); // Bundle aData = aMessage.getData(); // TODO: pass to fragments diff --git a/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java b/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java index c031986d25ee..28ba8d0fb031 100644 --- a/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java +++ b/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java @@ -1,8 +1,15 @@ package org.libreoffice.impressremote; +import org.libreoffice.impressremote.communication.CommunicationService; +import org.libreoffice.impressremote.communication.SlideShow; + +import pl.polidea.coverflow.AbstractCoverFlowImageAdapter; +import pl.polidea.coverflow.CoverFlow; import android.app.Fragment; import android.content.Context; +import android.graphics.Bitmap; import android.os.Bundle; +import android.os.Message; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; @@ -10,16 +17,20 @@ import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.webkit.WebView; +import android.widget.AdapterView; import android.widget.ImageView; public class PresentationFragment extends Fragment { - private View mTopView; + private CoverFlow mTopView; private ImageView mHandle; private View mLayout; - + private WebView mNotes; private Context mContext; + private CommunicationService mCommunicationService; + private SlideShow mSlideShow; + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mContext = container.getContext(); @@ -27,20 +38,25 @@ public class PresentationFragment extends Fragment { View v = inflater.inflate(R.layout.fragment_presentation, container, false); - WebView mWebView = (WebView) v.findViewById(R.id.textView1); + mNotes = (WebView) v.findViewById(R.id.presentation_notes); String summary = "<html><body>This is just a test<br/><ul><li>And item</li><li>And again</li></ul>More text<br/>Blabla<br/>Blabla<br/>blabla<br/>Blabla</body></html>"; - mWebView.loadData(summary, "text/html", null); + mNotes.loadData(summary, "text/html", null); - mTopView = v.findViewById(R.id.imageView1); + mTopView = (CoverFlow) v.findViewById(R.id.presentation_coverflow); mLayout = v.findViewById(R.id.presentation_layout); mHandle = (ImageView) v.findViewById(R.id.presentation_handle); mHandle.setOnTouchListener(new SizeListener()); + if (mCommunicationService != null && mSlideShow != null) { + mTopView.setAdapter(new ThumbnailAdapter(mContext, mSlideShow)); + } + return v; } + // -------------------------------------------------- RESIZING LISTENER ---- private class SizeListener implements OnTouchListener { @Override @@ -75,4 +91,90 @@ public class PresentationFragment extends Fragment { return true; } } + + // ----------------------------------------------------- CLICK LISTENER ---- + protected class ClickListener implements AdapterView.OnItemClickListener { + public void onItemClick(AdapterView<?> parent, View v, int position, + long id) { + if (mCommunicationService != null) + mCommunicationService.getTransmitter().gotoSlide(position); + } + } + + // ---------------------------------------------------- MESSAGE HANDLER ---- + public void setCommunicationService( + CommunicationService aCommunicationService) { + mCommunicationService = aCommunicationService; + mSlideShow = mCommunicationService.getSlideShow(); + if (mTopView != null) { + mTopView.setAdapter(new ThumbnailAdapter(mContext, mSlideShow)); + } + } + + public void handleMessage(Message aMessage) { + Bundle aData = aMessage.getData(); + switch (aMessage.what) { + case CommunicationService.MSG_SLIDE_CHANGED: + int aSlide = aData.getInt("slide_number"); + mTopView.setSelection(aSlide, true); + break; + case CommunicationService.MSG_SLIDE_PREVIEW: + int aNSlide = aData.getInt("slide_number"); + if (mTopView.getSelectedItemPosition() == aNSlide) { + // mTopView. // TODO: update the current item + } + break; + + } + } + + // ------------------------------------------------- THUMBNAIL ADAPTER ---- + protected class ThumbnailAdapter extends AbstractCoverFlowImageAdapter { + + private Context mContext; + + private SlideShow mSlideShow; + + public ThumbnailAdapter(Context aContext, SlideShow aSlideShow) { + mContext = aContext; + mSlideShow = aSlideShow; + } + + @Override + public int getCount() { + return mSlideShow.getSize(); + } + + // @Override + // public View getView(int position, View convertView, ViewGroup parent) + // { + // LayoutInflater aInflater = (LayoutInflater) mContext + // .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + // View v = aInflater.inflate(R.layout.slide_thumbnail, null); + // + // ImageView aImage = (ImageView) v.findViewById(R.id.sub_thumbnail); + // TextView aText = (TextView) v.findViewById(R.id.sub_number); + // + // // Do the image & number styling + // int aBorderWidth = getResources().getInteger( + // R.integer.thumbnail_border_width); + // aImage.setPadding(aBorderWidth, aBorderWidth, aBorderWidth, + // aBorderWidth); + // + // Bitmap aBitmap = mSlideShow.getImage(position); + // if (aBitmap != null) { + // aImage.setImageBitmap(aBitmap); + // } + // + // aText.setText(String.valueOf(position + 1)); + // + // return v; + // } + + @Override + protected Bitmap createBitmap(int position) { + Bitmap aBitmap = mSlideShow.getImage(position); + return aBitmap; + } + } } diff --git a/android/sdremote/src/org/libreoffice/impressremote/ThumbnailFragment.java b/android/sdremote/src/org/libreoffice/impressremote/ThumbnailFragment.java index b1ed882a4493..de07603a2fec 100644 --- a/android/sdremote/src/org/libreoffice/impressremote/ThumbnailFragment.java +++ b/android/sdremote/src/org/libreoffice/impressremote/ThumbnailFragment.java @@ -101,8 +101,6 @@ public class ThumbnailFragment extends Fragment { } } - // ------------------------------------------------- SERVICE CONNECTION ---- - // ----------------------------------------------------- CLICK LISTENER ---- protected class ClickListener implements AdapterView.OnItemClickListener { public void onItemClick(AdapterView<?> parent, View v, int position, diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/Client.java b/android/sdremote/src/org/libreoffice/impressremote/communication/Client.java index b3209b802972..bb76df9aef6b 100644 --- a/android/sdremote/src/org/libreoffice/impressremote/communication/Client.java +++ b/android/sdremote/src/org/libreoffice/impressremote/communication/Client.java @@ -60,7 +60,6 @@ public abstract class Client { String aTemp; // read until empty line while ((aTemp = aReader.readLine()).length() != 0) { - System.out.println("Read:" + aTemp); aList.add(aTemp); } mReceiver.parseCommand(aList); diff --git a/android/sdremote/src/pl/polidea/coverflow/AbstractCoverFlowImageAdapter.java b/android/sdremote/src/pl/polidea/coverflow/AbstractCoverFlowImageAdapter.java new file mode 100644 index 000000000000..f60975fa156a --- /dev/null +++ b/android/sdremote/src/pl/polidea/coverflow/AbstractCoverFlowImageAdapter.java @@ -0,0 +1,125 @@ +package pl.polidea.coverflow; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Map; + +import android.content.Context; +import android.graphics.Bitmap; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; + +/** + * This class is an adapter that provides base, abstract class for images + * adapter. + * + */ +public abstract class AbstractCoverFlowImageAdapter extends BaseAdapter { + + /** The Constant TAG. */ + private static final String TAG = AbstractCoverFlowImageAdapter.class + .getSimpleName(); + + /** The width. */ + private float width = 0; + + /** The height. */ + private float height = 0; + + /** The bitmap map. */ + private final Map<Integer, WeakReference<Bitmap>> bitmapMap = new HashMap<Integer, WeakReference<Bitmap>>(); + + public AbstractCoverFlowImageAdapter() { + super(); + } + + /** + * Set width for all pictures. + * + * @param width + * picture height + */ + public synchronized void setWidth(final float width) { + this.width = width; + } + + /** + * Set height for all pictures. + * + * @param height + * picture height + */ + public synchronized void setHeight(final float height) { + this.height = height; + } + + @Override + public final Bitmap getItem(final int position) { + final WeakReference<Bitmap> weakBitmapReference = bitmapMap + .get(position); + if (weakBitmapReference != null) { + final Bitmap bitmap = weakBitmapReference.get(); + if (bitmap == null) { + Log.v(TAG, "Empty bitmap reference at position: " + position + + ":" + this); + } else { + Log.v(TAG, "Reusing bitmap item at position: " + position + ":" + + this); + return bitmap; + } + } + Log.v(TAG, "Creating item at position: " + position + ":" + this); + final Bitmap bitmap = createBitmap(position); + bitmapMap.put(position, new WeakReference<Bitmap>(bitmap)); + Log.v(TAG, "Created item at position: " + position + ":" + this); + return bitmap; + } + + /** + * Creates new bitmap for the position specified. + * + * @param position + * position + * @return Bitmap created + */ + protected abstract Bitmap createBitmap(int position); + + /* + * (non-Javadoc) + * + * @see android.widget.Adapter#getItemId(int) + */ + @Override + public final synchronized long getItemId(final int position) { + return position; + } + + /* + * (non-Javadoc) + * + * @see android.widget.Adapter#getView(int, android.view.View, + * android.view.ViewGroup) + */ + @Override + public final synchronized ImageView getView(final int position, + final View convertView, final ViewGroup parent) { + ImageView imageView; + if (convertView == null) { + final Context context = parent.getContext(); + Log.v(TAG, "Creating Image view at position: " + position + ":" + + this); + imageView = new ImageView(context); + imageView.setLayoutParams(new CoverFlow.LayoutParams((int) width, + (int) height)); + } else { + Log.v(TAG, "Reusing view at position: " + position + ":" + this); + imageView = (ImageView) convertView; + } + imageView.setImageBitmap(getItem(position)); + return imageView; + } + +} diff --git a/android/sdremote/src/pl/polidea/coverflow/CoverFlow.java b/android/sdremote/src/pl/polidea/coverflow/CoverFlow.java new file mode 100644 index 000000000000..09da2a09f3f0 --- /dev/null +++ b/android/sdremote/src/pl/polidea/coverflow/CoverFlow.java @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2010 Neil Davies + * + * 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. + * + * This code is base on the Android Gallery widget and was Created + * by Neil Davies neild001 'at' gmail dot com to be a Coverflow widget + * + * @author Neil Davies + */ +package pl.polidea.coverflow; + +import org.libreoffice.impressremote.R; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Camera; +import android.graphics.Matrix; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.Transformation; +import android.widget.Gallery; +import android.widget.ImageView; +import android.widget.SpinnerAdapter; + +/** + * Cover Flow implementation. + * + */ +public class CoverFlow extends Gallery { + + /** + * Graphics Camera used for transforming the matrix of ImageViews. + */ + private final Camera mCamera = new Camera(); + + /** + * The maximum angle the Child ImageView will be rotated by. + */ + private int mMaxRotationAngle = 60; + + /** + * The maximum zoom on the centre Child. + */ + private int mMaxZoom = -120; + + /** + * The Centre of the Coverflow. + */ + private int mCoveflowCenter; + + /** The image height. */ + private float imageHeight; + + /** The image width. */ + private float imageWidth; + + /** The reflection gap. */ + private float reflectionGap; + + /** The with reflection. */ + private boolean withReflection; + + /** The image reflection ratio. */ + private float imageReflectionRatio; + + /** + * Gets the image height. + * + * @return the image height + */ + public float getImageHeight() { + return imageHeight; + } + + /** + * Sets the image height. + * + * @param imageHeight + * the new image height + */ + public void setImageHeight(final float imageHeight) { + this.imageHeight = imageHeight; + } + + /** + * Gets the image width. + * + * @return the image width + */ + public float getImageWidth() { + return imageWidth; + } + + /** + * Sets the image width. + * + * @param imageWidth + * the new image width + */ + public void setImageWidth(final float imageWidth) { + this.imageWidth = imageWidth; + } + + /** + * Gets the reflection gap. + * + * @return the reflection gap + */ + public float getReflectionGap() { + return reflectionGap; + } + + /** + * Sets the reflection gap. + * + * @param reflectionGap + * the new reflection gap + */ + public void setReflectionGap(final float reflectionGap) { + this.reflectionGap = reflectionGap; + } + + /** + * Checks if is with reflection. + * + * @return true, if is with reflection + */ + public boolean isWithReflection() { + return withReflection; + } + + /** + * Sets the with reflection. + * + * @param withReflection + * the new with reflection + */ + public void setWithReflection(final boolean withReflection) { + this.withReflection = withReflection; + } + + /** + * Sets the image reflection ratio. + * + * @param imageReflectionRatio + * the new image reflection ratio + */ + public void setImageReflectionRatio(final float imageReflectionRatio) { + this.imageReflectionRatio = imageReflectionRatio; + } + + /** + * Gets the image reflection ratio. + * + * @return the image reflection ratio + */ + public float getImageReflectionRatio() { + return imageReflectionRatio; + } + + public CoverFlow(final Context context) { + super(context); + this.setStaticTransformationsEnabled(true); + } + + public CoverFlow(final Context context, final AttributeSet attrs) { + this(context, attrs, android.R.attr.galleryStyle); + } + + public CoverFlow(final Context context, final AttributeSet attrs, + final int defStyle) { + super(context, attrs, defStyle); + parseAttributes(context, attrs); + this.setStaticTransformationsEnabled(true); + } + + /** + * Get the max rotational angle of the image. + * + * @return the mMaxRotationAngle + */ + public int getMaxRotationAngle() { + return mMaxRotationAngle; + } + + /** + * Sets the. + * + * @param adapter + * the new adapter + */ + @Override + public void setAdapter(final SpinnerAdapter adapter) { + if (!(adapter instanceof AbstractCoverFlowImageAdapter)) { + throw new IllegalArgumentException( + "The adapter should derive from " + + AbstractCoverFlowImageAdapter.class + .getName()); + } + final AbstractCoverFlowImageAdapter coverAdapter = (AbstractCoverFlowImageAdapter) adapter; + coverAdapter.setWidth(imageWidth); + coverAdapter.setHeight(imageHeight); + if (withReflection) { + final ReflectingImageAdapter reflectAdapter = new ReflectingImageAdapter( + coverAdapter); + reflectAdapter.setReflectionGap(reflectionGap); + reflectAdapter.setWidthRatio(imageReflectionRatio); + reflectAdapter.setWidth(imageWidth); + reflectAdapter.setHeight(imageHeight * (1 + imageReflectionRatio)); + super.setAdapter(reflectAdapter); + } else { + super.setAdapter(adapter); + } + } + + /** + * Set the max rotational angle of each image. + * + * @param maxRotationAngle + * the mMaxRotationAngle to set + */ + public void setMaxRotationAngle(final int maxRotationAngle) { + mMaxRotationAngle = maxRotationAngle; + } + + /** + * Get the Max zoom of the centre image. + * + * @return the mMaxZoom + */ + public int getMaxZoom() { + return mMaxZoom; + } + + /** + * Set the max zoom of the centre image. + * + * @param maxZoom + * the mMaxZoom to set + */ + public void setMaxZoom(final int maxZoom) { + mMaxZoom = maxZoom; + } + + /** + * Get the Centre of the Coverflow. + * + * @return The centre of this Coverflow. + */ + private int getCenterOfCoverflow() { + return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + + getPaddingLeft(); + } + + /** + * Get the Centre of the View. + * + * @return The centre of the given view. + */ + private static int getCenterOfView(final View view) { + return view.getLeft() + view.getWidth() / 2; + } + + /** + * {@inheritDoc} + * + * @see #setStaticTransformationsEnabled(boolean) + */ + @Override + protected boolean getChildStaticTransformation(final View child, + final Transformation t) { + + final int childCenter = getCenterOfView(child); + final int childWidth = child.getWidth(); + int rotationAngle = 0; + + t.clear(); + t.setTransformationType(Transformation.TYPE_MATRIX); + + if (childCenter == mCoveflowCenter) { + transformImageBitmap((ImageView) child, t, 0); + } else { + rotationAngle = (int) ((float) (mCoveflowCenter - childCenter) + / childWidth * mMaxRotationAngle); + if (Math.abs(rotationAngle) > mMaxRotationAngle) { + rotationAngle = rotationAngle < 0 ? -mMaxRotationAngle + : mMaxRotationAngle; + } + transformImageBitmap((ImageView) child, t, rotationAngle); + } + + return true; + } + + /** + * This is called during layout when the size of this view has changed. If + * you were just added to the view hierarchy, you're called with the old + * values of 0. + * + * @param w + * Current width of this view. + * @param h + * Current height of this view. + * @param oldw + * Old width of this view. + * @param oldh + * Old height of this view. + */ + @Override + protected void onSizeChanged(final int w, final int h, final int oldw, + final int oldh) { + mCoveflowCenter = getCenterOfCoverflow(); + super.onSizeChanged(w, h, oldw, oldh); + } + + /** + * Transform the Image Bitmap by the Angle passed. + * + * @param imageView + * ImageView the ImageView whose bitmap we want to rotate + * @param t + * transformation + * @param rotationAngle + * the Angle by which to rotate the Bitmap + */ + private void transformImageBitmap(final ImageView child, + final Transformation t, final int rotationAngle) { + mCamera.save(); + final Matrix imageMatrix = t.getMatrix(); + + final int height = child.getLayoutParams().height; + + final int width = child.getLayoutParams().width; + final int rotation = Math.abs(rotationAngle); + + mCamera.translate(0.0f, 0.0f, 100.0f); + + // As the angle of the view gets less, zoom in + if (rotation < mMaxRotationAngle) { + final float zoomAmount = (float) (mMaxZoom + rotation * 1.5); + mCamera.translate(0.0f, 0.0f, zoomAmount); + } + + mCamera.rotateY(rotationAngle); + mCamera.getMatrix(imageMatrix); + imageMatrix.preTranslate(-(width / 2.0f), -(height / 2.0f)); + imageMatrix.postTranslate((width / 2.0f), (height / 2.0f)); + mCamera.restore(); + } + + /** + * Parses the attributes. + * + * @param context + * the context + * @param attrs + * the attrs + */ + private void parseAttributes(final Context context, final AttributeSet attrs) { + final TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.CoverFlow); + try { + imageWidth = a.getDimension(R.styleable.CoverFlow_imageWidth, 480); + imageHeight = a.getDimension(R.styleable.CoverFlow_imageHeight, 320); + withReflection = a.getBoolean(R.styleable.CoverFlow_withReflection, + false); + imageReflectionRatio = a.getFloat( + R.styleable.CoverFlow_imageReflectionRatio, 0.2f); + reflectionGap = a.getDimension(R.styleable.CoverFlow_reflectionGap, + 4); + setSpacing(-15); + } finally { + a.recycle(); + } + } + +}
\ No newline at end of file diff --git a/android/sdremote/src/pl/polidea/coverflow/ReflectingImageAdapter.java b/android/sdremote/src/pl/polidea/coverflow/ReflectingImageAdapter.java new file mode 100644 index 000000000000..ff044753039f --- /dev/null +++ b/android/sdremote/src/pl/polidea/coverflow/ReflectingImageAdapter.java @@ -0,0 +1,129 @@ +package pl.polidea.coverflow; + +import android.R.color; +import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.Canvas; +import android.graphics.LinearGradient; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PorterDuff.Mode; +import android.graphics.PorterDuffXfermode; +import android.graphics.Shader.TileMode; + +/** + * This adapter provides reflected images from linked adapter. + * + * @author potiuk + * + */ +public class ReflectingImageAdapter extends AbstractCoverFlowImageAdapter { + + /** The linked adapter. */ + private final AbstractCoverFlowImageAdapter linkedAdapter; + /** + * Gap between the image and its reflection. + */ + private float reflectionGap; + + /** The image reflection ratio. */ + private float imageReflectionRatio; + + /** + * Sets the width ratio. + * + * @param imageReflectionRatio + * the new width ratio + */ + public void setWidthRatio(final float imageReflectionRatio) { + this.imageReflectionRatio = imageReflectionRatio; + } + + /** + * Creates reflecting adapter. + * + * @param linkedAdapter + * adapter that provides images to get reflections + */ + public ReflectingImageAdapter( + final AbstractCoverFlowImageAdapter linkedAdapter) { + super(); + this.linkedAdapter = linkedAdapter; + } + + /** + * Sets the reflection gap. + * + * @param reflectionGap + * the new reflection gap + */ + public void setReflectionGap(final float reflectionGap) { + this.reflectionGap = reflectionGap; + } + + /** + * Gets the reflection gap. + * + * @return the reflection gap + */ + public float getReflectionGap() { + return reflectionGap; + } + + /* + * (non-Javadoc) + * + * @see pl.polidea.coverflow.AbstractCoverFlowImageAdapter#createBitmap(int) + */ + @Override + protected Bitmap createBitmap(final int position) { + return createReflectedImages(linkedAdapter.getItem(position)); + } + + /** + * Creates the reflected images. + * + * @param originalImage + * the original image + * @return true, if successful + */ + public Bitmap createReflectedImages(final Bitmap originalImage) { + final int width = originalImage.getWidth(); + final int height = originalImage.getHeight(); + final Matrix matrix = new Matrix(); + matrix.preScale(1, -1); + final Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0, + (int) (height * imageReflectionRatio), width, + (int) (height - height * imageReflectionRatio), matrix, + false); + final Bitmap bitmapWithReflection = Bitmap.createBitmap(width, + (int) (height + height * imageReflectionRatio), + Config.ARGB_8888); + final Canvas canvas = new Canvas(bitmapWithReflection); + canvas.drawBitmap(originalImage, 0, 0, null); + final Paint deafaultPaint = new Paint(); + deafaultPaint.setColor(color.transparent); + canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null); + final Paint paint = new Paint(); + final LinearGradient shader = new LinearGradient(0, + originalImage.getHeight(), 0, + bitmapWithReflection.getHeight() + reflectionGap, + 0x70ffffff, 0x00ffffff, TileMode.CLAMP); + paint.setShader(shader); + paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); + canvas.drawRect(0, height, width, bitmapWithReflection.getHeight() + + reflectionGap, paint); + return bitmapWithReflection; + } + + /* + * (non-Javadoc) + * + * @see android.widget.Adapter#getCount() + */ + @Override + public int getCount() { + return linkedAdapter.getCount(); + } + +} diff --git a/android/sdremote/src/pl/polidea/coverflow/ResourceImageAdapter.java b/android/sdremote/src/pl/polidea/coverflow/ResourceImageAdapter.java new file mode 100644 index 000000000000..469d0d165b0b --- /dev/null +++ b/android/sdremote/src/pl/polidea/coverflow/ResourceImageAdapter.java @@ -0,0 +1,90 @@ +package pl.polidea.coverflow; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.util.Log; + +/** + * This class is an adapter that provides images from a fixed set of resource + * ids. Bitmaps and ImageViews are kept as weak references so that they can be + * cleared by garbage collection when not needed. + * + */ +public class ResourceImageAdapter extends AbstractCoverFlowImageAdapter { + + /** The Constant TAG. */ + private static final String TAG = ResourceImageAdapter.class + .getSimpleName(); + + /** The Constant DEFAULT_LIST_SIZE. */ + private static final int DEFAULT_LIST_SIZE = 20; + + /** The Constant IMAGE_RESOURCE_IDS. */ + private static final List<Integer> IMAGE_RESOURCE_IDS = new ArrayList<Integer>( + DEFAULT_LIST_SIZE); + + /** The Constant DEFAULT_RESOURCE_LIST. */ + private static final int[] DEFAULT_RESOURCE_LIST = {}; + /** The bitmap map. */ + private final Map<Integer, WeakReference<Bitmap>> bitmapMap = new HashMap<Integer, WeakReference<Bitmap>>(); + + private final Context context; + + /** + * Creates the adapter with default set of resource images. + * + * @param context + * context + */ + public ResourceImageAdapter(final Context context) { + super(); + this.context = context; + setResources(DEFAULT_RESOURCE_LIST); + } + + /** + * Replaces resources with those specified. + * + * @param resourceIds + * array of ids of resources. + */ + public final synchronized void setResources(final int[] resourceIds) { + IMAGE_RESOURCE_IDS.clear(); + for (final int resourceId : resourceIds) { + IMAGE_RESOURCE_IDS.add(resourceId); + } + notifyDataSetChanged(); + } + + /* + * (non-Javadoc) + * + * @see android.widget.Adapter#getCount() + */ + @Override + public synchronized int getCount() { + return IMAGE_RESOURCE_IDS.size(); + } + + /* + * (non-Javadoc) + * + * @see pl.polidea.coverflow.AbstractCoverFlowImageAdapter#createBitmap(int) + */ + @Override + protected Bitmap createBitmap(final int position) { + Log.v(TAG, "creating item " + position); + final Bitmap bitmap = ((BitmapDrawable) context.getResources() + .getDrawable(IMAGE_RESOURCE_IDS.get(position))) + .getBitmap(); + bitmapMap.put(position, new WeakReference<Bitmap>(bitmap)); + return bitmap; + } +}
\ No newline at end of file |